mirror of https://github.com/kubernetes/kops.git
351 lines
13 KiB
Go
351 lines
13 KiB
Go
/*
|
|
Copyright 2016 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package kops
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
// +genclient=true
|
|
|
|
// Cluster is a specific cluster wrapper
|
|
type Cluster struct {
|
|
metav1.TypeMeta `json:",inline"`
|
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
|
|
|
Spec ClusterSpec `json:"spec,omitempty"`
|
|
}
|
|
|
|
// ClusterList is a list of clusters
|
|
type ClusterList struct {
|
|
metav1.TypeMeta `json:",inline"`
|
|
metav1.ListMeta `json:"metadata,omitempty"`
|
|
|
|
Items []Cluster `json:"items"`
|
|
}
|
|
|
|
// ClusterSpec defines the configuration for a cluster
|
|
type ClusterSpec struct {
|
|
// The Channel we are following
|
|
Channel string `json:"channel,omitempty"`
|
|
// ConfigBase is the path where we store configuration for the cluster
|
|
// This might be different that the location when the cluster spec itself is stored,
|
|
// both because this must be accessible to the cluster,
|
|
// and because it might be on a different cloud or storage system (etcd vs S3)
|
|
ConfigBase string `json:"configBase,omitempty"`
|
|
// The CloudProvider to use (aws or gce)
|
|
CloudProvider string `json:"cloudProvider,omitempty"`
|
|
// The version of kubernetes to install (optional, and can be a "spec" like stable)
|
|
KubernetesVersion string `json:"kubernetesVersion,omitempty"`
|
|
// Configuration of subnets we are targeting
|
|
Subnets []ClusterSubnetSpec `json:"subnets,omitempty"`
|
|
// Project is the cloud project we should use, required on GCE
|
|
Project string `json:"project,omitempty"`
|
|
// MasterPublicName is the external DNS name for the master nodes
|
|
MasterPublicName string `json:"masterPublicName,omitempty"`
|
|
// MasterInternalName is the internal DNS name for the master nodes
|
|
MasterInternalName string `json:"masterInternalName,omitempty"`
|
|
// The CIDR used for the AWS VPC / GCE Network, or otherwise allocated to k8s
|
|
// This is a real CIDR, not the internal k8s network
|
|
NetworkCIDR string `json:"networkCIDR,omitempty"`
|
|
// NetworkID is an identifier of a network, if we want to reuse/share an existing network (e.g. an AWS VPC)
|
|
NetworkID string `json:"networkID,omitempty"`
|
|
// Topology defines the type of network topology to use on the cluster - default public
|
|
// This is heavily weighted towards AWS for the time being, but should also be agnostic enough
|
|
// to port out to GCE later if needed
|
|
Topology *TopologySpec `json:"topology,omitempty"`
|
|
// SecretStore is the VFS path to where secrets are stored
|
|
SecretStore string `json:"secretStore,omitempty"`
|
|
// KeyStore is the VFS path to where SSL keys and certificates are stored
|
|
KeyStore string `json:"keyStore,omitempty"`
|
|
// ConfigStore is the VFS path to where the configuration (Cluster, InstanceGroups etc) is stored
|
|
ConfigStore string `json:"configStore,omitempty"`
|
|
|
|
// DNSZone is the DNS zone we should use when configuring DNS
|
|
// This is because some clouds let us define a managed zone foo.bar, and then have
|
|
// kubernetes.dev.foo.bar, without needing to define dev.foo.bar as a hosted zone.
|
|
// DNSZone will probably be a suffix of the MasterPublicName and MasterInternalName
|
|
// Note that DNSZone can either by the host name of the zone (containing dots),
|
|
// or can be an identifier for the zone.
|
|
DNSZone string `json:"dnsZone,omitempty"`
|
|
// ClusterDNSDomain is the suffix we use for internal DNS names (normally cluster.local)
|
|
ClusterDNSDomain string `json:"clusterDNSDomain,omitempty"`
|
|
// ServiceClusterIPRange is the CIDR, from the internal network, where we allocate IPs for services
|
|
ServiceClusterIPRange string `json:"serviceClusterIPRange,omitempty"`
|
|
// NonMasqueradeCIDR is the CIDR for the internal k8s network (on which pods & services live)
|
|
// It cannot overlap ServiceClusterIPRange
|
|
NonMasqueradeCIDR string `json:"nonMasqueradeCIDR,omitempty"`
|
|
// SSHAccess is a list of the CIDRs that can access SSH.
|
|
SSHAccess []string `json:"sshAccess,omitempty"`
|
|
// KubernetesAPIAccess is a list of the CIDRs that can access the Kubernetes API endpoint (master HTTPS)
|
|
KubernetesAPIAccess []string `json:"kubernetesApiAccess,omitempty"`
|
|
// IsolatesMasters determines whether we should lock down masters so that they are not on the pod network.
|
|
// true is the kube-up behaviour, but it is very surprising: it means that daemonsets only work on the master
|
|
// if they have hostNetwork=true.
|
|
// false is now the default, and it will:
|
|
// * give the master a normal PodCIDR
|
|
// * run kube-proxy on the master
|
|
// * enable debugging handlers on the master, so kubectl logs works
|
|
IsolateMasters *bool `json:"isolateMasters,omitempty"`
|
|
// UpdatePolicy determines the policy for applying upgrades automatically.
|
|
// Valid values:
|
|
// 'external' do not apply updates automatically - they are applied manually or by an external system
|
|
// missing: default policy (currently OS security upgrades that do not require a reboot)
|
|
UpdatePolicy *string `json:"updatePolicy,omitempty"`
|
|
// Additional policies to add for roles
|
|
AdditionalPolicies *map[string]string `json:"additionalPolicies,omitempty"`
|
|
// EtcdClusters stores the configuration for each cluster
|
|
EtcdClusters []*EtcdClusterSpec `json:"etcdClusters,omitempty"`
|
|
// Component configurations
|
|
Docker *DockerConfig `json:"docker,omitempty"`
|
|
KubeDNS *KubeDNSConfig `json:"kubeDNS,omitempty"`
|
|
KubeAPIServer *KubeAPIServerConfig `json:"kubeAPIServer,omitempty"`
|
|
KubeControllerManager *KubeControllerManagerConfig `json:"kubeControllerManager,omitempty"`
|
|
KubeScheduler *KubeSchedulerConfig `json:"kubeScheduler,omitempty"`
|
|
KubeProxy *KubeProxyConfig `json:"kubeProxy,omitempty"`
|
|
Kubelet *KubeletConfigSpec `json:"kubelet,omitempty"`
|
|
MasterKubelet *KubeletConfigSpec `json:"masterKubelet,omitempty"`
|
|
CloudConfig *CloudConfiguration `json:"cloudConfig,omitempty"`
|
|
|
|
// Networking configuration
|
|
Networking *NetworkingSpec `json:"networking,omitempty"`
|
|
|
|
// API field controls how the API is exposed outside the cluster
|
|
API *AccessSpec `json:"api,omitempty"`
|
|
// Authentication field controls how the cluster is configured for authentication
|
|
Authentication *AuthenticationSpec `json:"authentication,omitempty"`
|
|
// Authorization field controls how the cluster is configured for authorization
|
|
Authorization *AuthorizationSpec `json:"authorization,omitempty"`
|
|
// Tags for AWS instance groups
|
|
CloudLabels map[string]string `json:"cloudLabels,omitempty"`
|
|
// Hooks for custom actions e.g. on first installation
|
|
Hooks []HookSpec `json:"hooks,omitempty"`
|
|
// Alternative locations for files and containers
|
|
// This API component is under contruction, will remove this comment
|
|
// once this API is fully functional.
|
|
Assets *Assets `json:"assets,omitempty"`
|
|
}
|
|
|
|
type Assets struct {
|
|
ContainerRegistry *string `json:"containerRegistry,omitempty"`
|
|
FileRepository *string `json:"fileRepository,omitempty"`
|
|
}
|
|
|
|
type HookSpec struct {
|
|
ExecContainer *ExecContainerAction `json:"execContainer,omitempty"`
|
|
}
|
|
|
|
type ExecContainerAction struct {
|
|
// Docker image name.
|
|
Image string `json:"image,omitempty" `
|
|
|
|
Command []string `json:"command,omitempty"`
|
|
}
|
|
|
|
type AuthenticationSpec struct {
|
|
Kopeio *KopeioAuthenticationSpec `json:"kopeio,omitempty"`
|
|
}
|
|
|
|
func (s *AuthenticationSpec) IsEmpty() bool {
|
|
return s.Kopeio == nil
|
|
}
|
|
|
|
type KopeioAuthenticationSpec struct {
|
|
}
|
|
|
|
type AuthorizationSpec struct {
|
|
AlwaysAllow *AlwaysAllowAuthorizationSpec `json:"alwaysAllow,omitempty"`
|
|
RBAC *RBACAuthorizationSpec `json:"rbac,omitempty"`
|
|
}
|
|
|
|
func (s *AuthorizationSpec) IsEmpty() bool {
|
|
return s.RBAC == nil && s.AlwaysAllow == nil
|
|
}
|
|
|
|
type RBACAuthorizationSpec struct {
|
|
}
|
|
|
|
type AlwaysAllowAuthorizationSpec struct {
|
|
}
|
|
|
|
type AccessSpec struct {
|
|
DNS *DNSAccessSpec `json:"dns,omitempty"`
|
|
LoadBalancer *LoadBalancerAccessSpec `json:"loadBalancer,omitempty"`
|
|
}
|
|
|
|
func (s *AccessSpec) IsEmpty() bool {
|
|
return s.DNS == nil && s.LoadBalancer == nil
|
|
}
|
|
|
|
type DNSAccessSpec struct {
|
|
}
|
|
|
|
// LoadBalancerType string describes LoadBalancer types (public, internal)
|
|
type LoadBalancerType string
|
|
|
|
const (
|
|
LoadBalancerTypePublic LoadBalancerType = "Public"
|
|
LoadBalancerTypeInternal LoadBalancerType = "Internal"
|
|
)
|
|
|
|
type LoadBalancerAccessSpec struct {
|
|
Type LoadBalancerType `json:"type,omitempty"`
|
|
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
|
|
}
|
|
|
|
// KubeDNSConfig defines the kube dns configuration
|
|
type KubeDNSConfig struct {
|
|
// Image is the name of the docker image to run
|
|
Image string `json:"image,omitempty"`
|
|
// Replicas is the number of pod replicas
|
|
Replicas int `json:"replicas,omitempty"`
|
|
// Domain is the dns domain
|
|
Domain string `json:"domain,omitempty"`
|
|
// ServerIP is the server ip
|
|
ServerIP string `json:"serverIP,omitempty"`
|
|
}
|
|
|
|
// EtcdStorageType defined the etcd storage backend
|
|
type EtcdStorageType string
|
|
|
|
const (
|
|
// EtcdStorageTypeV2 is the old v2 storage
|
|
EtcdStorageTypeV2 EtcdStorageType = "etcd2"
|
|
// EtcdStorageTypeV3 is the new v3 storage
|
|
EtcdStorageTypeV3 EtcdStorageType = "etcd3"
|
|
)
|
|
|
|
// EtcdClusterSpec is the etcd cluster specification
|
|
type EtcdClusterSpec struct {
|
|
// Name is the name of the etcd cluster (main, events etc)
|
|
Name string `json:"name,omitempty"`
|
|
// EnableEtcdTLS indicates the etcd service should use TLS between peers and clients
|
|
EnableEtcdTLS bool `json:"enableEtcdTLS,omitempty"`
|
|
// Members stores the configurations for each member of the cluster (including the data volume)
|
|
Members []*EtcdMemberSpec `json:"etcdMembers,omitempty"`
|
|
}
|
|
|
|
// EtcdMemberSpec is a specification for a etcd member
|
|
type EtcdMemberSpec struct {
|
|
// Name is the name of the member within the etcd cluster
|
|
Name string `json:"name,omitempty"`
|
|
// InstanceGroup is the instanceGroup this volume is associated
|
|
InstanceGroup *string `json:"instanceGroup,omitempty"`
|
|
// VolumeType is the underlining cloud storage class
|
|
VolumeType *string `json:"volumeType,omitempty"`
|
|
// VolumeSize is the underlining cloud volume size
|
|
VolumeSize *int32 `json:"volumeSize,omitempty"`
|
|
// KmsKeyId is a AWS KMS ID used to encrypt the volume
|
|
KmsKeyId *string `json:"kmsKeyId,omitempty"`
|
|
// EncryptedVolume indicates you want to encrypt the volume
|
|
EncryptedVolume *bool `json:"encryptedVolume,omitempty"`
|
|
}
|
|
|
|
// SubnetType string describes subnet types (public, private, utility)
|
|
type SubnetType string
|
|
|
|
const (
|
|
// SubnetTypePublic means the subnet is public
|
|
SubnetTypePublic SubnetType = "Public"
|
|
// SubnetTypePrivate means the subnet has no public address or is natted
|
|
SubnetTypePrivate SubnetType = "Private"
|
|
// SubnetTypeUtility mean the subnet is used for utility services, such as the bastion
|
|
SubnetTypeUtility SubnetType = "Utility"
|
|
)
|
|
|
|
// ClusterSubnetSpec defines a subnet
|
|
type ClusterSubnetSpec struct {
|
|
// Name is the name of the subnet
|
|
Name string `json:"name,omitempty"`
|
|
// CIDR is the network cidr of the subnet
|
|
CIDR string `json:"cidr,omitempty"`
|
|
// Zone is the zone the subnet resides
|
|
Zone string `json:"zone,omitempty"`
|
|
// ProviderID is the cloud provider id for the objects associated with the zone (the subnet on AWS)
|
|
ProviderID string `json:"id,omitempty"`
|
|
// Egress
|
|
Egress string `json:"egress,omitempty"`
|
|
// Type define which one if the internal types (public, utility, private) the network is
|
|
Type SubnetType `json:"type,omitempty"`
|
|
}
|
|
|
|
// FillDefaults populates default values.
|
|
// This is different from PerformAssignments, because these values are changeable, and thus we don't need to
|
|
// store them (i.e. we don't need to 'lock them')
|
|
func (c *Cluster) FillDefaults() error {
|
|
// Topology support
|
|
if c.Spec.Topology == nil {
|
|
c.Spec.Topology = &TopologySpec{Masters: TopologyPublic, Nodes: TopologyPublic}
|
|
c.Spec.Topology.DNS = &DNSSpec{Type: DNSTypePublic}
|
|
}
|
|
|
|
if c.Spec.Networking == nil {
|
|
c.Spec.Networking = &NetworkingSpec{}
|
|
}
|
|
|
|
// TODO move this into networking.go :(
|
|
if c.Spec.Networking.Classic != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.Kubenet != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.CNI != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.External != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.Kopeio != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.Weave != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.Flannel != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.Calico != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.Canal != nil {
|
|
// OK
|
|
} else if c.Spec.Networking.Kuberouter != nil {
|
|
// OK
|
|
} else {
|
|
// No networking model selected; choose Kubenet
|
|
c.Spec.Networking.Kubenet = &KubenetNetworkingSpec{}
|
|
}
|
|
|
|
if c.Spec.Channel == "" {
|
|
c.Spec.Channel = DefaultChannel
|
|
}
|
|
|
|
if c.ObjectMeta.Name == "" {
|
|
return fmt.Errorf("cluster Name not set in FillDefaults")
|
|
}
|
|
|
|
if c.Spec.MasterInternalName == "" {
|
|
c.Spec.MasterInternalName = "api.internal." + c.ObjectMeta.Name
|
|
}
|
|
|
|
if c.Spec.MasterPublicName == "" {
|
|
c.Spec.MasterPublicName = "api." + c.ObjectMeta.Name
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SharedVPC is a simple helper function which makes the templates for a shared VPC clearer
|
|
func (c *Cluster) SharedVPC() bool {
|
|
return c.Spec.NetworkID != ""
|
|
}
|