github.com/Diggs/controller-tools@v0.4.2/pkg/crd/markers/crd.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package markers
    18  
    19  import (
    20  	"fmt"
    21  
    22  	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    23  
    24  	"github.com/Diggs/controller-tools/pkg/markers"
    25  )
    26  
    27  // CRDMarkers lists all markers that directly modify the CRD (not validation
    28  // schemas).
    29  var CRDMarkers = []*definitionWithHelp{
    30  	// TODO(directxman12): more detailed help
    31  	must(markers.MakeDefinition("kubebuilder:subresource:status", markers.DescribesType, SubresourceStatus{})).
    32  		WithHelp(SubresourceStatus{}.Help()),
    33  
    34  	must(markers.MakeDefinition("kubebuilder:subresource:scale", markers.DescribesType, SubresourceScale{})).
    35  		WithHelp(SubresourceScale{}.Help()),
    36  
    37  	must(markers.MakeDefinition("kubebuilder:printcolumn", markers.DescribesType, PrintColumn{})).
    38  		WithHelp(PrintColumn{}.Help()),
    39  
    40  	must(markers.MakeDefinition("kubebuilder:resource", markers.DescribesType, Resource{})).
    41  		WithHelp(Resource{}.Help()),
    42  
    43  	must(markers.MakeDefinition("kubebuilder:storageversion", markers.DescribesType, StorageVersion{})).
    44  		WithHelp(StorageVersion{}.Help()),
    45  
    46  	must(markers.MakeDefinition("kubebuilder:skipversion", markers.DescribesType, SkipVersion{})).
    47  		WithHelp(SkipVersion{}.Help()),
    48  
    49  	must(markers.MakeDefinition("kubebuilder:unservedversion", markers.DescribesType, UnservedVersion{})).
    50  		WithHelp(UnservedVersion{}.Help()),
    51  }
    52  
    53  // TODO: categories and singular used to be annotations types
    54  // TODO: doc
    55  
    56  func init() {
    57  	AllDefinitions = append(AllDefinitions, CRDMarkers...)
    58  }
    59  
    60  // +controllertools:marker:generateHelp:category=CRD
    61  
    62  // SubresourceStatus enables the "/status" subresource on a CRD.
    63  type SubresourceStatus struct{}
    64  
    65  func (s SubresourceStatus) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
    66  	var subresources *apiext.CustomResourceSubresources
    67  	for i := range crd.Versions {
    68  		ver := &crd.Versions[i]
    69  		if ver.Name != version {
    70  			continue
    71  		}
    72  		if ver.Subresources == nil {
    73  			ver.Subresources = &apiext.CustomResourceSubresources{}
    74  		}
    75  		subresources = ver.Subresources
    76  		break
    77  	}
    78  	if subresources == nil {
    79  		return fmt.Errorf("status subresource applied to version %q not in CRD", version)
    80  	}
    81  	subresources.Status = &apiext.CustomResourceSubresourceStatus{}
    82  	return nil
    83  }
    84  
    85  // +controllertools:marker:generateHelp:category=CRD
    86  
    87  // SubresourceScale enables the "/scale" subresource on a CRD.
    88  type SubresourceScale struct {
    89  	// marker names are leftover legacy cruft
    90  
    91  	// SpecPath specifies the jsonpath to the replicas field for the scale's spec.
    92  	SpecPath string `marker:"specpath"`
    93  
    94  	// StatusPath specifies the jsonpath to the replicas field for the scale's status.
    95  	StatusPath string `marker:"statuspath"`
    96  
    97  	// SelectorPath specifies the jsonpath to the pod label selector field for the scale's status.
    98  	//
    99  	// The selector field must be the *string* form (serialized form) of a selector.
   100  	// Setting a pod label selector is necessary for your type to work with the HorizontalPodAutoscaler.
   101  	SelectorPath *string `marker:"selectorpath"`
   102  }
   103  
   104  func (s SubresourceScale) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
   105  	var subresources *apiext.CustomResourceSubresources
   106  	for i := range crd.Versions {
   107  		ver := &crd.Versions[i]
   108  		if ver.Name != version {
   109  			continue
   110  		}
   111  		if ver.Subresources == nil {
   112  			ver.Subresources = &apiext.CustomResourceSubresources{}
   113  		}
   114  		subresources = ver.Subresources
   115  		break
   116  	}
   117  	if subresources == nil {
   118  		return fmt.Errorf("scale subresource applied to version %q not in CRD", version)
   119  	}
   120  	subresources.Scale = &apiext.CustomResourceSubresourceScale{
   121  		SpecReplicasPath:   s.SpecPath,
   122  		StatusReplicasPath: s.StatusPath,
   123  		LabelSelectorPath:  s.SelectorPath,
   124  	}
   125  	return nil
   126  }
   127  
   128  // +controllertools:marker:generateHelp:category=CRD
   129  
   130  // StorageVersion marks this version as the "storage version" for the CRD for conversion.
   131  //
   132  // When conversion is enabled for a CRD (i.e. it's not a trivial-versions/single-version CRD),
   133  // one version is set as the "storage version" to be stored in etcd.  Attempting to store any
   134  // other version will result in conversion to the storage version via a conversion webhook.
   135  type StorageVersion struct{}
   136  
   137  func (s StorageVersion) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
   138  	if version == "" {
   139  		// single-version, do nothing
   140  		return nil
   141  	}
   142  	// multi-version
   143  	for i := range crd.Versions {
   144  		ver := &crd.Versions[i]
   145  		if ver.Name != version {
   146  			continue
   147  		}
   148  		ver.Storage = true
   149  		break
   150  	}
   151  	return nil
   152  }
   153  
   154  // +controllertools:marker:generateHelp:category=CRD
   155  
   156  // SkipVersion removes the particular version of the CRD from the CRDs spec.
   157  //
   158  // This is useful if you need to skip generating and listing version entries
   159  // for 'internal' resource versions, which typically exist if using the
   160  // Kubernetes upstream conversion-gen tool.
   161  type SkipVersion struct{}
   162  
   163  func (s SkipVersion) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
   164  	if version == "" {
   165  		// single-version, this is an invalid state
   166  		return fmt.Errorf("cannot skip a version if there is only a single version")
   167  	}
   168  	var versions []apiext.CustomResourceDefinitionVersion
   169  	// multi-version
   170  	for i := range crd.Versions {
   171  		ver := crd.Versions[i]
   172  		if ver.Name == version {
   173  			// skip the skipped version
   174  			continue
   175  		}
   176  		versions = append(versions, ver)
   177  	}
   178  	crd.Versions = versions
   179  	return nil
   180  }
   181  
   182  // +controllertools:marker:generateHelp:category=CRD
   183  
   184  // PrintColumn adds a column to "kubectl get" output for this CRD.
   185  type PrintColumn struct {
   186  	// Name specifies the name of the column.
   187  	Name string
   188  
   189  	// Type indicates the type of the column.
   190  	//
   191  	// It may be any OpenAPI data type listed at
   192  	// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types.
   193  	Type string
   194  
   195  	// JSONPath specifies the jsonpath expression used to extract the value of the column.
   196  	JSONPath string `marker:"JSONPath"` // legacy cruft
   197  
   198  	// Description specifies the help/description for this column.
   199  	Description string `marker:",optional"`
   200  
   201  	// Format specifies the format of the column.
   202  	//
   203  	// It may be any OpenAPI data format corresponding to the type, listed at
   204  	// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types.
   205  	Format string `marker:",optional"`
   206  
   207  	// Priority indicates how important it is that this column be displayed.
   208  	//
   209  	// Lower priority (*higher* numbered) columns will be hidden if the terminal
   210  	// width is too small.
   211  	Priority int32 `marker:",optional"`
   212  }
   213  
   214  func (s PrintColumn) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
   215  	var columns *[]apiext.CustomResourceColumnDefinition
   216  	for i := range crd.Versions {
   217  		ver := &crd.Versions[i]
   218  		if ver.Name != version {
   219  			continue
   220  		}
   221  		if ver.Subresources == nil {
   222  			ver.Subresources = &apiext.CustomResourceSubresources{}
   223  		}
   224  		columns = &ver.AdditionalPrinterColumns
   225  		break
   226  	}
   227  	if columns == nil {
   228  		return fmt.Errorf("printer columns applied to version %q not in CRD", version)
   229  	}
   230  
   231  	*columns = append(*columns, apiext.CustomResourceColumnDefinition{
   232  		Name:        s.Name,
   233  		Type:        s.Type,
   234  		JSONPath:    s.JSONPath,
   235  		Description: s.Description,
   236  		Format:      s.Format,
   237  		Priority:    s.Priority,
   238  	})
   239  
   240  	return nil
   241  }
   242  
   243  // +controllertools:marker:generateHelp:category=CRD
   244  
   245  // Resource configures naming and scope for a CRD.
   246  type Resource struct {
   247  	// Path specifies the plural "resource" for this CRD.
   248  	//
   249  	// It generally corresponds to a plural, lower-cased version of the Kind.
   250  	// See https://book.kubebuilder.io/cronjob-tutorial/gvks.html.
   251  	Path string `marker:",optional"`
   252  
   253  	// ShortName specifies aliases for this CRD.
   254  	//
   255  	// Short names are often used when people have work with your resource
   256  	// over and over again.  For instance, "rs" for "replicaset" or
   257  	// "crd" for customresourcedefinition.
   258  	ShortName []string `marker:",optional"`
   259  
   260  	// Categories specifies which group aliases this resource is part of.
   261  	//
   262  	// Group aliases are used to work with groups of resources at once.
   263  	// The most common one is "all" which covers about a third of the base
   264  	// resources in Kubernetes, and is generally used for "user-facing" resources.
   265  	Categories []string `marker:",optional"`
   266  
   267  	// Singular overrides the singular form of your resource.
   268  	//
   269  	// The singular form is otherwise defaulted off the plural (path).
   270  	Singular string `marker:",optional"`
   271  
   272  	// Scope overrides the scope of the CRD (Cluster vs Namespaced).
   273  	//
   274  	// Scope defaults to "Namespaced".  Cluster-scoped ("Cluster") resources
   275  	// don't exist in namespaces.
   276  	Scope string `marker:",optional"`
   277  }
   278  
   279  func (s Resource) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
   280  	if s.Path != "" {
   281  		crd.Names.Plural = s.Path
   282  	}
   283  	if s.Singular != "" {
   284  		crd.Names.Singular = s.Singular
   285  	}
   286  	crd.Names.ShortNames = s.ShortName
   287  	crd.Names.Categories = s.Categories
   288  
   289  	switch s.Scope {
   290  	case "":
   291  		crd.Scope = apiext.NamespaceScoped
   292  	default:
   293  		crd.Scope = apiext.ResourceScope(s.Scope)
   294  	}
   295  
   296  	return nil
   297  }
   298  
   299  // +controllertools:marker:generateHelp:category=CRD
   300  
   301  // UnservedVersion does not serve this version.
   302  //
   303  // This is useful if you need to drop support for a version in favor of a newer version.
   304  type UnservedVersion struct{}
   305  
   306  func (s UnservedVersion) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
   307  	for i := range crd.Versions {
   308  		ver := &crd.Versions[i]
   309  		if ver.Name != version {
   310  			continue
   311  		}
   312  		ver.Served = false
   313  		break
   314  	}
   315  	return nil
   316  }
   317  
   318  // NB(directxman12): singular was historically distinct, so we keep it here for backwards compat