github.com/imran-kn/cilium-fork@v1.6.9/pkg/k8s/apis/cilium.io/v2/register.go (about)

     1  // Copyright 2017 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 v2
    16  
    17  import (
    18  	goerrors "errors"
    19  	"fmt"
    20  	"time"
    21  
    22  	k8sconst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
    23  	"github.com/cilium/cilium/pkg/k8s/version"
    24  	"github.com/cilium/cilium/pkg/option"
    25  
    26  	apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
    27  	apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
    28  	"k8s.io/apimachinery/pkg/api/errors"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	"k8s.io/apimachinery/pkg/runtime/schema"
    32  	"k8s.io/apimachinery/pkg/util/wait"
    33  
    34  	goVersion "github.com/hashicorp/go-version"
    35  )
    36  
    37  const (
    38  	// CustomResourceDefinitionGroup is the name of the third party resource group
    39  	CustomResourceDefinitionGroup = k8sconst.GroupName
    40  
    41  	// CustomResourceDefinitionVersion is the current version of the resource
    42  	CustomResourceDefinitionVersion = "v2"
    43  
    44  	// CustomResourceDefinitionSchemaVersion is semver-conformant version of CRD schema
    45  	// Used to determine if CRD needs to be updated in cluster
    46  	CustomResourceDefinitionSchemaVersion = "1.15"
    47  
    48  	// CustomResourceDefinitionSchemaVersionKey is key to label which holds the CRD schema version
    49  	CustomResourceDefinitionSchemaVersionKey = "io.cilium.k8s.crd.schema.version"
    50  
    51  	// CNPKindDefinition is the kind name for Cilium Network Policy
    52  	CNPKindDefinition = "CiliumNetworkPolicy"
    53  
    54  	fqdnNameRegex = `^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])\.?$`
    55  
    56  	fqdnPatternRegex = `^(([a-zA-Z0-9\*]|[a-zA-Z0-9\*][a-zA-Z0-9\-\*]*[a-zA-Z0-9\*])\.)*([A-Za-z0-9\*]|[A-Za-z0-9\*][A-Za-z0-9\-\*]*[A-Za-z0-9\*])\.?$`
    57  )
    58  
    59  // SchemeGroupVersion is group version used to register these objects
    60  var SchemeGroupVersion = schema.GroupVersion{
    61  	Group:   CustomResourceDefinitionGroup,
    62  	Version: CustomResourceDefinitionVersion,
    63  }
    64  
    65  // Resource takes an unqualified resource and returns a Group qualified GroupResource
    66  func Resource(resource string) schema.GroupResource {
    67  	return SchemeGroupVersion.WithResource(resource).GroupResource()
    68  }
    69  
    70  var (
    71  	// SchemeBuilder is needed by DeepCopy generator.
    72  	SchemeBuilder runtime.SchemeBuilder
    73  	// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
    74  	localSchemeBuilder = &SchemeBuilder
    75  
    76  	// AddToScheme adds all types of this clientset into the given scheme.
    77  	// This allows composition of clientsets, like in:
    78  	//
    79  	//   import (
    80  	//     "k8s.io/client-go/kubernetes"
    81  	//     clientsetscheme "k8s.io/client-go/kuberentes/scheme"
    82  	//     aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
    83  	//   )
    84  	//
    85  	//   kclientset, _ := kubernetes.NewForConfig(c)
    86  	//   aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
    87  	AddToScheme = localSchemeBuilder.AddToScheme
    88  
    89  	comparableCRDSchemaVersion *goVersion.Version
    90  )
    91  
    92  func init() {
    93  	comparableCRDSchemaVersion = goVersion.Must(
    94  		goVersion.NewVersion(CustomResourceDefinitionSchemaVersion))
    95  
    96  	// We only register manually written functions here. The registration of the
    97  	// generated functions takes place in the generated files. The separation
    98  	// makes the code compile even when the generated files are missing.
    99  	localSchemeBuilder.Register(addKnownTypes)
   100  }
   101  
   102  // Adds the list of known types to api.Scheme.
   103  func addKnownTypes(scheme *runtime.Scheme) error {
   104  	scheme.AddKnownTypes(SchemeGroupVersion,
   105  		&CiliumNetworkPolicy{},
   106  		&CiliumNetworkPolicyList{},
   107  		&CiliumEndpoint{},
   108  		&CiliumEndpointList{},
   109  		&CiliumNode{},
   110  		&CiliumNodeList{},
   111  		&CiliumIdentity{},
   112  		&CiliumIdentityList{},
   113  	)
   114  
   115  	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
   116  	return nil
   117  }
   118  
   119  // CreateCustomResourceDefinitions creates our CRD objects in the kubernetes
   120  // cluster
   121  func CreateCustomResourceDefinitions(clientset apiextensionsclient.Interface) error {
   122  	if err := createCNPCRD(clientset); err != nil {
   123  		return err
   124  	}
   125  
   126  	if err := createCEPCRD(clientset); err != nil {
   127  		return err
   128  	}
   129  
   130  	if err := createNodeCRD(clientset); err != nil {
   131  		return err
   132  	}
   133  
   134  	if option.Config.IdentityAllocationMode == option.IdentityAllocationModeCRD {
   135  		if err := createIdentityCRD(clientset); err != nil {
   136  			return err
   137  		}
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  // createCNPCRD creates and updates the CiliumNetworkPolicies CRD. It should be called
   144  // on agent startup but is idempotent and safe to call again.
   145  func createCNPCRD(clientset apiextensionsclient.Interface) error {
   146  	var (
   147  		// CustomResourceDefinitionSingularName is the singular name of custom resource definition
   148  		CustomResourceDefinitionSingularName = "ciliumnetworkpolicy"
   149  
   150  		// CustomResourceDefinitionPluralName is the plural name of custom resource definition
   151  		CustomResourceDefinitionPluralName = "ciliumnetworkpolicies"
   152  
   153  		// CustomResourceDefinitionShortNames are the abbreviated names to refer to this CRD's instances
   154  		CustomResourceDefinitionShortNames = []string{"cnp", "ciliumnp"}
   155  
   156  		// CustomResourceDefinitionKind is the Kind name of custom resource definition
   157  		CustomResourceDefinitionKind = CNPKindDefinition
   158  
   159  		CRDName = CustomResourceDefinitionPluralName + "." + SchemeGroupVersion.Group
   160  	)
   161  
   162  	res := &apiextensionsv1beta1.CustomResourceDefinition{
   163  		ObjectMeta: metav1.ObjectMeta{
   164  			Name: CRDName,
   165  			Labels: map[string]string{
   166  				CustomResourceDefinitionSchemaVersionKey: CustomResourceDefinitionSchemaVersion,
   167  			},
   168  		},
   169  		Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
   170  			Group:   SchemeGroupVersion.Group,
   171  			Version: SchemeGroupVersion.Version,
   172  			Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
   173  				Plural:     CustomResourceDefinitionPluralName,
   174  				Singular:   CustomResourceDefinitionSingularName,
   175  				ShortNames: CustomResourceDefinitionShortNames,
   176  				Kind:       CustomResourceDefinitionKind,
   177  			},
   178  			Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
   179  				Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
   180  			},
   181  			Scope:      apiextensionsv1beta1.NamespaceScoped,
   182  			Validation: &CNPCRV,
   183  		},
   184  	}
   185  	// Kubernetes < 1.12 does not support having the field Type set in the root
   186  	// schema so we need to set it to empty if kube-apiserver does not supports
   187  	// it.
   188  	if !version.Capabilities().FieldTypeInCRDSchema {
   189  		res.Spec.Validation.OpenAPIV3Schema.Type = ""
   190  	}
   191  
   192  	return createUpdateCRD(clientset, "CiliumNetworkPolicy/v2", res)
   193  }
   194  
   195  // createCEPCRD creates and updates the CiliumEndpoint CRD. It should be called
   196  // on agent startup but is idempotent and safe to call again.
   197  func createCEPCRD(clientset apiextensionsclient.Interface) error {
   198  	var (
   199  		// CustomResourceDefinitionSingularName is the singular name of custom resource definition
   200  		CustomResourceDefinitionSingularName = "ciliumendpoint"
   201  
   202  		// CustomResourceDefinitionPluralName is the plural name of custom resource definition
   203  		CustomResourceDefinitionPluralName = "ciliumendpoints"
   204  
   205  		// CustomResourceDefinitionShortNames are the abbreviated names to refer to this CRD's instances
   206  		CustomResourceDefinitionShortNames = []string{"cep", "ciliumep"}
   207  
   208  		// CustomResourceDefinitionKind is the Kind name of custom resource definition
   209  		CustomResourceDefinitionKind = "CiliumEndpoint"
   210  
   211  		CRDName = CustomResourceDefinitionPluralName + "." + SchemeGroupVersion.Group
   212  	)
   213  
   214  	res := &apiextensionsv1beta1.CustomResourceDefinition{
   215  		ObjectMeta: metav1.ObjectMeta{
   216  			Name: CRDName,
   217  		},
   218  		Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
   219  			Group:   SchemeGroupVersion.Group,
   220  			Version: SchemeGroupVersion.Version,
   221  			Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
   222  				Plural:     CustomResourceDefinitionPluralName,
   223  				Singular:   CustomResourceDefinitionSingularName,
   224  				ShortNames: CustomResourceDefinitionShortNames,
   225  				Kind:       CustomResourceDefinitionKind,
   226  			},
   227  			AdditionalPrinterColumns: []apiextensionsv1beta1.CustomResourceColumnDefinition{
   228  				{
   229  					Name:        "Endpoint ID",
   230  					Type:        "integer",
   231  					Description: "Cilium endpoint id",
   232  					JSONPath:    ".status.id",
   233  				},
   234  				{
   235  					Name:        "Identity ID",
   236  					Type:        "integer",
   237  					Description: "Cilium identity id",
   238  					JSONPath:    ".status.identity.id",
   239  				},
   240  				{
   241  					Name:        "Ingress Enforcement",
   242  					Type:        "boolean",
   243  					Description: "Ingress enforcement in the endpoint",
   244  					JSONPath:    ".status.policy.ingress.enforcing",
   245  				},
   246  				{
   247  					Name:        "Egress Enforcement",
   248  					Type:        "boolean",
   249  					Description: "Egress enforcement in the endpoint",
   250  					JSONPath:    ".status.policy.egress.enforcing",
   251  				},
   252  				{
   253  					Name:        "Endpoint State",
   254  					Type:        "string",
   255  					Description: "Endpoint current state",
   256  					JSONPath:    ".status.state",
   257  				},
   258  				{
   259  					Name:        "IPv4",
   260  					Type:        "string",
   261  					Description: "Endpoint IPv4 address",
   262  					JSONPath:    ".status.networking.addressing[0].ipv4",
   263  				},
   264  				{
   265  					Name:        "IPv6",
   266  					Type:        "string",
   267  					Description: "Endpoint IPv6 address",
   268  					JSONPath:    ".status.networking.addressing[0].ipv6",
   269  				},
   270  			},
   271  			Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
   272  				Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
   273  			},
   274  			Scope:      apiextensionsv1beta1.NamespaceScoped,
   275  			Validation: &cepCRV,
   276  		},
   277  	}
   278  
   279  	return createUpdateCRD(clientset, "v2.CiliumEndpoint", res)
   280  }
   281  
   282  // createNodeCRD creates and updates the CiliumNode CRD. It should be called on
   283  // agent startup but is idempotent and safe to call again.
   284  func createNodeCRD(clientset apiextensionsclient.Interface) error {
   285  	res := &apiextensionsv1beta1.CustomResourceDefinition{
   286  		ObjectMeta: metav1.ObjectMeta{
   287  			Name: "ciliumnodes." + SchemeGroupVersion.Group,
   288  		},
   289  		Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
   290  			Group:   SchemeGroupVersion.Group,
   291  			Version: SchemeGroupVersion.Version,
   292  			Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
   293  				Plural:     "ciliumnodes",
   294  				Singular:   "ciliumnode",
   295  				ShortNames: []string{"cn"},
   296  				Kind:       "CiliumNode",
   297  			},
   298  			Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
   299  				Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
   300  			},
   301  			Scope: apiextensionsv1beta1.ClusterScoped,
   302  		},
   303  	}
   304  
   305  	return createUpdateCRD(clientset, "v2.CiliumNode", res)
   306  }
   307  
   308  // createIdentityCRD creates and updates the CiliumIdentity CRD. It should be
   309  // called on agent startup but is idempotent and safe to call again.
   310  func createIdentityCRD(clientset apiextensionsclient.Interface) error {
   311  
   312  	var (
   313  		// CustomResourceDefinitionSingularName is the singular name of custom resource definition
   314  		CustomResourceDefinitionSingularName = "ciliumidentity"
   315  
   316  		// CustomResourceDefinitionPluralName is the plural name of custom resource definition
   317  		CustomResourceDefinitionPluralName = "ciliumidentities"
   318  
   319  		// CustomResourceDefinitionShortNames are the abbreviated names to refer to this CRD's instances
   320  		CustomResourceDefinitionShortNames = []string{"ciliumid"}
   321  
   322  		// CustomResourceDefinitionKind is the Kind name of custom resource definition
   323  		CustomResourceDefinitionKind = "CiliumIdentity"
   324  
   325  		CRDName = CustomResourceDefinitionPluralName + "." + SchemeGroupVersion.Group
   326  	)
   327  
   328  	res := &apiextensionsv1beta1.CustomResourceDefinition{
   329  		ObjectMeta: metav1.ObjectMeta{
   330  			Name: CRDName,
   331  		},
   332  		Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
   333  			Group:   SchemeGroupVersion.Group,
   334  			Version: SchemeGroupVersion.Version,
   335  			Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
   336  				Plural:     CustomResourceDefinitionPluralName,
   337  				Singular:   CustomResourceDefinitionSingularName,
   338  				ShortNames: CustomResourceDefinitionShortNames,
   339  				Kind:       CustomResourceDefinitionKind,
   340  			},
   341  			Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
   342  				Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
   343  			},
   344  			Scope: apiextensionsv1beta1.ClusterScoped,
   345  		},
   346  	}
   347  
   348  	return createUpdateCRD(clientset, "v2.CiliumIdentity", res)
   349  }
   350  
   351  // createUpdateCRD ensures the CRD object is installed into the k8s cluster. It
   352  // will create or update the CRD and it's validation when needed
   353  func createUpdateCRD(clientset apiextensionsclient.Interface, CRDName string, crd *apiextensionsv1beta1.CustomResourceDefinition) error {
   354  	scopedLog := log.WithField("name", CRDName)
   355  
   356  	clusterCRD, err := clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Get(crd.ObjectMeta.Name, metav1.GetOptions{})
   357  	if errors.IsNotFound(err) {
   358  		scopedLog.Info("Creating CRD (CustomResourceDefinition)...")
   359  		clusterCRD, err = clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
   360  		// This occurs when multiple agents race to create the CRD. Since another has
   361  		// created it, it will also update it, hence the non-error return.
   362  		if errors.IsAlreadyExists(err) {
   363  			return nil
   364  		}
   365  	}
   366  	if err != nil {
   367  		return err
   368  	}
   369  
   370  	scopedLog.Debug("Checking if CRD (CustomResourceDefinition) needs update...")
   371  	if needsUpdate(clusterCRD) {
   372  		scopedLog.Info("Updating CRD (CustomResourceDefinition)...")
   373  		// Update the CRD with the validation schema.
   374  		err = wait.Poll(500*time.Millisecond, 60*time.Second, func() (bool, error) {
   375  			clusterCRD, err = clientset.ApiextensionsV1beta1().
   376  				CustomResourceDefinitions().Get(crd.ObjectMeta.Name, metav1.GetOptions{})
   377  
   378  			if err != nil {
   379  				return false, err
   380  			}
   381  
   382  			// This seems too permissive but we only get here if the version is
   383  			// different per needsUpdate above. If so, we want to update on any
   384  			// validation change including adding or removing validation.
   385  			if needsUpdate(clusterCRD) {
   386  				scopedLog.Debug("CRD validation is different, updating it...")
   387  				clusterCRD.ObjectMeta.Labels = crd.ObjectMeta.Labels
   388  				clusterCRD.Spec = crd.Spec
   389  				_, err = clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Update(clusterCRD)
   390  				if err == nil {
   391  					return true, nil
   392  				}
   393  				scopedLog.WithError(err).Debug("Unable to update CRD validation")
   394  				return false, err
   395  			}
   396  
   397  			return true, nil
   398  		})
   399  		if err != nil {
   400  			scopedLog.WithError(err).Error("Unable to update CRD")
   401  			return err
   402  		}
   403  	}
   404  
   405  	// wait for the CRD to be established
   406  	scopedLog.Debug("Waiting for CRD (CustomResourceDefinition) to be available...")
   407  	err = wait.Poll(500*time.Millisecond, 60*time.Second, func() (bool, error) {
   408  		crd, err := clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Get(crd.ObjectMeta.Name, metav1.GetOptions{})
   409  		if err != nil {
   410  			return false, err
   411  		}
   412  		for _, cond := range crd.Status.Conditions {
   413  			switch cond.Type {
   414  			case apiextensionsv1beta1.Established:
   415  				if cond.Status == apiextensionsv1beta1.ConditionTrue {
   416  					return true, err
   417  				}
   418  			case apiextensionsv1beta1.NamesAccepted:
   419  				if cond.Status == apiextensionsv1beta1.ConditionFalse {
   420  					scopedLog.WithError(goerrors.New(cond.Reason)).Error("Name conflict for CRD")
   421  					return false, err
   422  				}
   423  			}
   424  		}
   425  		return false, err
   426  	})
   427  	if err != nil {
   428  		deleteErr := clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Delete(crd.ObjectMeta.Name, nil)
   429  		if deleteErr != nil {
   430  			return fmt.Errorf("unable to delete k8s %s CRD %s. Deleting CRD due: %s", CRDName, deleteErr, err)
   431  		}
   432  		return err
   433  	}
   434  
   435  	scopedLog.Info("CRD (CustomResourceDefinition) is installed and up-to-date")
   436  	return nil
   437  }
   438  
   439  func needsUpdate(clusterCRD *apiextensionsv1beta1.CustomResourceDefinition) bool {
   440  
   441  	if clusterCRD.Spec.Validation == nil {
   442  		// no validation detected
   443  		return true
   444  	}
   445  	v, ok := clusterCRD.Labels[CustomResourceDefinitionSchemaVersionKey]
   446  	if !ok {
   447  		// no schema version detected
   448  		return true
   449  	}
   450  	clusterVersion, err := goVersion.NewVersion(v)
   451  	if err != nil || clusterVersion.LessThan(comparableCRDSchemaVersion) {
   452  		// version in cluster is either unparsable or smaller than current version
   453  		return true
   454  	}
   455  	return false
   456  }
   457  
   458  func getStr(str string) *string {
   459  	return &str
   460  }
   461  
   462  func getInt64(i int64) *int64 {
   463  	return &i
   464  }
   465  
   466  var (
   467  	// cepCRV is a minimal validation for CEP objects. Since only the agent is
   468  	// creating them, it is better to be permissive and have some data, if buggy,
   469  	// than to have no data in k8s.
   470  	cepCRV = apiextensionsv1beta1.CustomResourceValidation{
   471  		OpenAPIV3Schema: &apiextensionsv1beta1.JSONSchemaProps{},
   472  	}
   473  
   474  	CNPCRV = apiextensionsv1beta1.CustomResourceValidation{
   475  		OpenAPIV3Schema: &apiextensionsv1beta1.JSONSchemaProps{
   476  			// TODO: remove the following comment when we add checker
   477  			// to detect if we should install the CNP validation for k8s > 1.11
   478  			// with this line uncommented.
   479  			Type:       "object",
   480  			Properties: properties,
   481  		},
   482  	}
   483  
   484  	properties = map[string]apiextensionsv1beta1.JSONSchemaProps{
   485  		"CIDR":                     CIDR,
   486  		"CIDRRule":                 CIDRRule,
   487  		"EgressRule":               EgressRule,
   488  		"EndpointSelector":         EndpointSelector,
   489  		"IngressRule":              IngressRule,
   490  		"K8sServiceNamespace":      K8sServiceNamespace,
   491  		"L7Rules":                  L7Rules,
   492  		"Label":                    Label,
   493  		"LabelSelector":            LabelSelector,
   494  		"LabelSelectorRequirement": LabelSelectorRequirement,
   495  		"PortProtocol":             PortProtocol,
   496  		"PortRule":                 PortRule,
   497  		"PortRuleHTTP":             PortRuleHTTP,
   498  		"PortRuleKafka":            PortRuleKafka,
   499  		"PortRuleL7":               PortRuleL7,
   500  		"Rule":                     Rule,
   501  		"Service":                  Service,
   502  		"ServiceSelector":          ServiceSelector,
   503  		"spec":                     spec,
   504  		"specs":                    specs,
   505  	}
   506  
   507  	CIDR = apiextensionsv1beta1.JSONSchemaProps{
   508  		Description: "CIDR is a CIDR prefix / IP Block.",
   509  		Type:        "string",
   510  		OneOf: []apiextensionsv1beta1.JSONSchemaProps{
   511  			{
   512  				// IPv4 CIDR
   513  				Pattern: `^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4]` +
   514  					`[0-9]|[01]?[0-9][0-9]?)\/([0-9]|[1-2][0-9]|3[0-2])$`,
   515  			},
   516  			{
   517  				// IPv6 CIDR
   518  				Pattern: `^s*((([0-9A-Fa-f]{1,4}:){7}(:|([0-9A-Fa-f]{1,4})))` +
   519  					`|(([0-9A-Fa-f]{1,4}:){6}:([0-9A-Fa-f]{1,4})?)` +
   520  					`|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){0,1}):([0-9A-Fa-f]{1,4})?))` +
   521  					`|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){0,2}):([0-9A-Fa-f]{1,4})?))` +
   522  					`|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){0,3}):([0-9A-Fa-f]{1,4})?))` +
   523  					`|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){0,4}):([0-9A-Fa-f]{1,4})?))` +
   524  					`|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){0,5}):([0-9A-Fa-f]{1,4})?))` +
   525  					`|(:(:|((:[0-9A-Fa-f]{1,4}){1,7}))))` +
   526  					`(%.+)?s*/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$`,
   527  			},
   528  		},
   529  	}
   530  
   531  	CIDRRule = apiextensionsv1beta1.JSONSchemaProps{
   532  		Type: "object",
   533  		Description: "CIDRRule is a rule that specifies a CIDR prefix to/from which outside " +
   534  			"communication is allowed, along with an optional list of subnets within that CIDR " +
   535  			"prefix to/from which outside communication is not allowed.",
   536  		Required: []string{
   537  			"cidr",
   538  		},
   539  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   540  			"cidr": CIDR,
   541  			"except": {
   542  				Description: "ExceptCIDRs is a list of IP blocks which the endpoint subject to " +
   543  					"the rule is not allowed to initiate connections to. These CIDR prefixes " +
   544  					"should be contained within Cidr. These exceptions are only applied to the " +
   545  					"Cidr in this CIDRRule, and do not apply to any other CIDR prefixes in any " +
   546  					"other CIDRRules.",
   547  				Type: "array",
   548  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   549  					Schema: &CIDR,
   550  				},
   551  			},
   552  		},
   553  	}
   554  
   555  	EgressRule = apiextensionsv1beta1.JSONSchemaProps{
   556  		Type: "object",
   557  		Description: "EgressRule contains all rule types which can be applied at egress, i.e. " +
   558  			"network traffic that originates inside the endpoint and exits the endpoint " +
   559  			"selected by the endpointSelector.\n\n- All members of this structure are optional. " +
   560  			"If omitted or empty, the\n  member will have no effect on the rule.\n\n- For now, " +
   561  			"combining ToPorts and ToCIDR in the same rule is not supported\n  and such rules " +
   562  			"will be rejected. In the future, this will be supported and\n  if if multiple " +
   563  			"members of the structure are specified, then all members\n  must match in order " +
   564  			"for the rule to take effect.",
   565  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   566  			"toCIDR": {
   567  				Description: "ToCIDR is a list of IP blocks which the endpoint subject to the " +
   568  					"rule is allowed to initiate connections. This will match on the " +
   569  					"destination IP address of outgoing connections. Adding a prefix into " +
   570  					"ToCIDR or into ToCIDRSet with no ExcludeCIDRs is equivalent. Overlaps are " +
   571  					"allowed between ToCIDR and ToCIDRSet.\n\nExample: Any endpoint with the " +
   572  					"label \"app=database-proxy\" is allowed to initiate connections to " +
   573  					"10.2.3.0/24",
   574  				Type: "array",
   575  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   576  					Schema: &CIDR,
   577  				},
   578  			},
   579  			"toCIDRSet": {
   580  				Description: "ToCIDRSet is a list of IP blocks which the endpoint subject to " +
   581  					"the rule is allowed to initiate connections to in addition to connections " +
   582  					"which are allowed via FromEndpoints, along with a list of subnets " +
   583  					"contained within their corresponding IP block to which traffic should not " +
   584  					"be allowed. This will match on the destination IP address of outgoing " +
   585  					"connections. Adding a prefix into ToCIDR or into ToCIDRSet with no " +
   586  					"ExcludeCIDRs is equivalent. Overlaps are allowed between ToCIDR and " +
   587  					"ToCIDRSet.\n\nExample: Any endpoint with the label \"app=database-proxy\" " +
   588  					"is allowed to initiate connections to 10.2.3.0/24 except from IPs in " +
   589  					"subnet 10.2.3.0/28.",
   590  				Type: "array",
   591  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   592  					Schema: &CIDRRule,
   593  				},
   594  			},
   595  			"toEntities": {
   596  				Description: "ToEntities is a list of special entities to which the endpoint " +
   597  					"subject to the rule is allowed to initiate connections. Supported " +
   598  					"entities are `world`, `cluster` and `host`",
   599  				Type: "array",
   600  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   601  					Schema: &apiextensionsv1beta1.JSONSchemaProps{
   602  						Type: "string",
   603  					},
   604  				},
   605  			},
   606  			"toPorts": {
   607  				Description: "ToPorts is a list of destination ports identified by port number " +
   608  					"and protocol which the endpoint subject to the rule is allowed to connect " +
   609  					"to.\n\nExample: Any endpoint with the label \"role=frontend\" is allowed " +
   610  					"to initiate connections to destination port 8080/tcp",
   611  				Type: "array",
   612  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   613  					Schema: &PortRule,
   614  				},
   615  			},
   616  			"toServices": {
   617  				Description: "ToServices is a list of services to which the endpoint subject " +
   618  					"to the rule is allowed to initiate connections.\n\nExample: Any endpoint " +
   619  					"with the label \"app=backend-app\" is allowed to initiate connections to " +
   620  					"all cidrs backing the \"external-service\" service",
   621  				Type: "array",
   622  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   623  					Schema: &Service,
   624  				},
   625  			},
   626  			"toEndpoints": {
   627  				Description: "ToEndpoints is a list of endpoints identified by an " +
   628  					"EndpointSelector to which the endpoint subject to the rule" +
   629  					"is allowed to communicate.\n\nExample: Any endpoint with the label " +
   630  					"\"role=frontend\" can be consumed by any endpoint carrying the label " +
   631  					"\"role=backend\".",
   632  				Type: "array",
   633  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   634  					Schema: &EndpointSelector,
   635  				},
   636  			},
   637  			"toRequires": {
   638  				Description: "ToRequires is a list of additional constraints which must be " +
   639  					"met in order for the selected endpoints to be able to reach other " +
   640  					"endpoints. These additional constraints do not by themselves grant access " +
   641  					"privileges and must always be accompanied with at least one matching " +
   642  					"FromEndpoints.\n\nExample: Any Endpoint with the label \"team=A\" " +
   643  					"requires any endpoint to which it communicates to also carry the label " +
   644  					"\"team=A\".",
   645  				Type: "array",
   646  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   647  					Schema: &EndpointSelector,
   648  				},
   649  			},
   650  			"toGroups": {
   651  				Type: "object",
   652  				Description: `ToGroups is a list of constraints that will
   653  				gather data from third-party providers and create a new
   654  				derived policy.`,
   655  				Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   656  					"aws": AWSGroup,
   657  				},
   658  			},
   659  			"toFQDNs": {
   660  				Description: `ToFQDNs is a list of rules matching fqdns that endpoint
   661  				is allowed to communicate with`,
   662  				Type: "array",
   663  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   664  					Schema: &FQDNRule,
   665  				},
   666  			},
   667  		},
   668  	}
   669  
   670  	FQDNRule = apiextensionsv1beta1.JSONSchemaProps{
   671  		Type:        "object",
   672  		Description: `FQDNRule is a rule that specifies an fully qualified domain name to which outside communication is allowed`,
   673  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   674  			"matchName":    MatchFQDNName,
   675  			"matchPattern": MatchFQDNPattern,
   676  		},
   677  	}
   678  
   679  	MatchFQDNName = apiextensionsv1beta1.JSONSchemaProps{
   680  		Description: `MatchName matches fqdn name`,
   681  		Type:        "string",
   682  		Pattern:     fqdnNameRegex,
   683  	}
   684  
   685  	MatchFQDNPattern = apiextensionsv1beta1.JSONSchemaProps{
   686  		Description: `MatchPattern matches fqdn by pattern`,
   687  		Type:        "string",
   688  		Pattern:     fqdnPatternRegex,
   689  	}
   690  
   691  	AWSGroup = apiextensionsv1beta1.JSONSchemaProps{
   692  		Type: "object",
   693  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   694  			"securityGroupsIds": {
   695  				Description: `SecurityGroupsIds is the list of AWS security
   696  				group IDs that will filter the instances IPs from the AWS API`,
   697  				Type: "array",
   698  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   699  					Schema: &apiextensionsv1beta1.JSONSchemaProps{
   700  						Type: "string",
   701  					},
   702  				},
   703  			},
   704  			"securityGroupsNames": {
   705  				Description: `SecurityGroupsNames is the list of  AWS security
   706  				group names that will filter the instances IPs from the AWS API`,
   707  				Type: "array",
   708  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   709  					Schema: &apiextensionsv1beta1.JSONSchemaProps{
   710  						Type: "string",
   711  					},
   712  				},
   713  			},
   714  			"region": {
   715  				Description: `Region is the key that will filter the AWS EC2
   716  				instances in the given region`,
   717  				Type: "string",
   718  			},
   719  		},
   720  	}
   721  	EndpointSelector = *LabelSelector.DeepCopy()
   722  
   723  	IngressRule = apiextensionsv1beta1.JSONSchemaProps{
   724  		Type: "object",
   725  		Description: "IngressRule contains all rule types which can be applied at ingress, " +
   726  			"i.e. network traffic that originates outside of the endpoint and is entering " +
   727  			"the endpoint selected by the endpointSelector.\n\n- All members of this structure " +
   728  			"are optional. If omitted or empty, the\n  member will have no effect on the rule." +
   729  			"\n\n- If multiple members are set, all of them need to match in order for\n  " +
   730  			"the rule to take effect. The exception to this rule is FromRequires field;\n  " +
   731  			"the effects of any Requires field in any rule will apply to all other\n  rules " +
   732  			"as well.\n\n- For now, combining ToPorts, FromCIDR, and FromEndpoints in the same " +
   733  			"rule\n  is not supported and any such rules will be rejected. In the future, " +
   734  			"this\n  will be supported and if multiple members of this structure are specified," +
   735  			"\n then all members must match in order for the rule to take effect. The\n  " +
   736  			"exception to this rule is the Requires field, the effects of any Requires\n  " +
   737  			"field in any rule will apply to all other rules as well.",
   738  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   739  			"fromCIDR": {
   740  				Description: "FromCIDR is a list of IP blocks which the endpoint subject to " +
   741  					"the rule is allowed to receive connections from. This will match on the " +
   742  					"source IP address of incoming connections. Adding  a prefix into FromCIDR " +
   743  					"or into FromCIDRSet with no ExcludeCIDRs is  equivalent. Overlaps are " +
   744  					"allowed between FromCIDR and FromCIDRSet.\n\nExample: Any endpoint with " +
   745  					"the label \"app=my-legacy-pet\" is allowed to receive connections from " +
   746  					"10.3.9.1",
   747  				Type: "array",
   748  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   749  					Schema: &CIDR,
   750  				},
   751  			},
   752  			"fromCIDRSet": {
   753  				Description: "FromCIDRSet is a list of IP blocks which the endpoint subject to " +
   754  					"the rule is allowed to receive connections from in addition to " +
   755  					"FromEndpoints, along with a list of subnets contained within their " +
   756  					"corresponding IP block from which traffic should not be allowed. This " +
   757  					"will match on the source IP address of incoming connections. Adding a " +
   758  					"prefix into FromCIDR or into FromCIDRSet with no ExcludeCIDRs is " +
   759  					"equivalent. Overlaps are allowed between FromCIDR and FromCIDRSet." +
   760  					"\n\nExample: Any endpoint with the label \"app=my-legacy-pet\" is allowed " +
   761  					"to receive connections from 10.0.0.0/8 except from IPs in subnet " +
   762  					"10.96.0.0/12.",
   763  				Type: "array",
   764  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   765  					Schema: &CIDRRule,
   766  				},
   767  			},
   768  			"fromEndpoints": {
   769  				Description: "FromEndpoints is a list of endpoints identified by an " +
   770  					"EndpointSelector which are allowed to communicate with the endpoint " +
   771  					"subject to the rule.\n\nExample: Any endpoint with the label " +
   772  					"\"role=backend\" can be consumed by any endpoint carrying the label " +
   773  					"\"role=frontend\".",
   774  				Type: "array",
   775  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   776  					Schema: &EndpointSelector,
   777  				},
   778  			},
   779  			"fromEntities": {
   780  				Description: "FromEntities is a list of special entities which the endpoint " +
   781  					"subject to the rule is allowed to receive connections from. Supported " +
   782  					"entities are `world`, `cluster`, `host`, and `init`",
   783  				Type: "array",
   784  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   785  					Schema: &apiextensionsv1beta1.JSONSchemaProps{
   786  						Type: "string",
   787  					},
   788  				},
   789  			},
   790  			"fromRequires": {
   791  				Description: "FromRequires is a list of additional constraints which must be " +
   792  					"met in order for the selected endpoints to be reachable. These additional " +
   793  					"constraints do no by itself grant access privileges and must always be " +
   794  					"accompanied with at least one matching FromEndpoints.\n\nExample: Any " +
   795  					"Endpoint with the label \"team=A\" requires consuming endpoint to also " +
   796  					"carry the label \"team=A\".",
   797  				Type: "array",
   798  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   799  					Schema: &EndpointSelector,
   800  				},
   801  			},
   802  			"toPorts": {
   803  				Description: "ToPorts is a list of destination ports identified by port number " +
   804  					"and protocol which the endpoint subject to the rule is allowed to receive " +
   805  					"connections on.\n\nExample: Any endpoint with the label \"app=httpd\" can " +
   806  					"only accept incoming connections on port 80/tcp.",
   807  				Type: "array",
   808  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   809  					Schema: &PortRule,
   810  				},
   811  			},
   812  		},
   813  	}
   814  
   815  	K8sServiceNamespace = apiextensionsv1beta1.JSONSchemaProps{
   816  		Type: "object",
   817  		Description: "K8sServiceNamespace is an abstraction for the k8s service + namespace " +
   818  			"types.",
   819  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   820  			"namespace": {
   821  				Type: "string",
   822  			},
   823  			"serviceName": {
   824  				Type: "string",
   825  			},
   826  		},
   827  	}
   828  
   829  	L7Rules = apiextensionsv1beta1.JSONSchemaProps{
   830  		Type: "object",
   831  		Description: "L7Rules is a union of port level rule types. Mixing of different port " +
   832  			"level rule types is disallowed, so exactly one of the following must be set. If " +
   833  			"none are specified, then no additional port level rules are applied.",
   834  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   835  			"http": {
   836  				Description: "HTTP specific rules.",
   837  				Type:        "array",
   838  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   839  					Schema: &PortRuleHTTP,
   840  				},
   841  			},
   842  			"kafka": {
   843  				Description: "Kafka-specific rules.",
   844  				Type:        "array",
   845  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   846  					Schema: &PortRuleKafka,
   847  				},
   848  			},
   849  			"l7proto": {
   850  				Description: "Parser type name that uses Key-Value pair rules.",
   851  				Type:        "string",
   852  			},
   853  			"l7": {
   854  				Description: "Generic Key-Value pair rules.",
   855  				Type:        "array",
   856  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   857  					Schema: &PortRuleL7,
   858  				},
   859  			},
   860  			"dns": {
   861  				Description: "DNS specific rules",
   862  				Type:        "array",
   863  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   864  					Schema: &PortRuleDNS,
   865  				},
   866  			},
   867  		},
   868  	}
   869  
   870  	PortRuleDNS = apiextensionsv1beta1.JSONSchemaProps{
   871  		Type:        "object",
   872  		Description: `FQDNRule is a rule that specifies an fully qualified domain name to which outside communication is allowed`,
   873  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   874  			"matchName":    MatchFQDNName,
   875  			"matchPattern": MatchFQDNPattern,
   876  		},
   877  	}
   878  
   879  	Label = apiextensionsv1beta1.JSONSchemaProps{
   880  		Type:        "object",
   881  		Description: "Label is the cilium's representation of a container label.",
   882  		Required: []string{
   883  			"key",
   884  		},
   885  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   886  			"key": {
   887  				Type: "string",
   888  			},
   889  			"source": {
   890  				Description: "Source can be one of the values present in const.go " +
   891  					"(e.g.: LabelSourceContainer)",
   892  				Type: "string",
   893  			},
   894  			"value": {
   895  				Type: "string",
   896  			},
   897  		},
   898  	}
   899  
   900  	LabelSelector = apiextensionsv1beta1.JSONSchemaProps{
   901  		Type: "object",
   902  		Description: "A label selector is a label query over a set of resources. The result " +
   903  			"of matchLabels and matchExpressions are ANDed. An empty label selector matches " +
   904  			"all objects. A null label selector matches no objects.",
   905  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   906  			"matchLabels": {
   907  				Description: "matchLabels is a map of {key,value} pairs. A single {key,value} " +
   908  					"in the matchLabels map is equivalent to an element of matchExpressions, " +
   909  					"whose key field is \"key\", the operator is \"In\", and the values array " +
   910  					"contains only \"value\". The requirements are ANDed.",
   911  				Type: "object",
   912  			},
   913  			"matchExpressions": {
   914  				Description: "matchExpressions is a list of label selector requirements. " +
   915  					"The requirements are ANDed.",
   916  				Type: "array",
   917  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   918  					Schema: &LabelSelectorRequirement,
   919  				},
   920  			},
   921  		},
   922  	}
   923  
   924  	LabelSelectorRequirement = apiextensionsv1beta1.JSONSchemaProps{
   925  		Type: "object",
   926  		Description: "A label selector requirement is a selector that contains values, a key, " +
   927  			"and an operator that relates the key and values.",
   928  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   929  			"key": {
   930  				Description: "key is the label key that the selector applies to.",
   931  				Type:        "string",
   932  			},
   933  			"operator": {
   934  				Description: "operator represents a key's relationship to a set of values. " +
   935  					"Valid operators are In, NotIn, Exists and DoesNotExist.",
   936  				Type: "string",
   937  				Enum: []apiextensionsv1beta1.JSON{
   938  					{
   939  						Raw: []byte(`"In"`),
   940  					},
   941  					{
   942  						Raw: []byte(`"NotIn"`),
   943  					},
   944  					{
   945  						Raw: []byte(`"Exists"`),
   946  					},
   947  					{
   948  						Raw: []byte(`"DoesNotExist"`),
   949  					},
   950  				},
   951  			},
   952  			"values": {
   953  				Description: "values is an array of string values. If the operator is In or " +
   954  					"NotIn, the values array must be non-empty. If the operator is Exists or " +
   955  					"DoesNotExist, the values array must be empty. This array is replaced " +
   956  					"during a strategic merge patch.",
   957  				Type: "array",
   958  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
   959  					Schema: &apiextensionsv1beta1.JSONSchemaProps{
   960  						Type: "string",
   961  					},
   962  				},
   963  			},
   964  		},
   965  		Required: []string{"key", "operator"},
   966  	}
   967  
   968  	PortProtocol = apiextensionsv1beta1.JSONSchemaProps{
   969  		Type:        "object",
   970  		Description: "PortProtocol specifies an L4 port with an optional transport protocol",
   971  		Required: []string{
   972  			"port",
   973  		},
   974  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
   975  			"port": {
   976  				Description: "Port is an L4 port number. For now the string will be strictly " +
   977  					"parsed as a single uint16. In the future, this field may support ranges " +
   978  					"in the form \"1024-2048",
   979  				Type: "string",
   980  				// uint16 string regex
   981  				Pattern: `^(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|` +
   982  					`[1-5][0-9]{4}|[0-9]{1,4})$`,
   983  			},
   984  			"protocol": {
   985  				Description: `Protocol is the L4 protocol. If omitted or empty, any protocol ` +
   986  					`matches. Accepted values: "TCP", "UDP", ""/"ANY"\n\nMatching on ` +
   987  					`ICMP is not supported.`,
   988  				Type: "string",
   989  				Enum: []apiextensionsv1beta1.JSON{
   990  					{
   991  						Raw: []byte(`"TCP"`),
   992  					},
   993  					{
   994  						Raw: []byte(`"UDP"`),
   995  					},
   996  					{
   997  						Raw: []byte(`"ANY"`),
   998  					},
   999  				},
  1000  			},
  1001  		},
  1002  	}
  1003  
  1004  	PortRule = apiextensionsv1beta1.JSONSchemaProps{
  1005  		Type: "object",
  1006  		Description: "PortRule is a list of ports/protocol combinations with optional Layer 7 " +
  1007  			"rules which must be met.",
  1008  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
  1009  			"ports": {
  1010  				Description: "Ports is a list of L4 port/protocol\n\nIf omitted or empty but " +
  1011  					"RedirectPort is set, then all ports of the endpoint subject to either the " +
  1012  					"ingress or egress rule are being redirected.",
  1013  				Type: "array",
  1014  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
  1015  					Schema: &PortProtocol,
  1016  				},
  1017  			},
  1018  			"redirectPort": {
  1019  				Description: "RedirectPort is the L4 port which, if set, all traffic matching " +
  1020  					"the Ports is being redirected to. Whatever listener behind that port " +
  1021  					"becomes responsible to enforce the port rules and is also responsible to " +
  1022  					"reinject all traffic back and ensure it reaches its original destination.",
  1023  				Type:   "integer",
  1024  				Format: "uint16",
  1025  			},
  1026  			"rules": L7Rules,
  1027  		},
  1028  	}
  1029  
  1030  	PortRuleHTTP = apiextensionsv1beta1.JSONSchemaProps{
  1031  		Type: "object",
  1032  		Description: "PortRuleHTTP is a list of HTTP protocol constraints. All fields are " +
  1033  			"optional, if all fields are empty or missing, the rule does not have any effect." +
  1034  			"\n\nAll fields of this type are extended POSIX regex as defined by " +
  1035  			"IEEE Std 1003.1, (i.e this follows the egrep/unix syntax, not the perl syntax) " +
  1036  			"matched against the path of an incoming request. Currently it can contain " +
  1037  			"characters disallowed from the conventional \"path\" part of a URL as defined by " +
  1038  			"RFC 3986.",
  1039  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
  1040  			"headers": {
  1041  				Description: "Headers is a list of HTTP headers which must be present in the " +
  1042  					"request. If omitted or empty, requests are allowed regardless of headers " +
  1043  					"present.",
  1044  				Type: "array",
  1045  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
  1046  					Schema: &apiextensionsv1beta1.JSONSchemaProps{
  1047  						Type: "string",
  1048  					},
  1049  				},
  1050  			},
  1051  			"host": {
  1052  				Description: "Host is an extended POSIX regex matched against the host header " +
  1053  					"of a request, e.g. \"foo.com\"\n\nIf omitted or empty, the value of the " +
  1054  					"host header is ignored.",
  1055  				Type:   "string",
  1056  				Format: "idn-hostname",
  1057  			},
  1058  			"method": {
  1059  				Description: "Method is an extended POSIX regex matched against the method of " +
  1060  					"a request, e.g. \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", ...\n\n" +
  1061  					"If omitted or empty, all methods are allowed.",
  1062  				Type: "string",
  1063  			},
  1064  			"path": {
  1065  				Description: "Path is an extended POSIX regex matched against the path of a " +
  1066  					"request. Currently it can contain characters disallowed from the " +
  1067  					"conventional \"path\" part of a URL as defined by RFC 3986.\n\n" +
  1068  					"If omitted or empty, all paths are all allowed.",
  1069  				Type: "string",
  1070  			},
  1071  		},
  1072  	}
  1073  
  1074  	PortRuleKafka = apiextensionsv1beta1.JSONSchemaProps{
  1075  		Type: "object",
  1076  		Description: "PortRuleKafka is a list of Kafka protocol constraints. All fields are " +
  1077  			"optional, if all fields are empty or missing, the rule will match all Kafka " +
  1078  			"messages.",
  1079  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
  1080  			"role": {
  1081  				Description: "Role is a case-insensitive string and describes a group of API keys" +
  1082  					"necessary to perform certain higher level Kafka operations such as" +
  1083  					"\"produce\" or \"consume\". An APIGroup automatically expands into all APIKeys" +
  1084  					"required to perform the specified higher level operation." +
  1085  					"The following values are supported:" +
  1086  					"- \"produce\": Allow producing to the topics specified in the rule" +
  1087  					"- \"consume\": Allow consuming from the topics specified in the rule" +
  1088  					"This field is incompatible with the APIKey field, either APIKey or Role" +
  1089  					"may be specified. If omitted or empty, the field has no effect and the " +
  1090  					"logic of the APIKey field applies.",
  1091  				Type: "string",
  1092  				Enum: []apiextensionsv1beta1.JSON{
  1093  					{
  1094  						Raw: []byte(`"produce"`),
  1095  					},
  1096  					{
  1097  						Raw: []byte(`"consume"`),
  1098  					},
  1099  				},
  1100  			},
  1101  			"apiKey": {
  1102  				Description: "APIKey is a case-insensitive string matched against the key of " +
  1103  					"a request, e.g. \"produce\", \"fetch\", \"createtopic\", \"deletetopic\", " +
  1104  					"et al Reference: https://kafka.apache.org/protocol#protocol_api_keys\n\n" +
  1105  					"If omitted or empty, all keys are allowed.",
  1106  				Type: "string",
  1107  			},
  1108  			"apiVersion": {
  1109  				Description: "APIVersion is the version matched against the api version of the " +
  1110  					"Kafka message. If set, it has to be a string representing a positive " +
  1111  					"integer.\n\nIf omitted or empty, all versions are allowed.",
  1112  				Type: "string",
  1113  			},
  1114  			"clientID": {
  1115  				Description: "ClientID is the client identifier as provided in the request.\n\n" +
  1116  					"From Kafka protocol documentation: This is a user supplied identifier for " +
  1117  					"the client application. The user can use any identifier they like and it " +
  1118  					"will be used when logging errors, monitoring aggregates, etc. For " +
  1119  					"example, one might want to monitor not just the requests per second " +
  1120  					"overall, but the number coming from each client application (each of " +
  1121  					"which could reside on multiple servers). This id acts as a logical " +
  1122  					"grouping across all requests from a particular client.\n\nIf omitted or " +
  1123  					"empty, all client identifiers are allowed.",
  1124  				Type: "string",
  1125  			},
  1126  			"topic": {
  1127  				Description: "Topic is the topic name contained in the message. If a Kafka " +
  1128  					"request contains multiple topics, then all topics must be allowed or the " +
  1129  					"message will be rejected.\n\nThis constraint is ignored if the matched " +
  1130  					"request message type doesn't contain any topic. Maximum size of Topic can " +
  1131  					"be 249 characters as per recent Kafka spec and allowed characters are " +
  1132  					"a-z, A-Z, 0-9, -, . and _ Older Kafka versions had longer topic lengths " +
  1133  					"of 255, but in Kafka 0.10 version the length was changed from 255 to 249. " +
  1134  					"For compatibility reasons we are using 255\n\nIf omitted or empty, all " +
  1135  					"topics are allowed.",
  1136  				Type:      "string",
  1137  				MaxLength: getInt64(255),
  1138  			},
  1139  		},
  1140  	}
  1141  
  1142  	PortRuleL7 = apiextensionsv1beta1.JSONSchemaProps{
  1143  		Type: "object",
  1144  		Description: "PortRuleL7 is a map of {key,value} pairs which is passed to the " +
  1145  			"parser referenced in l7proto. It is up to the parser to define what to " +
  1146  			"do with the map data. If omitted or empty, all requests are allowed. " +
  1147  			"Both keys and values must be strings.",
  1148  		//
  1149  		// AdditionalProperties is supported by k8s 1.11 and later only
  1150  		// Without it non-string value types are accepted which may cause policy translation
  1151  		// in cilium-agent to fail.
  1152  		//
  1153  		// Keep this here so that we can re-introduce this when th minimum suppoerted k8s version
  1154  		// is 1.11.
  1155  		//
  1156  		//AdditionalProperties: &apiextensionsv1beta1.JSONSchemaPropsOrBool{
  1157  		//	Schema: &apiextensionsv1beta1.JSONSchemaProps{
  1158  		//		Type: "string",
  1159  		//	},
  1160  		//},
  1161  	}
  1162  
  1163  	Rule = apiextensionsv1beta1.JSONSchemaProps{
  1164  		Type: "object",
  1165  		Description: "Rule is a policy rule which must be applied to all endpoints which match " +
  1166  			"the labels contained in the endpointSelector\n\nEach rule is split into an " +
  1167  			"ingress section which contains all rules applicable at ingress, and an egress " +
  1168  			"section applicable at egress. For rule types such as `L4Rule` and `CIDR` which " +
  1169  			"can be applied at both ingress and egress, both ingress and egress side have to " +
  1170  			"either specifically allow the connection or one side has to be omitted.\n\n" +
  1171  			"Either ingress, egress, or both can be provided. If both ingress and egress are " +
  1172  			"omitted, the rule has no effect.",
  1173  		Required: []string{
  1174  			"endpointSelector",
  1175  		},
  1176  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
  1177  			"Description": {
  1178  				Description: "Description is a free form string, it can be used by the creator " +
  1179  					"of the rule to store human readable explanation of the purpose of this " +
  1180  					"rule. Rules cannot be identified by comment.",
  1181  				Type: "string",
  1182  			},
  1183  			"egress": {
  1184  				Description: "Egress is a list of EgressRule which are enforced at egress. If " +
  1185  					"omitted or empty, this rule does not apply at egress.",
  1186  				Type: "array",
  1187  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
  1188  					Schema: &EgressRule,
  1189  				},
  1190  			},
  1191  			"endpointSelector": EndpointSelector,
  1192  			"ingress": {
  1193  				Description: "Ingress is a list of IngressRule which are enforced at ingress. " +
  1194  					"If omitted or empty, this rule does not apply at ingress.",
  1195  				Type: "array",
  1196  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
  1197  					Schema: &IngressRule,
  1198  				},
  1199  			},
  1200  			"labels": {
  1201  				Description: "Labels is a list of optional strings which can be used to " +
  1202  					"re-identify the rule or to store metadata. It is possible to lookup or " +
  1203  					"delete strings based on labels. Labels are not required to be unique, " +
  1204  					"multiple rules can have overlapping or identical labels.",
  1205  				Type: "array",
  1206  				Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
  1207  					Schema: &Label,
  1208  				},
  1209  			},
  1210  		},
  1211  	}
  1212  
  1213  	Service = apiextensionsv1beta1.JSONSchemaProps{
  1214  		Type:        "object",
  1215  		Description: "Service wraps around selectors for services",
  1216  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
  1217  			"k8sService":         K8sServiceNamespace,
  1218  			"k8sServiceSelector": ServiceSelector,
  1219  		},
  1220  	}
  1221  
  1222  	ServiceSelector = apiextensionsv1beta1.JSONSchemaProps{
  1223  		Type:        "object",
  1224  		Description: "ServiceSelector is a label selector for k8s services",
  1225  		Required: []string{
  1226  			"selector",
  1227  		},
  1228  		Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
  1229  			"selector": EndpointSelector,
  1230  			"namespace": {
  1231  				Type: "string",
  1232  			},
  1233  		},
  1234  	}
  1235  
  1236  	spec = *Rule.DeepCopy()
  1237  
  1238  	specs = apiextensionsv1beta1.JSONSchemaProps{
  1239  		Description: "Specs is a list of desired Cilium specific rule specification.",
  1240  		Type:        "array",
  1241  		Items: &apiextensionsv1beta1.JSONSchemaPropsOrArray{
  1242  			Schema: &spec,
  1243  		},
  1244  	}
  1245  )
  1246  
  1247  func init() {
  1248  	EndpointSelector.Description = "EndpointSelector is a wrapper for k8s LabelSelector."
  1249  
  1250  	portRuleProps := PortRule.Properties["rules"]
  1251  	portRuleProps.Description = "Rules is a list of additional port level rules which must be " +
  1252  		"met in order for the PortRule to allow the traffic. If omitted or empty, " +
  1253  		"no layer 7 rules are enforced."
  1254  	PortRule.Properties["rules"] = portRuleProps
  1255  
  1256  	ruleProps := Rule.Properties["endpointSelector"]
  1257  	ruleProps.Description = "EndpointSelector selects all endpoints which should be subject " +
  1258  		"to this rule. Cannot be empty."
  1259  	Rule.Properties["endpointSelector"] = ruleProps
  1260  
  1261  	serviceProps := Service.Properties["k8sServiceSelector"]
  1262  	serviceProps.Description = "K8sServiceSelector selects services by k8s labels. " +
  1263  		"Not supported yet"
  1264  	Service.Properties["k8sServiceSelector"] = serviceProps
  1265  
  1266  	spec.Description = "Spec is the desired Cilium specific rule specification."
  1267  	spec.Type = "object"
  1268  
  1269  }