github.com/alex123012/deckhouse-controller-tools@v0.0.0-20230510090815-d594daf1af8c/pkg/crd/markers/topology.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  	"sigs.k8s.io/controller-tools/pkg/markers"
    24  )
    25  
    26  // TopologyMarkers specify topology markers (i.e. markers that describe if a
    27  // list behaves as an associative-list or a set, if a map is atomic or not).
    28  var TopologyMarkers = []*definitionWithHelp{
    29  	must(markers.MakeDefinition("listMapKey", markers.DescribesField, ListMapKey(""))).
    30  		WithHelp(ListMapKey("").Help()),
    31  	must(markers.MakeDefinition("listMapKey", markers.DescribesType, ListMapKey(""))).
    32  		WithHelp(ListMapKey("").Help()),
    33  	must(markers.MakeDefinition("listType", markers.DescribesField, ListType(""))).
    34  		WithHelp(ListType("").Help()),
    35  	must(markers.MakeDefinition("listType", markers.DescribesType, ListType(""))).
    36  		WithHelp(ListType("").Help()),
    37  	must(markers.MakeDefinition("mapType", markers.DescribesField, MapType(""))).
    38  		WithHelp(MapType("").Help()),
    39  	must(markers.MakeDefinition("mapType", markers.DescribesType, MapType(""))).
    40  		WithHelp(MapType("").Help()),
    41  	must(markers.MakeDefinition("structType", markers.DescribesField, StructType(""))).
    42  		WithHelp(StructType("").Help()),
    43  	must(markers.MakeDefinition("structType", markers.DescribesType, StructType(""))).
    44  		WithHelp(StructType("").Help()),
    45  }
    46  
    47  func init() {
    48  	AllDefinitions = append(AllDefinitions, TopologyMarkers...)
    49  }
    50  
    51  // +controllertools:marker:generateHelp:category="CRD processing"
    52  
    53  // ListType specifies the type of data-structure that the list
    54  // represents (map, set, atomic).
    55  //
    56  // Possible data-structure types of a list are:
    57  //
    58  //   - "map": it needs to have a key field, which will be used to build an
    59  //     associative list. A typical example is a the pod container list,
    60  //     which is indexed by the container name.
    61  //
    62  //   - "set": Fields need to be "scalar", and there can be only one
    63  //     occurrence of each.
    64  //
    65  //   - "atomic": All the fields in the list are treated as a single value,
    66  //     are typically manipulated together by the same actor.
    67  type ListType string
    68  
    69  // +controllertools:marker:generateHelp:category="CRD processing"
    70  
    71  // ListMapKey specifies the keys to map listTypes.
    72  //
    73  // It indicates the index of a map list. They can be repeated if multiple keys
    74  // must be used. It can only be used when ListType is set to map, and the keys
    75  // should be scalar types.
    76  type ListMapKey string
    77  
    78  // +controllertools:marker:generateHelp:category="CRD processing"
    79  
    80  // MapType specifies the level of atomicity of the map;
    81  // i.e. whether each item in the map is independent of the others,
    82  // or all fields are treated as a single unit.
    83  //
    84  // Possible values:
    85  //
    86  //   - "granular": items in the map are independent of each other,
    87  //     and can be manipulated by different actors.
    88  //     This is the default behavior.
    89  //
    90  //   - "atomic": all fields are treated as one unit.
    91  //     Any changes have to replace the entire map.
    92  type MapType string
    93  
    94  // +controllertools:marker:generateHelp:category="CRD processing"
    95  
    96  // StructType specifies the level of atomicity of the struct;
    97  // i.e. whether each field in the struct is independent of the others,
    98  // or all fields are treated as a single unit.
    99  //
   100  // Possible values:
   101  //
   102  //   - "granular": fields in the struct are independent of each other,
   103  //     and can be manipulated by different actors.
   104  //     This is the default behavior.
   105  //
   106  //   - "atomic": all fields are treated as one unit.
   107  //     Any changes have to replace the entire struct.
   108  type StructType string
   109  
   110  func (l ListType) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
   111  	if schema.Type != "array" {
   112  		return fmt.Errorf("must apply listType to an array, found %s", schema.Type)
   113  	}
   114  	if l != "map" && l != "atomic" && l != "set" {
   115  		return fmt.Errorf(`ListType must be either "map", "set" or "atomic"`)
   116  	}
   117  	p := string(l)
   118  	schema.XListType = &p
   119  	return nil
   120  }
   121  
   122  func (l ListType) ApplyFirst() {}
   123  
   124  func (l ListMapKey) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
   125  	if schema.Type != "array" {
   126  		return fmt.Errorf("must apply listMapKey to an array, found %s", schema.Type)
   127  	}
   128  	if schema.XListType == nil || *schema.XListType != "map" {
   129  		return fmt.Errorf("must apply listMapKey to an associative-list")
   130  	}
   131  	schema.XListMapKeys = append(schema.XListMapKeys, string(l))
   132  	return nil
   133  }
   134  
   135  func (m MapType) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
   136  	if schema.Type != "object" {
   137  		return fmt.Errorf("must apply mapType to an object")
   138  	}
   139  
   140  	if m != "atomic" && m != "granular" {
   141  		return fmt.Errorf(`MapType must be either "granular" or "atomic"`)
   142  	}
   143  
   144  	p := string(m)
   145  	schema.XMapType = &p
   146  
   147  	return nil
   148  }
   149  
   150  func (s StructType) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
   151  	if schema.Type != "object" && schema.Type != "" {
   152  		return fmt.Errorf("must apply structType to an object; either explicitly set or defaulted through an empty schema type")
   153  	}
   154  
   155  	if s != "atomic" && s != "granular" {
   156  		return fmt.Errorf(`StructType must be either "granular" or "atomic"`)
   157  	}
   158  
   159  	p := string(s)
   160  	schema.XMapType = &p
   161  
   162  	return nil
   163  }