github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/broker/plans_schema.go (about)

     1  package broker
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/kyma-project/kyma-environment-broker/internal/networking"
     9  )
    10  
    11  type RootSchema struct {
    12  	Schema string `json:"$schema"`
    13  	Type
    14  	Properties interface{} `json:"properties"`
    15  	Required   []string    `json:"required"`
    16  
    17  	// Specified to true enables form view on website
    18  	ShowFormView bool `json:"_show_form_view"`
    19  	// Specifies in what order properties will be displayed on the form
    20  	ControlsOrder []string `json:"_controlsOrder"`
    21  }
    22  
    23  type ProvisioningProperties struct {
    24  	UpdateProperties
    25  
    26  	Name        NameType        `json:"name"`
    27  	ShootName   *Type           `json:"shootName,omitempty"`
    28  	ShootDomain *Type           `json:"shootDomain,omitempty"`
    29  	Region      *Type           `json:"region,omitempty"`
    30  	Networking  *NetworkingType `json:"networking,omitempty"`
    31  	Modules     *Modules        `json:"modules,omitempty"`
    32  }
    33  
    34  type UpdateProperties struct {
    35  	Kubeconfig     *Type     `json:"kubeconfig,omitempty"`
    36  	AutoScalerMin  *Type     `json:"autoScalerMin,omitempty"`
    37  	AutoScalerMax  *Type     `json:"autoScalerMax,omitempty"`
    38  	OIDC           *OIDCType `json:"oidc,omitempty"`
    39  	Administrators *Type     `json:"administrators,omitempty"`
    40  	MachineType    *Type     `json:"machineType,omitempty"`
    41  }
    42  
    43  func (up *UpdateProperties) IncludeAdditional() {
    44  	up.OIDC = NewOIDCSchema()
    45  	up.Administrators = AdministratorsProperty()
    46  }
    47  
    48  type NetworkingProperties struct {
    49  	Nodes Type `json:"nodes"`
    50  }
    51  
    52  type NetworkingType struct {
    53  	Type
    54  	Properties NetworkingProperties `json:"properties"`
    55  	Required   []string             `json:"required"`
    56  }
    57  
    58  type OIDCProperties struct {
    59  	ClientID       Type `json:"clientID"`
    60  	GroupsClaim    Type `json:"groupsClaim"`
    61  	IssuerURL      Type `json:"issuerURL"`
    62  	SigningAlgs    Type `json:"signingAlgs"`
    63  	UsernameClaim  Type `json:"usernameClaim"`
    64  	UsernamePrefix Type `json:"usernamePrefix"`
    65  }
    66  
    67  type OIDCType struct {
    68  	Type
    69  	Properties OIDCProperties `json:"properties"`
    70  	Required   []string       `json:"required"`
    71  }
    72  
    73  type Type struct {
    74  	Type        string `json:"type"`
    75  	Title       string `json:"title,omitempty"`
    76  	Description string `json:"description,omitempty"`
    77  	Minimum     int    `json:"minimum,omitempty"`
    78  	Maximum     int    `json:"maximum,omitempty"`
    79  	MinLength   int    `json:"minLength,omitempty"`
    80  	MaxLength   int    `json:"maxLength,omitempty"`
    81  
    82  	// Regex pattern to match against string type of fields.
    83  	// If not specified for strings user can pass empty string with whitespaces only.
    84  	Pattern              string            `json:"pattern,omitempty"`
    85  	Default              interface{}       `json:"default,omitempty"`
    86  	Example              interface{}       `json:"example,omitempty"`
    87  	Enum                 []interface{}     `json:"enum,omitempty"`
    88  	EnumDisplayName      map[string]string `json:"_enumDisplayName,omitempty"`
    89  	Items                *Type             `json:"items,omitempty"`
    90  	AdditionalItems      interface{}       `json:"additionalItems,omitempty"`
    91  	UniqueItems          interface{}       `json:"uniqueItems,omitempty"`
    92  	ReadOnly             interface{}       `json:"readOnly,omitempty"`
    93  	AdditionalProperties interface{}       `json:"additionalProperties,omitempty"`
    94  }
    95  
    96  type NameType struct {
    97  	Type
    98  	BTPdefaultTemplate BTPdefaultTemplate `json:"_BTPdefaultTemplate,omitempty"`
    99  }
   100  
   101  type BTPdefaultTemplate struct {
   102  	Elements  []string `json:"elements,omitempty"`
   103  	Separator string   `json:"separator,omitempty"`
   104  }
   105  
   106  type Modules struct {
   107  	Type
   108  	ControlsOrder []string      `json:"_controlsOrder,omitempty"`
   109  	OneOf         []interface{} `json:"oneOf,omitempty"`
   110  }
   111  
   112  type ModulesDefault struct {
   113  	Type
   114  	Properties ModulesDefaultProperties `json:"properties,omitempty"`
   115  }
   116  
   117  type ModulesDefaultProperties struct {
   118  	Default Type `json:"default,omitempty"`
   119  }
   120  
   121  type ModulesCustom struct {
   122  	Type
   123  	Properties ModulesCustomProperties `json:"properties,omitempty"`
   124  }
   125  
   126  type ModulesCustomProperties struct {
   127  	List ModulesCustomList `json:"list,omitempty"`
   128  }
   129  
   130  type ModulesCustomList struct {
   131  	Type
   132  	Items ModulesCustomListItems `json:"items,omitempty"`
   133  }
   134  
   135  type ModulesCustomListItems struct {
   136  	Type
   137  	ControlsOrder []string                         `json:"_controlsOrder,omitempty"`
   138  	Properties    ModulesCustomListItemsProperties `json:"properties,omitempty"`
   139  }
   140  
   141  type ModulesCustomListItemsProperties struct {
   142  	Name                 Type `json:"name,omitempty"`
   143  	Channel              Type `json:"channel,omitempty"`
   144  	CustomResourcePolicy Type `json:"customResourcePolicy,omitempty"`
   145  }
   146  
   147  func NewModulesSchema(modulesEnabled bool) *Modules {
   148  	if !modulesEnabled {
   149  		return nil
   150  	}
   151  	return &Modules{
   152  		Type: Type{
   153  			Type:        "object",
   154  			Description: "Use default modules or provide your custom list of modules.",
   155  		},
   156  		ControlsOrder: []string{"default", "list"},
   157  		OneOf: []any{
   158  			ModulesDefault{
   159  				Type: Type{
   160  					Type:                 "object",
   161  					Title:                "Default",
   162  					Description:          "Default modules",
   163  					AdditionalProperties: false,
   164  				},
   165  				Properties: ModulesDefaultProperties{
   166  					Type{
   167  						Type:        "boolean",
   168  						Title:       "Use Default",
   169  						Description: "Check the default modules at: https://help.sap.com/docs/btp/sap-business-technology-platform/kyma-modules?version=Cloud.",
   170  						Default:     true,
   171  						ReadOnly:    true,
   172  					},
   173  				},
   174  			},
   175  			ModulesCustom{
   176  				Type: Type{
   177  					Type:                 "object",
   178  					Title:                "Custom",
   179  					Description:          "Define custom module list",
   180  					AdditionalProperties: false,
   181  				},
   182  				Properties: ModulesCustomProperties{
   183  					ModulesCustomList{
   184  						Type: Type{
   185  							Type:        "array",
   186  							UniqueItems: true,
   187  							Description: "Select a module technical name from the list available at: https://help.sap.com/docs/btp/sap-business-technology-platform/kyma-modules?version=Cloud. You can only use a module technical name once.",
   188  						},
   189  						Items: ModulesCustomListItems{
   190  							ControlsOrder: []string{"name", "channel", "customResourcePolicy"},
   191  							Type: Type{
   192  								Type: "object",
   193  							},
   194  							Properties: ModulesCustomListItemsProperties{
   195  								Name: Type{
   196  									Type:        "string",
   197  									Title:       "Name",
   198  									MinLength:   1,
   199  									Description: "Select a module technical name from the list available at: https://help.sap.com/docs/btp/sap-business-technology-platform/kyma-modules?version=Cloud. You can only use a module technical name once.",
   200  								},
   201  								Channel: Type{
   202  									Type:        "string",
   203  									Default:     "regular",
   204  									Description: "Select your preferred release channel.",
   205  									Enum:        ToInterfaceSlice([]string{"regular", "fast"}),
   206  									EnumDisplayName: map[string]string{
   207  										"regular": "Regular - default version",
   208  										"fast":    "Fast - latest version",
   209  									},
   210  								},
   211  								CustomResourcePolicy: Type{
   212  									Type:        "string",
   213  									Description: "Select your preferred CustomResourcePolicy setting.",
   214  									Default:     "CreateAndDelete",
   215  									Enum:        ToInterfaceSlice([]string{"CreateAndDelete", "Ignore"}),
   216  									EnumDisplayName: map[string]string{
   217  										"CreateAndDelete": "CreateAndDelete - default module resource is created or deleted.",
   218  										"Ignore":          "Ignore - module resource is not created.",
   219  									},
   220  								},
   221  							},
   222  						},
   223  					}},
   224  			}},
   225  	}
   226  }
   227  
   228  func NameProperty() NameType {
   229  	return NameType{
   230  		Type: Type{
   231  			Type:  "string",
   232  			Title: "Cluster Name",
   233  			// Allows for all alphanumeric characters and '-'
   234  			Pattern:   "^[a-zA-Z0-9-]*$",
   235  			MinLength: 1,
   236  		},
   237  		BTPdefaultTemplate: BTPdefaultTemplate{
   238  			Elements: []string{"saSubdomain"},
   239  		},
   240  	}
   241  }
   242  
   243  func KubeconfigProperty() *Type {
   244  	return &Type{
   245  		Type:  "string",
   246  		Title: "Kubeconfig contents",
   247  	}
   248  }
   249  
   250  func ShootNameProperty() *Type {
   251  	return &Type{
   252  		Type:      "string",
   253  		Title:     "Shoot name",
   254  		Pattern:   "^[a-zA-Z0-9-]*$",
   255  		MinLength: 1,
   256  	}
   257  }
   258  
   259  func ShootDomainProperty() *Type {
   260  	return &Type{
   261  		Type:      "string",
   262  		Title:     "Shoot domain",
   263  		Pattern:   "^[a-zA-Z0-9-\\.]*$",
   264  		MinLength: 1,
   265  	}
   266  }
   267  
   268  // NewProvisioningProperties creates a new properties for different plans
   269  // Note that the order of properties will be the same in the form on the website
   270  func NewProvisioningProperties(machineTypesDisplay map[string]string, machineTypes, regions []string, update, modulesEnabled bool) ProvisioningProperties {
   271  
   272  	properties := ProvisioningProperties{
   273  		UpdateProperties: UpdateProperties{
   274  			AutoScalerMin: &Type{
   275  				Type:        "integer",
   276  				Minimum:     2,
   277  				Default:     3,
   278  				Description: "Specifies the minimum number of virtual machines to create",
   279  			},
   280  			AutoScalerMax: &Type{
   281  				Type:        "integer",
   282  				Minimum:     2,
   283  				Maximum:     80,
   284  				Default:     20,
   285  				Description: "Specifies the maximum number of virtual machines to create",
   286  			},
   287  			MachineType: &Type{
   288  				Type:            "string",
   289  				Enum:            ToInterfaceSlice(machineTypes),
   290  				EnumDisplayName: machineTypesDisplay,
   291  			},
   292  		},
   293  		Name: NameProperty(),
   294  		Region: &Type{
   295  			Type: "string",
   296  			Enum: ToInterfaceSlice(regions),
   297  		},
   298  		Networking: NewNetworkingSchema(),
   299  		Modules:    NewModulesSchema(modulesEnabled),
   300  	}
   301  
   302  	if update {
   303  		properties.AutoScalerMax.Default = nil
   304  		properties.AutoScalerMin.Default = nil
   305  	}
   306  
   307  	return properties
   308  }
   309  
   310  func NewNetworkingSchema() *NetworkingType {
   311  	seedCIDRs := strings.Join(networking.GardenerSeedCIDRs, ", ")
   312  	return &NetworkingType{
   313  		Type: Type{Type: "object", Description: "Networking configuration. These values are immutable and cannot be updated later."},
   314  		Properties: NetworkingProperties{
   315  			Nodes: Type{Type: "string", Title: "CIDR range for nodes", Description: fmt.Sprintf("CIDR range for nodes, must not overlap with the following CIDRs: %s, %s, %s", networking.DefaultPodsCIDR, networking.DefaultServicesCIDR, seedCIDRs),
   316  				Default: networking.DefaultNodesCIDR},
   317  		},
   318  		Required: []string{"nodes"},
   319  	}
   320  }
   321  
   322  func NewOIDCSchema() *OIDCType {
   323  	return &OIDCType{
   324  		Type: Type{Type: "object", Description: "OIDC configuration"},
   325  		Properties: OIDCProperties{
   326  			ClientID:       Type{Type: "string", Description: "The client ID for the OpenID Connect client."},
   327  			IssuerURL:      Type{Type: "string", Description: "The URL of the OpenID issuer, only HTTPS scheme will be accepted."},
   328  			GroupsClaim:    Type{Type: "string", Description: "If provided, the name of a custom OpenID Connect claim for specifying user groups."},
   329  			UsernameClaim:  Type{Type: "string", Description: "The OpenID claim to use as the user name."},
   330  			UsernamePrefix: Type{Type: "string", Description: "If provided, all usernames will be prefixed with this value. If not provided, username claims other than 'email' are prefixed by the issuer URL to avoid clashes. To skip any prefixing, provide the value '-' (dash character without additional characters)."},
   331  			SigningAlgs: Type{
   332  				Type: "array",
   333  				Items: &Type{
   334  					Type: "string",
   335  				},
   336  				Description: "Comma separated list of allowed JOSE asymmetric signing algorithms, for example, RS256, ES256",
   337  			},
   338  		},
   339  		Required: []string{"clientID", "issuerURL"},
   340  	}
   341  }
   342  
   343  func NewSchema(properties interface{}, update bool, required []string) *RootSchema {
   344  	schema := &RootSchema{
   345  		Schema: "http://json-schema.org/draft-04/schema#",
   346  		Type: Type{
   347  			Type: "object",
   348  		},
   349  		Properties:   properties,
   350  		ShowFormView: true,
   351  		Required:     required,
   352  	}
   353  
   354  	if update {
   355  		schema.Required = []string{}
   356  	}
   357  
   358  	return schema
   359  }
   360  
   361  func unmarshalOrPanic(from, to interface{}) interface{} {
   362  	if from != nil {
   363  		marshaled := Marshal(from)
   364  		err := json.Unmarshal(marshaled, to)
   365  		if err != nil {
   366  			panic(err)
   367  		}
   368  	}
   369  	return to
   370  }
   371  
   372  func DefaultControlsOrder() []string {
   373  	return []string{"name", "kubeconfig", "shootName", "shootDomain", "region", "machineType", "autoScalerMin", "autoScalerMax", "zonesCount", "modules", "networking", "oidc", "administrators"}
   374  }
   375  
   376  func ToInterfaceSlice(input []string) []interface{} {
   377  	interfaces := make([]interface{}, len(input))
   378  	for i, item := range input {
   379  		interfaces[i] = item
   380  	}
   381  	return interfaces
   382  }
   383  
   384  func AdministratorsProperty() *Type {
   385  	return &Type{
   386  		Type:        "array",
   387  		Title:       "Administrators",
   388  		Description: "Specifies the list of runtime administrators",
   389  		Items: &Type{
   390  			Type: "string",
   391  		},
   392  	}
   393  }