github.com/jlmeeker/kismatic@v1.10.1-0.20180612190640-57f9005a1f1a/pkg/install/plan_types.go (about)

     1  package install
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strings"
     7  
     8  	"github.com/apprenda/kismatic/pkg/ssh"
     9  	"github.com/apprenda/kismatic/pkg/tls"
    10  )
    11  
    12  const (
    13  	cniProviderContiv = "contiv"
    14  	cniProviderCalico = "calico"
    15  	cniProviderWeave  = "weave"
    16  	cniProviderCustom = "custom"
    17  )
    18  
    19  const (
    20  	dnsProviderKubedns = "kubedns"
    21  	dnsProviderCoredns = "coredns"
    22  )
    23  
    24  func packageManagerProviders() []string {
    25  	return []string{"helm", ""}
    26  }
    27  
    28  func cniProviders() []string {
    29  	return []string{cniProviderCalico, cniProviderContiv, cniProviderWeave, cniProviderCustom}
    30  }
    31  
    32  func dnsProviders() []string {
    33  	return []string{dnsProviderKubedns, dnsProviderCoredns}
    34  }
    35  
    36  func calicoMode() []string {
    37  	return []string{"overlay", "routed"}
    38  }
    39  
    40  func calicoLogLevel() []string {
    41  	return []string{"warning", "info", "debug", ""}
    42  }
    43  
    44  func serviceTypes() []string {
    45  	return []string{"ClusterIP", "NodePort", "LoadBalancer", "ExternalName"}
    46  }
    47  
    48  func cloudProviders() []string {
    49  	return []string{"aws", "azure", "cloudstack", "fake", "gce", "mesos", "openstack", "ovirt", "photon", "rackspace", "vsphere"}
    50  }
    51  
    52  func roles() []string {
    53  	return []string{"etcd", "master", "worker", "ingress", "storage"}
    54  }
    55  
    56  func taintEffects() []string {
    57  	return []string{"NoSchedule", "PreferNoSchedule", "NoExecute"}
    58  }
    59  
    60  // Plan is the installation plan that the user intends to execute
    61  type Plan struct {
    62  	// Kubernetes cluster configuration
    63  	// +required
    64  	Cluster Cluster
    65  	// Configuration for the docker engine installed by KET
    66  	Docker Docker
    67  	// Docker registry configuration
    68  	DockerRegistry DockerRegistry `yaml:"docker_registry"`
    69  	// A set of files or directories to copy from the local machine to any of the nodes in the cluster.
    70  	AdditionalFiles []AdditionalFile `yaml:"additional_files"`
    71  	// Add on configuration
    72  	AddOns AddOns `yaml:"add_ons"`
    73  	// Feature configuration
    74  	// +deprecated
    75  	Features *Features `yaml:"features,omitempty"`
    76  	// Etcd nodes of the cluster
    77  	// +required
    78  	Etcd NodeGroup
    79  	// Master nodes of the cluster
    80  	// +required
    81  	Master MasterNodeGroup
    82  	// Worker nodes of the cluster
    83  	// +required
    84  	Worker NodeGroup
    85  	// Ingress nodes of the cluster
    86  	Ingress OptionalNodeGroup
    87  	// Storage nodes of the cluster.
    88  	Storage OptionalNodeGroup
    89  	// NFS volumes of the cluster.
    90  	NFS *NFS `yaml:"nfs,omitempty"`
    91  }
    92  
    93  // Cluster describes a Kubernetes cluster
    94  type Cluster struct {
    95  	// Name of the cluster to be used when generating assets that require a
    96  	// cluster name, such as kubeconfig files and certificates.
    97  	// +required
    98  	Name string
    99  	// The Kubernetes version to install.
   100  	// If left blank will be set to the latest tested version.
   101  	// Only a single Minor version is supported with.
   102  	// +default=v1.10.3
   103  	Version string
   104  	// The password for the admin user.
   105  	// If provided, ABAC will be enabled in the cluster.
   106  	// This field will be removed completely in a future release.
   107  	// +deprecated
   108  	AdminPassword string `yaml:"admin_password,omitempty"`
   109  	// Whether KET should install the packages on the cluster nodes.
   110  	// When true, KET will not install the required packages.
   111  	// Instead, it will verify that the packages have been installed by the operator.
   112  	DisablePackageInstallation bool `yaml:"disable_package_installation"`
   113  	// Whether KET should install the packages on the cluster nodes.
   114  	// Use DisablePackageInstallation instead.
   115  	// +deprecated
   116  	AllowPackageInstallation *bool `yaml:"allow_package_installation,omitempty"`
   117  	// Whether the cluster nodes are disconnected from the internet.
   118  	// When set to `true`, internal package repositories and a container image
   119  	// registry are required for installation.
   120  	// +default=false
   121  	DisconnectedInstallation bool `yaml:"disconnected_installation"`
   122  	// The Networking configuration for the cluster.
   123  	Networking NetworkConfig
   124  	// The Certificates configuration for the cluster.
   125  	Certificates CertsConfig
   126  	// The SSH configuration for the cluster nodes.
   127  	SSH SSHConfig
   128  	// Kubernetes API Server configuration.
   129  	APIServerOptions APIServerOptions `yaml:"kube_apiserver"`
   130  	// Kubernetes Controller Manager configuration.
   131  	KubeControllerManagerOptions KubeControllerManagerOptions `yaml:"kube_controller_manager"`
   132  	// Kubernetes Scheduler configuration.
   133  	KubeSchedulerOptions KubeSchedulerOptions `yaml:"kube_scheduler"`
   134  	// Kubernetes Proxy configuration.
   135  	KubeProxyOptions KubeProxyOptions `yaml:"kube_proxy"`
   136  	// Kubelet configuration applied to all nodes.
   137  	KubeletOptions KubeletOptions `yaml:"kubelet"`
   138  	// The CloudProvider configuration for the cluster.
   139  	CloudProvider CloudProvider `yaml:"cloud_provider"`
   140  }
   141  
   142  type APIServerOptions struct {
   143  	// Listing of option overrides that are to be applied to the Kubernetes
   144  	// API server configuration. This is an advanced feature that can prevent
   145  	// the API server from starting up if invalid configuration is provided.
   146  	Overrides map[string]string `yaml:"option_overrides"`
   147  }
   148  
   149  type KubeControllerManagerOptions struct {
   150  	// Listing of option overrides that are to be applied to the Kubernetes
   151  	// Controller Manager configuration. This is an advanced feature that can prevent
   152  	// the Controller Manager from starting up if invalid configuration is provided.
   153  	Overrides map[string]string `yaml:"option_overrides"`
   154  }
   155  
   156  type KubeProxyOptions struct {
   157  	// Listing of option overrides that are to be applied to the Kubernetes
   158  	// Proxy configuration. This is an advanced feature that can prevent
   159  	// the Proxy from starting up if invalid configuration is provided.
   160  	Overrides map[string]string `yaml:"option_overrides"`
   161  }
   162  
   163  type KubeSchedulerOptions struct {
   164  	// Listing of option overrides that are to be applied to the Kubernetes
   165  	// Scheduler configuration. This is an advanced feature that can prevent
   166  	// the Scheduler from starting up if invalid configuration is provided.
   167  	Overrides map[string]string `yaml:"option_overrides"`
   168  }
   169  
   170  type KubeletOptions struct {
   171  	// Listing of option overrides that are to be applied to the Kubelet configurations.
   172  	// This is an advanced feature that can prevent the Kubelet from starting up if invalid configuration is provided.
   173  	Overrides map[string]string `yaml:"option_overrides"`
   174  }
   175  
   176  // NetworkConfig describes the cluster's networking configuration
   177  type NetworkConfig struct {
   178  	// The datapath technique that should be configured in Calico.
   179  	// +default=overlay
   180  	// +options=overlay,routed
   181  	// +deprecated
   182  	Type string `yaml:"type,omitempty"`
   183  	// The pod network's CIDR block. For example: `172.16.0.0/16`
   184  	// +required
   185  	PodCIDRBlock string `yaml:"pod_cidr_block"`
   186  	// The Kubernetes service network's CIDR block. For example: `172.20.0.0/16`
   187  	// +required
   188  	ServiceCIDRBlock string `yaml:"service_cidr_block"`
   189  	// Whether the /etc/hosts file should be updated on the cluster nodes.
   190  	// When set to true, KET will update the hosts file on all nodes to include
   191  	// entries for all other nodes in the cluster.
   192  	// +default=false
   193  	UpdateHostsFiles bool `yaml:"update_hosts_files"`
   194  	// The URL of the proxy that should be used for HTTP connections.
   195  	HTTPProxy string `yaml:"http_proxy"`
   196  	// The URL of the proxy that should be used for HTTPS connections.
   197  	HTTPSProxy string `yaml:"https_proxy"`
   198  	// Comma-separated list of host names and/or IPs for which connections
   199  	// should not go through a proxy.
   200  	// All nodes' 'host' and 'IPs' are always set.
   201  	NoProxy string `yaml:"no_proxy"`
   202  }
   203  
   204  // CertsConfig describes the cluster's trust and certificate configuration
   205  type CertsConfig struct {
   206  	// The length of time that the generated certificates should be valid for.
   207  	// For example: "17520h" for 2 years.
   208  	// +required
   209  	Expiry string
   210  	// The length of time that the generated Certificate Authority should be valid for.
   211  	// For example: "17520h" for 2 years.
   212  	// +required.
   213  	CAExpiry string `yaml:"ca_expiry"`
   214  }
   215  
   216  // SSHConfig describes the cluster's SSH configuration for accessing nodes
   217  type SSHConfig struct {
   218  	// The user for accessing the cluster nodes via SSH.
   219  	// This user requires sudo elevation privileges on the cluster nodes.
   220  	// +required
   221  	User string
   222  	// The absolute path of the SSH key that should be used for accessing the
   223  	// cluster nodes via SSH.
   224  	// +required
   225  	Key string `yaml:"ssh_key"`
   226  	// The port number on which cluster nodes are listening for SSH connections.
   227  	// +required
   228  	Port int `yaml:"ssh_port"`
   229  }
   230  
   231  // CloudProvider controls the Kubernetes cloud providers feature
   232  type CloudProvider struct {
   233  	// The cloud provider that should be set in the Kubernetes components
   234  	// +options=aws,azure,cloudstack,fake,gce,mesos,openstack,ovirt,photon,rackspace,vsphere
   235  	Provider string
   236  	// Path to the cloud provider config file. This will be copied to all the machines in the cluster
   237  	Config string
   238  }
   239  
   240  // Docker includes the configuration for the docker installation owned by KET.
   241  type Docker struct {
   242  	// Set to true to disable the installation of docker container runtime on the nodes.
   243  	// The installer will validate that docker is installed and running prior to proceeding.
   244  	// Use this option if a different version of docker from the included one is required.
   245  	Disable bool
   246  	// Log configuration for the docker engine.
   247  	Logs DockerLogs
   248  	// Storage configuration for the docker engine.
   249  	Storage DockerStorage
   250  }
   251  
   252  // DockerLogs includes the log-specific configuration for docker.
   253  type DockerLogs struct {
   254  	// Docker logging driver, more details https://docs.docker.com/engine/admin/logging/overview/.
   255  	// +default=json-file
   256  	Driver string
   257  	// Driver specific options.
   258  	Opts map[string]string
   259  }
   260  
   261  // DockerStorage includes the storage-specific configuration for docker.
   262  type DockerStorage struct {
   263  	// Docker storage driver, more details https://docs.docker.com/engine/userguide/storagedriver/.
   264  	// Leave empty to have docker automatically select the driver.
   265  	// +default='empty'
   266  	Driver string
   267  	// Driver specific options
   268  	Opts map[string]string
   269  	// DirectLVMBlockDevice is the configuration required for setting up Device Mapper storage driver in direct-lvm mode.
   270  	// Refer to https://docs.docker.com/v17.03/engine/userguide/storagedriver/device-mapper-driver/#manage-devicemapper docs.
   271  	DirectLVMBlockDevice DirectLVMBlockDevice `yaml:"direct_lvm_block_device"`
   272  	// DirectLVM is the configuration required for setting up device mapper in direct-lvm mode.
   273  	// +deprecated
   274  	DirectLVM *DockerStorageDirectLVMDeprecated `yaml:"direct_lvm,omitempty"`
   275  }
   276  
   277  type DirectLVMBlockDevice struct {
   278  	// The path to the block device.
   279  	Path string
   280  	// The percentage of space to use for storage from the passed in block device.
   281  	// +default=95
   282  	ThinpoolPercent string `yaml:"thinpool_percent"`
   283  	// The percentage of space to for metadata storage from the passed in block device.
   284  	// +default=1
   285  	ThinpoolMetaPercent string `yaml:"thinpool_metapercent"`
   286  	// The threshold for when lvm should automatically extend the thin pool as a percentage of the total storage space.
   287  	// +default=80
   288  	ThinpoolAutoextendThreshold string `yaml:"thinpool_autoextend_threshold"`
   289  	// The percentage to increase the thin pool by when an autoextend is triggered.
   290  	// +default=20
   291  	ThinpoolAutoextendPercent string `yaml:"thinpool_autoextend_percent"`
   292  }
   293  
   294  // DockerStorageDirectLVMDeprecated includes the configuration required for setting up
   295  // device mapper in direct-lvm mode.
   296  type DockerStorageDirectLVMDeprecated struct {
   297  	// Whether the direct_lvm mode of the devicemapper storage driver should be enabled.
   298  	// When set to true, a dedicated block storage device must be available on each cluster node.
   299  	// +default=false
   300  	Enabled bool
   301  	// The path to the block storage device that will be used by the devicemapper storage driver.
   302  	BlockDevice string `yaml:"block_device"`
   303  	// Whether deferred deletion should be enabled when using devicemapper in direct_lvm mode.
   304  	// +default=false
   305  	EnableDeferredDeletion bool `yaml:"enable_deferred_deletion"`
   306  }
   307  
   308  // AdditionalFile is a file or directory to copy to remote host(s) from the local host
   309  type AdditionalFile struct {
   310  	// Hostname or role where additional files or directories will be copied.
   311  	// +required
   312  	Hosts []string
   313  	// Path to the file or directory on local machine.
   314  	// Must be an absolute path.
   315  	// +required
   316  	Source string
   317  	// Path to the file or directory on remote machine, where file will be copied.
   318  	// Must be an absolute path.
   319  	// +required
   320  	Destination string
   321  	// Set to true if validation will be run before the file exists on the local machine.
   322  	// Useful for files generated at install time, ie. assets in generated/ directory.
   323  	SkipValidation bool `yaml:"skip_validation"`
   324  }
   325  
   326  // DockerRegistry details for docker registry, either confgiured by the cli or customer provided
   327  type DockerRegistry struct {
   328  	// The hostname or IP address and port of a private container image registry.
   329  	// Do not include http or https.
   330  	// When performing a disconnected installation, this registry will be used
   331  	// to fetch all the required container images.
   332  	Server string
   333  	// The hostname or IP address of a private container image registry.
   334  	// When performing a disconnected installation, this registry will be used
   335  	// to fetch all the required container images.
   336  	// +deprecated
   337  	Address string `yaml:"address,omitempty"`
   338  	// The port on which the private container image registry is listening on.
   339  	// +deprecated
   340  	Port int `yaml:"port,omitempty"`
   341  	// The absolute path of the Certificate Authority that should be installed on
   342  	// all cluster nodes that have a docker daemon.
   343  	// This is required to establish trust between the daemons and the private
   344  	// registry when the registry is using a self-signed certificate.
   345  	CAPath string `yaml:"CA"`
   346  	// The username that should be used when connecting to a registry that has authentication enabled.
   347  	// Otherwise leave blank for unauthenticated access.
   348  	Username string
   349  	// The password that should be used when connecting to a registry that has authentication enabled.
   350  	// Otherwise leave blank for unauthenticated access.
   351  	Password string
   352  }
   353  
   354  // AddOns are components that are deployed on the cluster that KET considers
   355  // necessary for producing a production cluster.
   356  type AddOns struct {
   357  	// The Container Networking Interface (CNI) add-on configuration.
   358  	CNI *CNI `yaml:"cni"`
   359  	// The DNS add-on configuration.
   360  	DNS DNS `yaml:"dns"`
   361  	// The Heapster Monitoring add-on configuration.
   362  	HeapsterMonitoring *HeapsterMonitoring `yaml:"heapster"`
   363  	// Metrics Server add-on configuration.
   364  	// A cluster-wide aggregator of resource usage data.
   365  	// Required for Horizontal Pod Autoscaler to function properly.
   366  	MetricsServer MetricsServer `yaml:"metrics_server"`
   367  	// The Dashboard add-on configuration.
   368  	Dashboard Dashboard `yaml:"dashboard"`
   369  	// The PackageManager add-on configuration.
   370  	PackageManager PackageManager `yaml:"package_manager"`
   371  	// The Rescheduler add-on configuration.
   372  	// Because the Rescheduler does not have leader election and therefore can only run as a single instance in a cluster, it will be deployed as a static pod on the first master.
   373  	// More information about the Rescheduler can be found here: https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/
   374  	Rescheduler Rescheduler `yaml:"rescheduler"`
   375  }
   376  
   377  // Features configuration
   378  // +deprecated
   379  type Features struct {
   380  	// The PackageManager feature configuration.
   381  	// +deprecated
   382  	PackageManager *DeprecatedPackageManager `yaml:"package_manager,omitempty"`
   383  }
   384  
   385  // CNI add-on configuration
   386  type CNI struct {
   387  	// Whether the CNI add-on is disabled. When set to true,
   388  	// CNI will not be installed on the cluster. Furthermore, the smoke test and
   389  	// any validation that depends on a functional pod network will be skipped.
   390  	// +default=false
   391  	Disable bool
   392  	// The CNI provider that should be installed on the cluster.
   393  	// +default=calico
   394  	// +options=calico,weave,contiv,custom
   395  	Provider string
   396  	// The CNI options that can be configured for each CNI provider.
   397  	Options CNIOptions `yaml:"options"`
   398  }
   399  
   400  // CNIOptions that can be configured for each CNI provider.
   401  type CNIOptions struct {
   402  	// The options that can be configured for the Portmap CNI provider.
   403  	Portmap PortmapOptions
   404  	// The options that can be configured for the Calico CNI provider.
   405  	Calico CalicoOptions
   406  	// The options that can be configured for the Weave CNI provider.
   407  	Weave WeaveOptions
   408  }
   409  
   410  // The PortmapOptions that can be configured for the Portmap CNI plugin.
   411  type PortmapOptions struct {
   412  	// Disable the portmap CNI plugin
   413  	// +default=false
   414  	Disable bool
   415  }
   416  
   417  // The CalicoOptions that can be configured for the Calico CNI provider.
   418  type CalicoOptions struct {
   419  	// The datapath technique that should be configured in Calico.
   420  	// +default=overlay
   421  	// +options=overlay,routed
   422  	Mode string
   423  	// The logging level for the CNI plugin
   424  	// +default=info
   425  	// +options=warning,info,debug
   426  	LogLevel string `yaml:"log_level"`
   427  	// MTU for the workload interface, configures the CNI config.
   428  	// +default=1500
   429  	WorkloadMTU int `yaml:"workload_mtu"`
   430  	// MTU for the tunnel device used if IPIP is enabled.
   431  	// +default=1440
   432  	FelixInputMTU int `yaml:"felix_input_mtu"`
   433  	// IPAutodetectionMethod is used to detect the IPv4 address of the host.
   434  	// The value gets set in IP_AUTODETECTION_METHOD variable in the pod.
   435  	// +default=first-found
   436  	IPAutodetectionMethod string `yaml:"ip_autodetection_method"`
   437  }
   438  
   439  // The WeaveOptions that can be configured for the Weave CNI provider.
   440  type WeaveOptions struct {
   441  	// The password to use for network traffic encryption.
   442  	Password string
   443  }
   444  
   445  // The DNS add-on configuration
   446  type DNS struct {
   447  	// Whether the DNS add-on should be disabled.
   448  	// When set to true, no DNS solution will be deployed on the cluster.
   449  	Disable bool
   450  	// This property indicates the in-cluster DNS provider.
   451  	// +required
   452  	// +options=kubedns,coredns
   453  	// +default=kubedns
   454  	Provider string
   455  	// The options that can be configured for the cluster DNS add-on
   456  	Options DNSOptions
   457  }
   458  
   459  type DNSOptions struct {
   460  	// Number of cluster DNS replicas that should be scheduled on the cluster.
   461  	// +default=2
   462  	Replicas int
   463  }
   464  
   465  // The HeapsterMonitoring add-on configuration
   466  type HeapsterMonitoring struct {
   467  	// Whether the Heapster add-on should be disabled.
   468  	// When set to true, Heapster and InfluxDB will not be deployed on the cluster.
   469  	// +default=false
   470  	Disable bool
   471  	// The options that can be configured for the Heapster add-on
   472  	Options HeapsterOptions `yaml:"options"`
   473  }
   474  
   475  // The HeapsterOptions for the HeapsterMonitoring add-on
   476  type HeapsterOptions struct {
   477  	// The Heapster configuration options.
   478  	Heapster Heapster `yaml:"heapster"`
   479  	// The InfluxDB configuration options.
   480  	InfluxDB InfluxDB `yaml:"influxdb"`
   481  	// Number of Heapster replicas that should be scheduled on the cluster.
   482  	// +deprecated
   483  	HeapsterReplicas int `yaml:"heapster_replicas,omitempty"`
   484  	// Name of the Persistent Volume Claim that will be used by InfluxDB.
   485  	// When set, this PVC must be created after the installation.
   486  	// If not set, InfluxDB will be configured with ephemeral storage.
   487  	// +deprecated
   488  	InfluxDBPVCName string `yaml:"influxdb_pvc_name,omitempty"`
   489  }
   490  
   491  // Heapster configuration options for the Heapster add-on
   492  type Heapster struct {
   493  	// Number of Heapster replicas that should be scheduled on the cluster.
   494  	// +default=2
   495  	Replicas int `yaml:"replicas"`
   496  	// Kubernetes service type of the Heapster service.
   497  	// +default=ClusterIP
   498  	// +options=ClusterIP,NodePort,LoadBalancer,ExternalName
   499  	ServiceType string `yaml:"service_type"`
   500  	// URL of the backend store that will be used as the Heapster sink.
   501  	// +default=influxdb:http://heapster-influxdb.kube-system.svc:8086
   502  	Sink string `yaml:"sink"`
   503  }
   504  
   505  // The MetricsServer add-on configuration.
   506  type MetricsServer struct {
   507  	// Whether the metrics-server add-on should be disabled.
   508  	// When set to true, metrics-server will not be deployed on the cluster.
   509  	// +default=false
   510  	Disable bool
   511  }
   512  
   513  // InfluxDB configuration options for the Heapster add-on
   514  type InfluxDB struct {
   515  	// Name of the Persistent Volume Claim that will be used by InfluxDB.
   516  	// This PVC must be created after the installation.
   517  	// If not set, InfluxDB will be configured with ephemeral storage.
   518  	PVCName string `yaml:"pvc_name"`
   519  }
   520  
   521  // Dashboard add-on configuration
   522  type Dashboard struct {
   523  	// Whether the dashboard add-on should be disabled.
   524  	// When set to true, the Kubernetes Dashboard will not be installed on the cluster.
   525  	// +default=false
   526  	Disable bool
   527  	// The options that can be configured for the Dashboard add-on
   528  	Options DashboardOptions
   529  }
   530  
   531  // The DashboardOptions for the Dashboard addon
   532  type DashboardOptions struct {
   533  	// Kubernetes service type of the Dashboard service.
   534  	// +default=ClusterIP
   535  	// +options=ClusterIP,NodePort,LoadBalancer,ExternalName
   536  	ServiceType string `yaml:"service_type"`
   537  	// When using NodePort set the port to use.
   538  	// When left empty Kubernetes will allocate a random port.
   539  	// +default=''
   540  	NodePort string `yaml:"node_port"`
   541  }
   542  
   543  // PackageManager add-on configuration
   544  type PackageManager struct {
   545  	// Whether the package manager add-on should be disabled.
   546  	// When set to true, the package manager will not be installed on the cluster.
   547  	// +default=false
   548  	Disable bool
   549  	// This property indicates the package manager provider.
   550  	// +required
   551  	// +options=helm
   552  	Provider string
   553  	// The PackageManager options.
   554  	Options PackageManagerOptions `yaml:"options"`
   555  }
   556  
   557  // The PackageManagerOptions for the PackageManager add-on
   558  type PackageManagerOptions struct {
   559  	// Helm PackageManager options
   560  	Helm HelmOptions
   561  }
   562  
   563  // HelmOptions for the helm PackageManager add-on
   564  type HelmOptions struct {
   565  	// Namespace to deploy tiller
   566  	// +default=kube-system
   567  	Namespace string
   568  }
   569  
   570  // Rescheduler add-on configuration
   571  type Rescheduler struct {
   572  	// Whether the pod rescheduler add-on should be disabled.
   573  	// When set to true, the rescheduler will not be installed on the cluster.
   574  	// +default=false
   575  	Disable bool
   576  }
   577  
   578  type DeprecatedPackageManager struct {
   579  	// Whether the package manager add-on should be enabled.
   580  	// +deprecated
   581  	Enabled bool
   582  }
   583  
   584  // MasterNodeGroup is the collection of master nodes
   585  type MasterNodeGroup struct {
   586  	// Number of master nodes that are part of the cluster.
   587  	// +required
   588  	ExpectedCount int `yaml:"expected_count"`
   589  	// The FQDN of the load balancer that is fronting multiple master nodes.
   590  	// In the case where there is only one master node, this can be set to the IP address of the master node.
   591  	// +required
   592  	LoadBalancedFQDN string `yaml:"load_balanced_fqdn"`
   593  	// The short name of the load balancer that is fronting multiple master nodes.
   594  	// In the case where there is only one master node, this can be set to the IP address of the master nodes.
   595  	// +required
   596  	LoadBalancedShortName string `yaml:"load_balanced_short_name"`
   597  	// List of master nodes that are part of the cluster.
   598  	// +required
   599  	Nodes []Node
   600  }
   601  
   602  // A NodeGroup is a collection of nodes
   603  type NodeGroup struct {
   604  	// Number of nodes.
   605  	// +required
   606  	ExpectedCount int `yaml:"expected_count"`
   607  	// List of nodes.
   608  	// +required
   609  	Nodes []Node
   610  }
   611  
   612  // An OptionalNodeGroup is a collection of nodes that can be empty
   613  type OptionalNodeGroup NodeGroup
   614  
   615  // A Node is a compute unit, virtual or physical, that is part of the cluster
   616  type Node struct {
   617  	// The hostname of the node. The hostname is verified
   618  	// in the validation phase of the installation.
   619  	// +required
   620  	Host string
   621  	// The IP address of the node. This is the IP address that will be used to
   622  	// connect to the node over SSH.
   623  	// +required
   624  	IP string
   625  	// The internal (or private) IP address of the node.
   626  	// If set, this IP will be used when configuring cluster components.
   627  	InternalIP string
   628  	// Labels to add when installing the node in the cluster.
   629  	// If a node is defined under multiple roles, the labels for that node will be merged.
   630  	// If a label is repeated for the same node,
   631  	// only one will be used in this order: etcd,master,worker,ingress,storage roles where 'storage' has the highest precedence.
   632  	// It is recommended to use reverse-DNS notation to avoid collision with other labels.
   633  	Labels map[string]string
   634  	// Taints to add when installing the node in the cluster.
   635  	// If a node is defined under multiple roles, the taints for that node will be merged.
   636  	// If a taint is repeated for the same node,
   637  	// only one will be used in this order: etcd,master,worker,ingress,storage roles where 'storage' has the highest precedence.
   638  	Taints []Taint
   639  	// Kubelet configuration applied to this node.
   640  	// If a node is repeated for multiple roles, the overrides cannot be different.
   641  	KubeletOptions KubeletOptions `yaml:"kubelet,omitempty"`
   642  }
   643  
   644  // Taint for nodes
   645  type Taint struct {
   646  	// Key for the taint
   647  	Key string
   648  	// Value for the taint
   649  	Value string
   650  	// Effect for the taint
   651  	// +options=NoSchedule,PreferNoSchedule,NoExecute
   652  	Effect string
   653  }
   654  
   655  // Equal returns true of 2 nodes have the same host, IP and InternalIP
   656  func (node Node) Equal(other Node) bool {
   657  	return node.Host == other.Host && node.IP == other.IP && node.InternalIP == other.InternalIP
   658  }
   659  
   660  // HashCode is crude implementation for the Node struct
   661  func (node Node) HashCode() string {
   662  	return fmt.Sprint(node.Host, node.IP, node.InternalIP)
   663  }
   664  
   665  // KubeletAddresses returns the host and the internalIP
   666  // If no internalIP is provided, IP will be be returned instead
   667  func (node Node) KubeletAddresses() []string {
   668  	addr := []string{node.Host}
   669  	if node.InternalIP != "" {
   670  		addr = append(addr, node.InternalIP)
   671  	} else {
   672  		addr = append(addr, node.IP)
   673  	}
   674  	return addr
   675  }
   676  
   677  type NFS struct {
   678  	// List of NFS volumes that should be attached to the cluster during
   679  	// the installation.
   680  	Volumes []NFSVolume `yaml:"nfs_volume"`
   681  }
   682  
   683  type NFSVolume struct {
   684  	// The hostname or IP of the NFS volume.
   685  	// +required
   686  	Host string `yaml:"nfs_host"`
   687  	// The path where the NFS volume should be mounted.
   688  	// +required
   689  	Path string `yaml:"mount_path"`
   690  }
   691  
   692  // StorageVolume managed by Kismatic
   693  type StorageVolume struct {
   694  	// Name of the storage volume
   695  	Name string
   696  	// SizeGB is the size of the volume, in gigabytes
   697  	SizeGB int
   698  	// ReplicateCount is the number of replicas
   699  	ReplicateCount int
   700  	// DistributionCount is the degree to which data will be distributed across the cluster
   701  	DistributionCount int
   702  	// StorageClass is the annotation that will be used when creating the persistent-volume in kubernetes
   703  	StorageClass string
   704  	// AllowAddresses is a list of address wildcards that have access to the volume
   705  	AllowAddresses []string
   706  	// ReclaimPolicy is the persistent volume's reclaim policy
   707  	// ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaim-policy
   708  	ReclaimPolicy string
   709  	// AccessModes supported by the persistent volume
   710  	// ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
   711  	AccessModes []string
   712  }
   713  
   714  type SSHConnection struct {
   715  	SSHConfig *SSHConfig
   716  	Node      *Node
   717  }
   718  
   719  // GetUniqueNodes returns a list of the unique nodes that are listed in the plan file.
   720  // That is, if a node has multiple roles, it will only appear once in the list.
   721  // Nodes are considered unique if the combination of 'host', 'IP' or 'internalIP' is unique to all other nodes.
   722  func (p *Plan) GetUniqueNodes() []Node {
   723  	seenNodes := map[string]bool{}
   724  	nodes := []Node{}
   725  	for _, node := range p.getAllNodes() {
   726  		// Cannot use the Node struct directly as it contains a map
   727  		key := node.HashCode()
   728  		if seenNodes[key] {
   729  			continue
   730  		}
   731  		nodes = append(nodes, node)
   732  		seenNodes[key] = true
   733  	}
   734  	return nodes
   735  }
   736  
   737  func (p *Plan) getAllNodes() []Node {
   738  	nodes := []Node{}
   739  	nodes = append(nodes, p.Etcd.Nodes...)
   740  	nodes = append(nodes, p.Master.Nodes...)
   741  	nodes = append(nodes, p.Worker.Nodes...)
   742  	if p.Ingress.Nodes != nil {
   743  		nodes = append(nodes, p.Ingress.Nodes...)
   744  	}
   745  	if p.Storage.Nodes != nil {
   746  		nodes = append(nodes, p.Storage.Nodes...)
   747  	}
   748  	return nodes
   749  }
   750  
   751  func (p *Plan) getNodeWithIP(ip string) (*Node, error) {
   752  	for _, n := range p.getAllNodes() {
   753  		if n.IP == ip {
   754  			return &n, nil
   755  		}
   756  	}
   757  	return nil, fmt.Errorf("Node with IP %q was not found in plan", ip)
   758  }
   759  
   760  // AllAddresses will return the hostnames, IPs and internal IPs for all nodes
   761  func (p *Plan) AllAddresses() []string {
   762  	nodes := p.GetUniqueNodes()
   763  	var addr []string
   764  	for _, n := range nodes {
   765  		addr = append(addr, n.Host)
   766  		addr = append(addr, n.IP)
   767  		if n.InternalIP != "" {
   768  			addr = append(addr, n.InternalIP)
   769  		}
   770  	}
   771  	return addr
   772  }
   773  
   774  func (p *Plan) ValidRole(role string) bool {
   775  	for _, r := range roles() {
   776  		if r == role {
   777  			return true
   778  		}
   779  	}
   780  	return false
   781  }
   782  
   783  func (p *Plan) HostExists(host string) bool {
   784  	for _, n := range p.GetUniqueNodes() {
   785  		if host == n.Host {
   786  			return true
   787  		}
   788  	}
   789  	return false
   790  }
   791  
   792  // GetSSHConnection returns the SSHConnection struct containing the node and SSHConfig details
   793  func (p *Plan) GetSSHConnection(host string) (*SSHConnection, error) {
   794  	nodes := p.getAllNodes()
   795  
   796  	var isIP bool
   797  	if ip := net.ParseIP(host); ip != nil {
   798  		isIP = true
   799  	}
   800  
   801  	// try to find the node with the provided hostname
   802  	var foundNode *Node
   803  	for _, node := range nodes {
   804  		nodeAddress := node.Host
   805  		if isIP {
   806  			nodeAddress = node.IP
   807  		}
   808  		if nodeAddress == host {
   809  			foundNode = &node
   810  			break
   811  		}
   812  	}
   813  
   814  	if foundNode == nil {
   815  		switch host {
   816  		case "master":
   817  			foundNode = firstIfItExists(p.Master.Nodes)
   818  		case "etcd":
   819  			foundNode = firstIfItExists(p.Etcd.Nodes)
   820  		case "worker":
   821  			foundNode = firstIfItExists(p.Worker.Nodes)
   822  		case "ingress":
   823  			foundNode = firstIfItExists(p.Ingress.Nodes)
   824  		case "storage":
   825  			foundNode = firstIfItExists(p.Storage.Nodes)
   826  		}
   827  	}
   828  
   829  	if foundNode == nil {
   830  		notFoundErr := fmt.Errorf("node %q not found in the plan", host)
   831  		if isIP {
   832  			notFoundErr = fmt.Errorf("node with IP %q not found in the plan", host)
   833  		}
   834  		return nil, notFoundErr
   835  	}
   836  
   837  	return &SSHConnection{&p.Cluster.SSH, foundNode}, nil
   838  }
   839  
   840  // GetSSHClient is a convience method that calls GetSSHConnection and returns an SSH client with the result
   841  func (p *Plan) GetSSHClient(host string) (ssh.Client, error) {
   842  	con, err := p.GetSSHConnection(host)
   843  	if err != nil {
   844  		return nil, err
   845  	}
   846  	client, err := ssh.NewClient(con.Node.IP, con.SSHConfig.Port, con.SSHConfig.User, con.SSHConfig.Key)
   847  	if err != nil {
   848  		return nil, fmt.Errorf("error creating SSH client for host %s: %v", host, err)
   849  	}
   850  
   851  	return client, nil
   852  }
   853  
   854  func firstIfItExists(nodes []Node) *Node {
   855  	if len(nodes) > 0 {
   856  		return &nodes[0]
   857  	}
   858  	return nil
   859  }
   860  
   861  func (p *Plan) GetRolesForIP(ip string) []string {
   862  	allRoles := []string{}
   863  
   864  	if hasIP(&p.Master.Nodes, ip) {
   865  		allRoles = append(allRoles, "master")
   866  	}
   867  
   868  	if hasIP(&p.Etcd.Nodes, ip) {
   869  		allRoles = append(allRoles, "etcd")
   870  	}
   871  
   872  	if hasIP(&p.Worker.Nodes, ip) {
   873  		allRoles = append(allRoles, "worker")
   874  	}
   875  
   876  	if hasIP(&p.Ingress.Nodes, ip) {
   877  		allRoles = append(allRoles, "ingress")
   878  	}
   879  
   880  	if hasIP(&p.Storage.Nodes, ip) {
   881  		allRoles = append(allRoles, "storage")
   882  	}
   883  
   884  	return allRoles
   885  }
   886  
   887  func hasIP(nodes *[]Node, ip string) bool {
   888  	for _, node := range *nodes {
   889  		if node.IP == ip {
   890  			return true
   891  		}
   892  	}
   893  	return false
   894  }
   895  
   896  // PrivateRegistryProvided returns true when the details about a private
   897  // registry have been provided
   898  func (p Plan) PrivateRegistryProvided() bool {
   899  	return p.DockerRegistry.Server != ""
   900  }
   901  
   902  // NetworkConfigured returns true if pod validation/smoketest should run
   903  func (p Plan) NetworkConfigured() bool {
   904  	// CNI disabled or "custom" return false
   905  	return p.AddOns.CNI == nil || (!p.AddOns.CNI.Disable && p.AddOns.CNI.Provider != "custom")
   906  }
   907  
   908  func (p Plan) Versions() map[string]string {
   909  	kubernetesVersion := kubernetesVersionString
   910  	if p.Cluster.Version != "" {
   911  		kubernetesVersion = p.Cluster.Version
   912  	}
   913  	versions := make(map[string]string)
   914  	versions["kube_proxy"] = kubernetesVersion
   915  	versions["kube_controller_manager"] = kubernetesVersion
   916  	versions["kube_scheduler"] = kubernetesVersion
   917  	versions["kube_apiserver"] = kubernetesVersion
   918  
   919  	return versions
   920  }
   921  
   922  // returns a list of specs for all the certs that are required for the node
   923  func (node Node) certSpecs(plan Plan, ca *tls.CA) ([]certificateSpec, error) {
   924  	m := []certificateSpec{}
   925  	roles := plan.GetRolesForIP(node.IP)
   926  
   927  	// Certificates for etcd
   928  	if contains("etcd", roles) {
   929  		san := []string{node.Host, node.IP, "127.0.0.1"}
   930  		if node.InternalIP != "" {
   931  			san = append(san, node.InternalIP)
   932  		}
   933  		m = append(m, certificateSpec{
   934  			description:           fmt.Sprintf("%s etcd server", node.Host),
   935  			filename:              fmt.Sprintf("%s-etcd", node.Host),
   936  			commonName:            node.Host,
   937  			subjectAlternateNames: san,
   938  			ca: ca,
   939  		})
   940  	}
   941  
   942  	// Certificates for master
   943  	if contains("master", roles) {
   944  		// API Server certificate
   945  		san, err := clusterCertsSubjectAlternateNames(plan)
   946  		if err != nil {
   947  			return nil, err
   948  		}
   949  		san = append(san, node.Host, node.IP, "127.0.0.1")
   950  		if node.InternalIP != "" {
   951  			san = append(san, node.InternalIP)
   952  		}
   953  		if !contains(plan.Master.LoadBalancedFQDN, san) {
   954  			san = append(san, plan.Master.LoadBalancedFQDN)
   955  		}
   956  		if !contains(plan.Master.LoadBalancedShortName, san) {
   957  			san = append(san, plan.Master.LoadBalancedShortName)
   958  		}
   959  		m = append(m, certificateSpec{
   960  			description:           fmt.Sprintf("%s API server", node.Host),
   961  			filename:              fmt.Sprintf("%s-apiserver", node.Host),
   962  			commonName:            node.Host,
   963  			subjectAlternateNames: san,
   964  			ca: ca,
   965  		})
   966  		// Controller manager certificate
   967  		m = append(m, certificateSpec{
   968  			description: "kubernetes controller manager",
   969  			filename:    controllerManagerCertFilenamePrefix,
   970  			commonName:  controllerManagerUser,
   971  			ca:          ca,
   972  		})
   973  		// Scheduler client certificate
   974  		m = append(m, certificateSpec{
   975  			description: "kubernetes scheduler",
   976  			filename:    schedulerCertFilenamePrefix,
   977  			commonName:  schedulerUser,
   978  			ca:          ca,
   979  		})
   980  		// Certificate for signing service account tokens
   981  		m = append(m, certificateSpec{
   982  			description: "service account signing",
   983  			filename:    serviceAccountCertFilename,
   984  			commonName:  serviceAccountCertCommonName,
   985  			ca:          ca,
   986  		})
   987  	}
   988  
   989  	// Kubelet and etcd client certificate
   990  	if containsAny([]string{"master", "worker", "ingress", "storage"}, roles) {
   991  		m = append(m, certificateSpec{
   992  			description:           fmt.Sprintf("%s kubelet", node.Host),
   993  			filename:              fmt.Sprintf("%s-kubelet", node.Host),
   994  			commonName:            fmt.Sprintf("%s:%s", kubeletUserPrefix, strings.ToLower(node.Host)),
   995  			subjectAlternateNames: node.KubeletAddresses(),
   996  			organizations:         []string{kubeletGroup},
   997  			ca:                    ca,
   998  		})
   999  
  1000  		// etcd client certificate
  1001  		// all nodes need to be able to talk to etcd b/c of calico
  1002  		m = append(m, certificateSpec{
  1003  			description: "etcd client",
  1004  			filename:    "etcd-client",
  1005  			commonName:  "etcd-client",
  1006  			ca:          ca,
  1007  		})
  1008  	}
  1009  
  1010  	return m, nil
  1011  }
  1012  
  1013  // returns a list of cert specs for the cluster described in the plan file
  1014  func (plan Plan) certSpecs(clusterCA *tls.CA, proxyClientCA *tls.CA) ([]certificateSpec, error) {
  1015  	m := []certificateSpec{}
  1016  
  1017  	// Certificate for nodes
  1018  	nodes := plan.GetUniqueNodes()
  1019  	for _, n := range nodes {
  1020  		nodeManifest, err := n.certSpecs(plan, clusterCA)
  1021  		if err != nil {
  1022  			return nil, err
  1023  		}
  1024  
  1025  		// Some nodes share common certificates between them. E.g. the kube-proxy client cert.
  1026  		// Before appending to the manifest, we ensure that this cert is not already in it.
  1027  		for _, s := range nodeManifest {
  1028  			if !certSpecInManifest(s, m) {
  1029  				m = append(m, s)
  1030  			}
  1031  		}
  1032  	}
  1033  
  1034  	// Kube APIServer Kubelet Client certificate
  1035  	m = append(m, certificateSpec{
  1036  		description:   "kube-apiserver kubelet client",
  1037  		filename:      kubeAPIServerKubeletClientClientFilename,
  1038  		commonName:    kubeAPIServerKubeletClientClientCommonName,
  1039  		organizations: []string{adminGroup},
  1040  		ca:            clusterCA,
  1041  	})
  1042  
  1043  	// Proxy Client certificate
  1044  	m = append(m, certificateSpec{
  1045  		description:   "proxy client",
  1046  		filename:      proxyClientCertFilename,
  1047  		commonName:    proxyClientCertCommonName,
  1048  		organizations: []string{adminGroup},
  1049  		ca:            proxyClientCA,
  1050  	})
  1051  
  1052  	// Contiv certificates
  1053  	if plan.AddOns.CNI.Provider == cniProviderContiv {
  1054  		m = append(m, certificateSpec{
  1055  			description: "contiv proxy server",
  1056  			filename:    contivProxyServerCertFilename,
  1057  			commonName:  "auth-local.cisco.com", // using the same as contiv install script
  1058  			ca:          clusterCA,
  1059  		})
  1060  	}
  1061  
  1062  	// Admin certificate
  1063  	m = append(m, certificateSpec{
  1064  		description:   "admin client",
  1065  		filename:      adminCertFilename,
  1066  		commonName:    adminUser,
  1067  		organizations: []string{adminGroup},
  1068  		ca:            clusterCA,
  1069  	})
  1070  
  1071  	return m, nil
  1072  }