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 }