github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/cilium/cmd/preflight_k8s_valid_cnp.go (about)

     1  // Copyright 2020 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cmd
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"os"
    21  	"time"
    22  
    23  	"github.com/cilium/cilium/pkg/k8s"
    24  	v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    25  	"github.com/cilium/cilium/pkg/k8s/client/clientset/versioned/scheme"
    26  	"github.com/cilium/cilium/pkg/logging"
    27  	"github.com/cilium/cilium/pkg/option"
    28  
    29  	"github.com/spf13/cobra"
    30  	"github.com/spf13/viper"
    31  	apiextensionsinternal "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
    32  	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
    33  	"k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
    34  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    35  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    36  )
    37  
    38  var validateCNP = &cobra.Command{
    39  	Use:   "validate-cnp",
    40  	Short: "Validate Cilium Network Policies deployed in the cluster",
    41  	Long: `Before upgrading Cilium it is recommended to run this validation checker
    42  to make sure the policies deployed are valid. The validator will verify if all policies
    43  deployed in the cluster are valid, in case they are not, an error is printed and the
    44  has an exit code -1 is returned.`,
    45  	Run: func(cmd *cobra.Command, args []string) {
    46  		err := validateCNPs()
    47  		if err != nil {
    48  			log.Error(err)
    49  			os.Exit(-1)
    50  		}
    51  	},
    52  }
    53  
    54  const validateK8sPoliciesTimeout = 5 * time.Minute
    55  
    56  func validateCNPs() error {
    57  	// The internal packages log things. Make sure they follow the setup of of
    58  	// the CLI tool.
    59  	logging.DefaultLogger.SetFormatter(log.Formatter)
    60  
    61  	log.Info("Setting up Kubernetes client")
    62  
    63  	k8sClientQPSLimit := viper.GetFloat64(option.K8sClientQPSLimit)
    64  	k8sClientBurst := viper.GetInt(option.K8sClientBurst)
    65  
    66  	k8s.Configure(k8sAPIServer, k8sKubeConfigPath, float32(k8sClientQPSLimit), k8sClientBurst)
    67  
    68  	if err := k8s.Init(); err != nil {
    69  		log.WithError(err).Fatal("Unable to connect to Kubernetes apiserver")
    70  	}
    71  
    72  	ctx, initCancel := context.WithTimeout(context.Background(), validateK8sPoliciesTimeout)
    73  	defer initCancel()
    74  	cnpErr := validateNPResources(ctx, "ciliumnetworkpolicies", "CiliumNetworkPolicy")
    75  
    76  	ctx, initCancel2 := context.WithTimeout(context.Background(), validateK8sPoliciesTimeout)
    77  	defer initCancel2()
    78  	ccnpErr := validateNPResources(ctx, "ciliumclusterwidenetworkpolicies", "CiliumClusterwideNetworkPolicy")
    79  
    80  	if cnpErr != nil {
    81  		return cnpErr
    82  	}
    83  	if ccnpErr != nil {
    84  		return ccnpErr
    85  	}
    86  	log.Info("All CCNPs and CNPs valid!")
    87  	return nil
    88  }
    89  
    90  func validateNPResources(ctx context.Context, name, shortName string) error {
    91  	var internal apiextensionsinternal.CustomResourceValidation
    92  	err := v1beta1.Convert_v1beta1_CustomResourceValidation_To_apiextensions_CustomResourceValidation(
    93  		&v2.CNPCRV,
    94  		&internal,
    95  		nil,
    96  	)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	validator, _, err := validation.NewSchemaValidator(&internal)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	var policyErr error
   106  	var cnps unstructured.UnstructuredList
   107  	for {
   108  		opts := metav1.ListOptions{
   109  			Limit:    25,
   110  			Continue: cnps.GetContinue(),
   111  		}
   112  		err = k8s.CiliumClient().
   113  			Interface.
   114  			CiliumV2().
   115  			RESTClient().
   116  			Get().
   117  			VersionedParams(&opts, scheme.ParameterCodec).
   118  			Resource(name).
   119  			Do().
   120  			Into(&cnps)
   121  		if err != nil {
   122  			return err
   123  		}
   124  
   125  		for _, cnp := range cnps.Items {
   126  			cnpName := fmt.Sprintf("%s/%s", cnp.GetNamespace(), cnp.GetName())
   127  			if errs := validation.ValidateCustomResource(nil, &cnp, validator); len(errs) > 0 {
   128  				log.Errorf("Validating %s '%s': unexpected validation error: %s",
   129  					shortName, cnpName, errs.ToAggregate())
   130  				policyErr = fmt.Errorf("Found invalid %s", shortName)
   131  			} else {
   132  				log.Infof("Validating %s '%s': OK!", shortName, cnpName)
   133  			}
   134  		}
   135  		if cnps.GetContinue() == "" {
   136  			break
   137  		}
   138  	}
   139  	return policyErr
   140  }