| /* |
| Copyright 2014 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 cloudprovider |
| |
| import ( |
| "context" |
| "errors" |
| "fmt" |
| "strings" |
| |
| "k8s.io/api/core/v1" |
| "k8s.io/apimachinery/pkg/types" |
| "k8s.io/client-go/informers" |
| clientset "k8s.io/client-go/kubernetes" |
| restclient "k8s.io/client-go/rest" |
| ) |
| |
| // ControllerClientBuilder allows you to get clients and configs for controllers |
| // Please note a copy also exists in pkg/controller/client_builder.go |
| // TODO: Make this depend on the separate controller utilities repo (issues/68947) |
| type ControllerClientBuilder interface { |
| Config(name string) (*restclient.Config, error) |
| ConfigOrDie(name string) *restclient.Config |
| Client(name string) (clientset.Interface, error) |
| ClientOrDie(name string) clientset.Interface |
| } |
| |
| // Interface is an abstract, pluggable interface for cloud providers. |
| type Interface interface { |
| // Initialize provides the cloud with a kubernetes client builder and may spawn goroutines |
| // to perform housekeeping or run custom controllers specific to the cloud provider. |
| // Any tasks started here should be cleaned up when the stop channel closes. |
| Initialize(clientBuilder ControllerClientBuilder, stop <-chan struct{}) |
| // LoadBalancer returns a balancer interface. Also returns true if the interface is supported, false otherwise. |
| LoadBalancer() (LoadBalancer, bool) |
| // Instances returns an instances interface. Also returns true if the interface is supported, false otherwise. |
| Instances() (Instances, bool) |
| // Zones returns a zones interface. Also returns true if the interface is supported, false otherwise. |
| Zones() (Zones, bool) |
| // Clusters returns a clusters interface. Also returns true if the interface is supported, false otherwise. |
| Clusters() (Clusters, bool) |
| // Routes returns a routes interface along with whether the interface is supported. |
| Routes() (Routes, bool) |
| // ProviderName returns the cloud provider ID. |
| ProviderName() string |
| // HasClusterID returns true if a ClusterID is required and set |
| HasClusterID() bool |
| } |
| |
| type InformerUser interface { |
| // SetInformers sets the informer on the cloud object. |
| SetInformers(informerFactory informers.SharedInformerFactory) |
| } |
| |
| // Clusters is an abstract, pluggable interface for clusters of containers. |
| type Clusters interface { |
| // ListClusters lists the names of the available clusters. |
| ListClusters(ctx context.Context) ([]string, error) |
| // Master gets back the address (either DNS name or IP address) of the master node for the cluster. |
| Master(ctx context.Context, clusterName string) (string, error) |
| } |
| |
| // (DEPRECATED) DefaultLoadBalancerName is the default load balancer name that is called from |
| // LoadBalancer.GetLoadBalancerName. Use this method to maintain backward compatible names for |
| // LoadBalancers that were created prior to Kubernetes v1.12. In the future, each provider should |
| // replace this method call in GetLoadBalancerName with a provider-specific implementation that |
| // is less cryptic than the Service's UUID. |
| func DefaultLoadBalancerName(service *v1.Service) string { |
| //GCE requires that the name of a load balancer starts with a lower case letter. |
| ret := "a" + string(service.UID) |
| ret = strings.Replace(ret, "-", "", -1) |
| //AWS requires that the name of a load balancer is shorter than 32 bytes. |
| if len(ret) > 32 { |
| ret = ret[:32] |
| } |
| return ret |
| } |
| |
| // GetInstanceProviderID builds a ProviderID for a node in a cloud. |
| func GetInstanceProviderID(ctx context.Context, cloud Interface, nodeName types.NodeName) (string, error) { |
| instances, ok := cloud.Instances() |
| if !ok { |
| return "", fmt.Errorf("failed to get instances from cloud provider") |
| } |
| instanceID, err := instances.InstanceID(ctx, nodeName) |
| if err != nil { |
| return "", fmt.Errorf("failed to get instance ID from cloud provider: %v", err) |
| } |
| return cloud.ProviderName() + "://" + instanceID, nil |
| } |
| |
| // LoadBalancer is an abstract, pluggable interface for load balancers. |
| type LoadBalancer interface { |
| // TODO: Break this up into different interfaces (LB, etc) when we have more than one type of service |
| // GetLoadBalancer returns whether the specified load balancer exists, and |
| // if so, what its status is. |
| // Implementations must treat the *v1.Service parameter as read-only and not modify it. |
| // Parameter 'clusterName' is the name of the cluster as presented to kube-controller-manager |
| GetLoadBalancer(ctx context.Context, clusterName string, service *v1.Service) (status *v1.LoadBalancerStatus, exists bool, err error) |
| // GetLoadBalancerName returns the name of the load balancer. Implementations must treat the |
| // *v1.Service parameter as read-only and not modify it. |
| GetLoadBalancerName(ctx context.Context, clusterName string, service *v1.Service) string |
| // EnsureLoadBalancer creates a new load balancer 'name', or updates the existing one. Returns the status of the balancer |
| // Implementations must treat the *v1.Service and *v1.Node |
| // parameters as read-only and not modify them. |
| // Parameter 'clusterName' is the name of the cluster as presented to kube-controller-manager |
| EnsureLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) |
| // UpdateLoadBalancer updates hosts under the specified load balancer. |
| // Implementations must treat the *v1.Service and *v1.Node |
| // parameters as read-only and not modify them. |
| // Parameter 'clusterName' is the name of the cluster as presented to kube-controller-manager |
| UpdateLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) error |
| // EnsureLoadBalancerDeleted deletes the specified load balancer if it |
| // exists, returning nil if the load balancer specified either didn't exist or |
| // was successfully deleted. |
| // This construction is useful because many cloud providers' load balancers |
| // have multiple underlying components, meaning a Get could say that the LB |
| // doesn't exist even if some part of it is still laying around. |
| // Implementations must treat the *v1.Service parameter as read-only and not modify it. |
| // Parameter 'clusterName' is the name of the cluster as presented to kube-controller-manager |
| EnsureLoadBalancerDeleted(ctx context.Context, clusterName string, service *v1.Service) error |
| } |
| |
| // Instances is an abstract, pluggable interface for sets of instances. |
| type Instances interface { |
| // NodeAddresses returns the addresses of the specified instance. |
| // TODO(roberthbailey): This currently is only used in such a way that it |
| // returns the address of the calling instance. We should do a rename to |
| // make this clearer. |
| NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) |
| // NodeAddressesByProviderID returns the addresses of the specified instance. |
| // The instance is specified using the providerID of the node. The |
| // ProviderID is a unique identifier of the node. This will not be called |
| // from the node whose nodeaddresses are being queried. i.e. local metadata |
| // services cannot be used in this method to obtain nodeaddresses |
| NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) |
| // InstanceID returns the cloud provider ID of the node with the specified NodeName. |
| // Note that if the instance does not exist, we must return ("", cloudprovider.InstanceNotFound) |
| // cloudprovider.InstanceNotFound should NOT be returned for instances that exist but are stopped/sleeping |
| InstanceID(ctx context.Context, nodeName types.NodeName) (string, error) |
| // InstanceType returns the type of the specified instance. |
| InstanceType(ctx context.Context, name types.NodeName) (string, error) |
| // InstanceTypeByProviderID returns the type of the specified instance. |
| InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) |
| // AddSSHKeyToAllInstances adds an SSH public key as a legal identity for all instances |
| // expected format for the key is standard ssh-keygen format: <protocol> <blob> |
| AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error |
| // CurrentNodeName returns the name of the node we are currently running on |
| // On most clouds (e.g. GCE) this is the hostname, so we provide the hostname |
| CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) |
| // InstanceExistsByProviderID returns true if the instance for the given provider exists. |
| // If false is returned with no error, the instance will be immediately deleted by the cloud controller manager. |
| // This method should still return true for instances that exist but are stopped/sleeping. |
| InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) |
| // InstanceShutdownByProviderID returns true if the instance is shutdown in cloudprovider |
| InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) |
| } |
| |
| // Route is a representation of an advanced routing rule. |
| type Route struct { |
| // Name is the name of the routing rule in the cloud-provider. |
| // It will be ignored in a Create (although nameHint may influence it) |
| Name string |
| // TargetNode is the NodeName of the target instance. |
| TargetNode types.NodeName |
| // DestinationCIDR is the CIDR format IP range that this routing rule |
| // applies to. |
| DestinationCIDR string |
| // Blackhole is set to true if this is a blackhole route |
| // The node controller will delete the route if it is in the managed range. |
| Blackhole bool |
| } |
| |
| // Routes is an abstract, pluggable interface for advanced routing rules. |
| type Routes interface { |
| // ListRoutes lists all managed routes that belong to the specified clusterName |
| ListRoutes(ctx context.Context, clusterName string) ([]*Route, error) |
| // CreateRoute creates the described managed route |
| // route.Name will be ignored, although the cloud-provider may use nameHint |
| // to create a more user-meaningful name. |
| CreateRoute(ctx context.Context, clusterName string, nameHint string, route *Route) error |
| // DeleteRoute deletes the specified managed route |
| // Route should be as returned by ListRoutes |
| DeleteRoute(ctx context.Context, clusterName string, route *Route) error |
| } |
| |
| var ( |
| InstanceNotFound = errors.New("instance not found") |
| DiskNotFound = errors.New("disk is not found") |
| NotImplemented = errors.New("unimplemented") |
| ) |
| |
| // Zone represents the location of a particular machine. |
| type Zone struct { |
| FailureDomain string |
| Region string |
| } |
| |
| // Zones is an abstract, pluggable interface for zone enumeration. |
| type Zones interface { |
| // GetZone returns the Zone containing the current failure zone and locality region that the program is running in |
| // In most cases, this method is called from the kubelet querying a local metadata service to acquire its zone. |
| // For the case of external cloud providers, use GetZoneByProviderID or GetZoneByNodeName since GetZone |
| // can no longer be called from the kubelets. |
| GetZone(ctx context.Context) (Zone, error) |
| |
| // GetZoneByProviderID returns the Zone containing the current zone and locality region of the node specified by providerID |
| // This method is particularly used in the context of external cloud providers where node initialization must be done |
| // outside the kubelets. |
| GetZoneByProviderID(ctx context.Context, providerID string) (Zone, error) |
| |
| // GetZoneByNodeName returns the Zone containing the current zone and locality region of the node specified by node name |
| // This method is particularly used in the context of external cloud providers where node initialization must be done |
| // outside the kubelets. |
| GetZoneByNodeName(ctx context.Context, nodeName types.NodeName) (Zone, error) |
| } |
| |
| // PVLabeler is an abstract, pluggable interface for fetching labels for volumes |
| type PVLabeler interface { |
| GetLabelsForVolume(ctx context.Context, pv *v1.PersistentVolume) (map[string]string, error) |
| } |