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 <fsimonce@redhat.com>
This commit is contained in:
Federico Simoncelli 2015-02-11 17:37:27 -05:00
parent 8844c06574
commit a450da4fd0
15 changed files with 58 additions and 0 deletions

View File

@ -781,6 +781,8 @@ type NodeSpec struct {
// PodCIDR represents the pod IP range assigned to the node // 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. // Note: assigning IP ranges to nodes might need to be revisited when we support migratable IPs.
PodCIDR string `json:"cidr,omitempty"` 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. // NodeStatus is information about the current status of a node.

View File

@ -699,6 +699,7 @@ func init() {
out.HostIP = in.Status.HostIP out.HostIP = in.Status.HostIP
out.PodCIDR = in.Spec.PodCIDR out.PodCIDR = in.Spec.PodCIDR
out.ExternalID = in.Spec.ExternalID
return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0) return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0)
}, },
func(in *Minion, out *newer.Node, s conversion.Scope) error { func(in *Minion, out *newer.Node, s conversion.Scope) error {
@ -720,6 +721,7 @@ func init() {
out.Status.HostIP = in.HostIP out.Status.HostIP = in.HostIP
out.Spec.PodCIDR = in.PodCIDR out.Spec.PodCIDR = in.PodCIDR
out.Spec.ExternalID = in.ExternalID
return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0) return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0)
}, },
func(in *newer.LimitRange, out *LimitRange, s conversion.Scope) error { func(in *newer.LimitRange, out *LimitRange, s conversion.Scope) error {

View File

@ -690,6 +690,8 @@ type Minion struct {
Status NodeStatus `json:"status,omitempty" description:"current status of node"` Status NodeStatus `json:"status,omitempty" description:"current status of node"`
// Labels for the 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"` 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. // MinionList is a list of minions.

View File

@ -619,6 +619,7 @@ func init() {
out.HostIP = in.Status.HostIP out.HostIP = in.Status.HostIP
out.PodCIDR = in.Spec.PodCIDR out.PodCIDR = in.Spec.PodCIDR
out.ExternalID = in.Spec.ExternalID
return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0) return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0)
}, },
func(in *Minion, out *newer.Node, s conversion.Scope) error { func(in *Minion, out *newer.Node, s conversion.Scope) error {
@ -640,6 +641,7 @@ func init() {
out.Status.HostIP = in.HostIP out.Status.HostIP = in.HostIP
out.Spec.PodCIDR = in.PodCIDR out.Spec.PodCIDR = in.PodCIDR
out.Spec.ExternalID = in.ExternalID
return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0) return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0)
}, },
func(in *newer.LimitRange, out *LimitRange, s conversion.Scope) error { func(in *newer.LimitRange, out *LimitRange, s conversion.Scope) error {

View File

@ -654,6 +654,8 @@ type Minion struct {
Status NodeStatus `json:"status,omitempty" description:"current status of node"` Status NodeStatus `json:"status,omitempty" description:"current status of node"`
// Labels for the 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"` 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. // MinionList is a list of minions.

View File

@ -814,6 +814,8 @@ type NodeSpec struct {
Capacity ResourceList `json:"capacity,omitempty"` Capacity ResourceList `json:"capacity,omitempty"`
// PodCIDR represents the pod IP range assigned to the node // PodCIDR represents the pod IP range assigned to the node
PodCIDR string `json:"cidr,omitempty"` 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. // NodeStatus is information about the current status of a node.

View File

@ -150,6 +150,11 @@ func (aws *AWSCloud) IPAddress(name string) (net.IP, error) {
return ip, nil 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. // Return a list of instances matching regex string.
func (aws *AWSCloud) getInstancesByRegex(regex string) ([]string, error) { func (aws *AWSCloud) getInstancesByRegex(regex string) ([]string, error) {
resp, err := aws.ec2.Instances(nil, nil) resp, err := aws.ec2.Instances(nil, nil)

View File

@ -59,6 +59,8 @@ type TCPLoadBalancer interface {
type Instances interface { type Instances interface {
// IPAddress returns an IP address of the specified instance. // IPAddress returns an IP address of the specified instance.
IPAddress(name string) (net.IP, error) 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 lists instances that match 'filter' which is a regular expression which must match the entire instance name (fqdn)
List(filter string) ([]string, error) List(filter string) ([]string, error)
// GetNodeResources gets the resources for a particular node // GetNodeResources gets the resources for a particular node

View File

@ -231,6 +231,12 @@ func (s *NodeController) PopulateIPs(nodes *api.NodeList) (*api.NodeList, error)
} else { } else {
node.Status.HostIP = hostIP.String() 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 { } else {
for i := range nodes.Items { for i := range nodes.Items {

View File

@ -30,6 +30,7 @@ type FakeCloud struct {
Err error Err error
Calls []string Calls []string
IP net.IP IP net.IP
ExtID string
Machines []string Machines []string
NodeResources *api.NodeResources NodeResources *api.NodeResources
ClusterList []string ClusterList []string
@ -110,6 +111,13 @@ func (f *FakeCloud) IPAddress(instance string) (net.IP, error) {
return f.IP, f.Err 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. // List is a test-spy implementation of Instances.List.
// It adds an entry "list" into the internal method call record. // It adds an entry "list" into the internal method call record.
func (f *FakeCloud) List(filter string) ([]string, error) { func (f *FakeCloud) List(filter string) ([]string, error) {

View File

@ -294,6 +294,11 @@ func (gce *GCECloud) IPAddress(instance string) (net.IP, error) {
return ip, nil 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. // fqdnSuffix is hacky function to compute the delta between hostame and hostname -f.
func fqdnSuffix() (string, error) { func fqdnSuffix() (string, error) {
fullHostname, err := exec.Command("hostname", "-f").Output() fullHostname, err := exec.Command("hostname", "-f").Output()

View File

@ -312,6 +312,11 @@ func (i *Instances) IPAddress(name string) (net.IP, error) {
return net.ParseIP(ip), err 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) { func (i *Instances) GetNodeResources(name string) (*api.NodeResources, error) {
glog.V(2).Infof("GetNodeResources(%v) called", name) glog.V(2).Infof("GetNodeResources(%v) called", name)

View File

@ -153,6 +153,11 @@ func (v *OVirtCloud) IPAddress(name string) (net.IP, error) {
return address, nil 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) { func getInstancesFromXml(body io.Reader) (OVirtInstanceMap, error) {
if body == nil { if body == nil {
return nil, fmt.Errorf("ovirt rest-api response body is missing") return nil, fmt.Errorf("ovirt rest-api response body is missing")

View File

@ -363,6 +363,11 @@ func (i *Instances) IPAddress(name string) (net.IP, error) {
return net.ParseIP(ip), err 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) { func (i *Instances) GetNodeResources(name string) (*api.NodeResources, error) {
glog.V(2).Infof("GetNodeResources(%v) called", name) glog.V(2).Infof("GetNodeResources(%v) called", name)

View File

@ -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) 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. // saltMinionsByRole filters a list of minions that have a matching role.
func (v *VagrantCloud) saltMinionsByRole(minions []SaltMinion, role string) []SaltMinion { func (v *VagrantCloud) saltMinionsByRole(minions []SaltMinion, role string) []SaltMinion {
var filteredMinions []SaltMinion var filteredMinions []SaltMinion