From a450da4fd02967362d953d5b048a393d5d5cf141 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Wed, 11 Feb 2015 17:37:27 -0500 Subject: [PATCH] cloudprovider: add instance id to NodeSpec Sometimes for external applications it is important to identify the cloud instance of the nodes. Until this patch there was no contract that the node name returned by List was also the unique identifier of the cloud instance. This new API ensures that an external application can reliably retrieve the relevant instance id of the nodes. Signed-off-by: Federico Simoncelli --- pkg/api/types.go | 2 ++ pkg/api/v1beta1/conversion.go | 2 ++ pkg/api/v1beta1/types.go | 2 ++ pkg/api/v1beta2/conversion.go | 2 ++ pkg/api/v1beta2/types.go | 2 ++ pkg/api/v1beta3/types.go | 2 ++ pkg/cloudprovider/aws/aws.go | 5 +++++ pkg/cloudprovider/cloud.go | 2 ++ pkg/cloudprovider/controller/nodecontroller.go | 6 ++++++ pkg/cloudprovider/fake/fake.go | 8 ++++++++ pkg/cloudprovider/gce/gce.go | 5 +++++ pkg/cloudprovider/openstack/openstack.go | 5 +++++ pkg/cloudprovider/ovirt/ovirt.go | 5 +++++ pkg/cloudprovider/rackspace/rackspace.go | 5 +++++ pkg/cloudprovider/vagrant/vagrant.go | 5 +++++ 15 files changed, 58 insertions(+) diff --git a/pkg/api/types.go b/pkg/api/types.go index 28acced55c2..f898afdbf63 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -781,6 +781,8 @@ type NodeSpec struct { // PodCIDR represents the pod IP range assigned to the node // Note: assigning IP ranges to nodes might need to be revisited when we support migratable IPs. PodCIDR string `json:"cidr,omitempty"` + // External ID of the node assigned by some machine database (e.g. a cloud provider) + ExternalID string `json:"externalID,omitempty"` } // NodeStatus is information about the current status of a node. diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index 7126d61ee9b..b1496605ba4 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -699,6 +699,7 @@ func init() { out.HostIP = in.Status.HostIP out.PodCIDR = in.Spec.PodCIDR + out.ExternalID = in.Spec.ExternalID return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0) }, func(in *Minion, out *newer.Node, s conversion.Scope) error { @@ -720,6 +721,7 @@ func init() { out.Status.HostIP = in.HostIP out.Spec.PodCIDR = in.PodCIDR + out.Spec.ExternalID = in.ExternalID return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0) }, func(in *newer.LimitRange, out *LimitRange, s conversion.Scope) error { diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index 9e2bd555a68..9354847994a 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -690,6 +690,8 @@ type Minion struct { Status NodeStatus `json:"status,omitempty" description:"current status of node"` // Labels for the node Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize minions; labels of a minion assigned by the scheduler must match the scheduled pod's nodeSelector"` + // External ID of the node + ExternalID string `json:"externalID,omitempty" description:"external id of the node assigned by some machine database (e.g. a cloud provider)"` } // MinionList is a list of minions. diff --git a/pkg/api/v1beta2/conversion.go b/pkg/api/v1beta2/conversion.go index c1c5e7603b8..a0ac51de0d0 100644 --- a/pkg/api/v1beta2/conversion.go +++ b/pkg/api/v1beta2/conversion.go @@ -619,6 +619,7 @@ func init() { out.HostIP = in.Status.HostIP out.PodCIDR = in.Spec.PodCIDR + out.ExternalID = in.Spec.ExternalID return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0) }, func(in *Minion, out *newer.Node, s conversion.Scope) error { @@ -640,6 +641,7 @@ func init() { out.Status.HostIP = in.HostIP out.Spec.PodCIDR = in.PodCIDR + out.Spec.ExternalID = in.ExternalID return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0) }, func(in *newer.LimitRange, out *LimitRange, s conversion.Scope) error { diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index 6787cc6c32e..8d51040071b 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -654,6 +654,8 @@ type Minion struct { Status NodeStatus `json:"status,omitempty" description:"current status of node"` // Labels for the node Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize minions; labels of a minion assigned by the scheduler must match the scheduled pod's nodeSelector"` + // External ID of the node + ExternalID string `json:"externalID,omitempty" description:"external id of the node assigned by some machine database (e.g. a cloud provider)"` } // MinionList is a list of minions. diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index 2258946e6ba..e10c45e058e 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -814,6 +814,8 @@ type NodeSpec struct { Capacity ResourceList `json:"capacity,omitempty"` // PodCIDR represents the pod IP range assigned to the node PodCIDR string `json:"cidr,omitempty"` + // External ID of the node assigned by some machine database (e.g. a cloud provider) + ExternalID string `json:"externalID,omitempty"` } // NodeStatus is information about the current status of a node. diff --git a/pkg/cloudprovider/aws/aws.go b/pkg/cloudprovider/aws/aws.go index fda91ee960e..497d16b8802 100644 --- a/pkg/cloudprovider/aws/aws.go +++ b/pkg/cloudprovider/aws/aws.go @@ -150,6 +150,11 @@ func (aws *AWSCloud) IPAddress(name string) (net.IP, error) { return ip, nil } +// ExternalID returns the cloud provider ID of the specified instance. +func (aws *AWSCloud) ExternalID(name string) (string, error) { + return "", fmt.Errorf("unimplemented") +} + // Return a list of instances matching regex string. func (aws *AWSCloud) getInstancesByRegex(regex string) ([]string, error) { resp, err := aws.ec2.Instances(nil, nil) diff --git a/pkg/cloudprovider/cloud.go b/pkg/cloudprovider/cloud.go index 5ba83617940..7960c00c57e 100644 --- a/pkg/cloudprovider/cloud.go +++ b/pkg/cloudprovider/cloud.go @@ -59,6 +59,8 @@ type TCPLoadBalancer interface { type Instances interface { // IPAddress returns an IP address of the specified instance. IPAddress(name string) (net.IP, error) + // ExternalID returns the cloud provider ID of the specified instance. + ExternalID(name string) (string, error) // List lists instances that match 'filter' which is a regular expression which must match the entire instance name (fqdn) List(filter string) ([]string, error) // GetNodeResources gets the resources for a particular node diff --git a/pkg/cloudprovider/controller/nodecontroller.go b/pkg/cloudprovider/controller/nodecontroller.go index 180016ee44f..6771a3ee15d 100644 --- a/pkg/cloudprovider/controller/nodecontroller.go +++ b/pkg/cloudprovider/controller/nodecontroller.go @@ -231,6 +231,12 @@ func (s *NodeController) PopulateIPs(nodes *api.NodeList) (*api.NodeList, error) } else { node.Status.HostIP = hostIP.String() } + instanceID, err := instances.ExternalID(node.Name) + if err != nil { + glog.Errorf("error getting instance id for %s: %v", node.Name, err) + } else { + node.Spec.ExternalID = instanceID + } } } else { for i := range nodes.Items { diff --git a/pkg/cloudprovider/fake/fake.go b/pkg/cloudprovider/fake/fake.go index 4efc6d82d78..b4bf3b37c9c 100644 --- a/pkg/cloudprovider/fake/fake.go +++ b/pkg/cloudprovider/fake/fake.go @@ -30,6 +30,7 @@ type FakeCloud struct { Err error Calls []string IP net.IP + ExtID string Machines []string NodeResources *api.NodeResources ClusterList []string @@ -110,6 +111,13 @@ func (f *FakeCloud) IPAddress(instance string) (net.IP, error) { return f.IP, f.Err } +// ExternalID is a test-spy implementation of Instances.ExternalID. +// It adds an entry "external-id" into the internal method call record. +func (f *FakeCloud) ExternalID(instance string) (string, error) { + f.addCall("external-id") + return f.ExtID, f.Err +} + // List is a test-spy implementation of Instances.List. // It adds an entry "list" into the internal method call record. func (f *FakeCloud) List(filter string) ([]string, error) { diff --git a/pkg/cloudprovider/gce/gce.go b/pkg/cloudprovider/gce/gce.go index 529c810643e..9c36ed0b129 100644 --- a/pkg/cloudprovider/gce/gce.go +++ b/pkg/cloudprovider/gce/gce.go @@ -294,6 +294,11 @@ func (gce *GCECloud) IPAddress(instance string) (net.IP, error) { return ip, nil } +// ExternalID returns the cloud provider ID of the specified instance. +func (gce *GCECloud) ExternalID(instance string) (string, error) { + return "", fmt.Errorf("unimplemented") +} + // fqdnSuffix is hacky function to compute the delta between hostame and hostname -f. func fqdnSuffix() (string, error) { fullHostname, err := exec.Command("hostname", "-f").Output() diff --git a/pkg/cloudprovider/openstack/openstack.go b/pkg/cloudprovider/openstack/openstack.go index 4e5947d6cca..3d93c7a06da 100644 --- a/pkg/cloudprovider/openstack/openstack.go +++ b/pkg/cloudprovider/openstack/openstack.go @@ -312,6 +312,11 @@ func (i *Instances) IPAddress(name string) (net.IP, error) { return net.ParseIP(ip), err } +// ExternalID returns the cloud provider ID of the specified instance. +func (i *Instances) ExternalID(name string) (string, error) { + return "", fmt.Errorf("unimplemented") +} + func (i *Instances) GetNodeResources(name string) (*api.NodeResources, error) { glog.V(2).Infof("GetNodeResources(%v) called", name) diff --git a/pkg/cloudprovider/ovirt/ovirt.go b/pkg/cloudprovider/ovirt/ovirt.go index 1b3e959f2f7..ddb3292dfdf 100644 --- a/pkg/cloudprovider/ovirt/ovirt.go +++ b/pkg/cloudprovider/ovirt/ovirt.go @@ -153,6 +153,11 @@ func (v *OVirtCloud) IPAddress(name string) (net.IP, error) { return address, nil } +// ExternalID returns the cloud provider ID of the specified instance. +func (v *OVirtCloud) ExternalID(name string) (string, error) { + return "", fmt.Errorf("unimplemented") +} + func getInstancesFromXml(body io.Reader) (OVirtInstanceMap, error) { if body == nil { return nil, fmt.Errorf("ovirt rest-api response body is missing") diff --git a/pkg/cloudprovider/rackspace/rackspace.go b/pkg/cloudprovider/rackspace/rackspace.go index 5ab564c9ee2..95d3ad67e02 100644 --- a/pkg/cloudprovider/rackspace/rackspace.go +++ b/pkg/cloudprovider/rackspace/rackspace.go @@ -363,6 +363,11 @@ func (i *Instances) IPAddress(name string) (net.IP, error) { return net.ParseIP(ip), err } +// ExternalID returns the cloud provider ID of the specified instance. +func (i *Instances) ExternalID(name string) (string, error) { + return "", fmt.Errorf("unimplemented") +} + func (i *Instances) GetNodeResources(name string) (*api.NodeResources, error) { glog.V(2).Infof("GetNodeResources(%v) called", name) diff --git a/pkg/cloudprovider/vagrant/vagrant.go b/pkg/cloudprovider/vagrant/vagrant.go index 3a7c6b4c179..ea0cf81e533 100644 --- a/pkg/cloudprovider/vagrant/vagrant.go +++ b/pkg/cloudprovider/vagrant/vagrant.go @@ -119,6 +119,11 @@ func (v *VagrantCloud) IPAddress(instance string) (net.IP, error) { return nil, fmt.Errorf("unable to find IP address for instance: %s", instance) } +// ExternalID returns the cloud provider ID of the specified instance. +func (v *VagrantCloud) ExternalID(instance string) (string, error) { + return "", fmt.Errorf("unimplemented") +} + // saltMinionsByRole filters a list of minions that have a matching role. func (v *VagrantCloud) saltMinionsByRole(minions []SaltMinion, role string) []SaltMinion { var filteredMinions []SaltMinion