Skip to content

Commit

Permalink
Implement InstanceExistsByProviderID() for cloud providers
Browse files Browse the repository at this point in the history
Fix kubernetes#51406
If cloud providers(like aws, gce etc...) implement ExternalID()
and support getting instance by ProviderID , they also implement
InstanceExistsByProviderID().
  • Loading branch information
FengyunPan2 committed Oct 20, 2017
1 parent 191ff80 commit 462087f
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 10 deletions.
28 changes: 27 additions & 1 deletion pkg/cloudprovider/providers/aws/aws.go
Expand Up @@ -1152,7 +1152,33 @@ func (c *Cloud) ExternalID(nodeName types.NodeName) (string, error) {
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (c *Cloud) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, cloudprovider.NotImplemented
instanceID, err := kubernetesInstanceID(providerID).mapToAWSInstanceID()
if err != nil {
return false, err
}

request := &ec2.DescribeInstancesInput{
InstanceIds: []*string{instanceID.awsString()},
}

instances, err := c.ec2.DescribeInstances(request)
if err != nil {
return false, err
}
if len(instances) == 0 {
return false, nil
}
if len(instances) > 1 {
return false, fmt.Errorf("multiple instances found for instance: %s", instanceID)
}

state := instances[0].State.Name
if *state != "running" {
glog.Warningf("the instance %s is not running", instanceID)
return false, nil
}

return true, nil
}

// InstanceID returns the cloud provider ID of the node with the specified nodeName.
Expand Down
15 changes: 14 additions & 1 deletion pkg/cloudprovider/providers/azure/azure_instances.go
Expand Up @@ -89,7 +89,20 @@ func (az *Cloud) ExternalID(name types.NodeName) (string, error) {
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (az *Cloud) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, cloudprovider.NotImplemented
name, err := splitProviderID(providerID)
if err != nil {
return false, err
}

_, err = az.InstanceID(name)
if err != nil {
if err == cloudprovider.InstanceNotFound {
return false, nil
}
return false, err
}

return true, nil
}

func (az *Cloud) isCurrentInstance(name types.NodeName) (bool, error) {
Expand Down
36 changes: 30 additions & 6 deletions pkg/cloudprovider/providers/gce/gce_instances.go
Expand Up @@ -116,19 +116,35 @@ func (gce *GCECloud) NodeAddressesByProviderID(providerID string) ([]v1.NodeAddr
return nodeAddresses, nil
}

// instanceByProviderID returns the cloudprovider instance of the node
// with the specified unique providerID
func (gce *GCECloud) instanceByProviderID(providerID string) (*gceInstance, error) {
project, zone, name, err := splitProviderID(providerID)
if err != nil {
return nil, err
}

instance, err := gce.getInstanceFromProjectInZoneByName(project, zone, name)
if err != nil {
if isHTTPErrorCode(err, http.StatusNotFound) {
return nil, cloudprovider.InstanceNotFound
}
return nil, err
}

return instance, nil
}

// InstanceTypeByProviderID returns the cloudprovider instance type of the node
// with the specified unique providerID This method will not be called from the
// node that is requesting this ID. i.e. metadata service and other local
// methods cannot be used here
func (gce *GCECloud) InstanceTypeByProviderID(providerID string) (string, error) {
project, zone, name, err := splitProviderID(providerID)
if err != nil {
return "", err
}
instance, err := gce.getInstanceFromProjectInZoneByName(project, zone, name)
instance, err := gce.instanceByProviderID(providerID)
if err != nil {
return "", err
}

return instance.Type, nil
}

Expand Down Expand Up @@ -156,7 +172,15 @@ func (gce *GCECloud) ExternalID(nodeName types.NodeName) (string, error) {
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (gce *GCECloud) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, cloudprovider.NotImplemented
_, err := gce.instanceByProviderID(providerID)
if err != nil {
if err == cloudprovider.InstanceNotFound {
return false, nil
}
return false, err
}

return true, nil
}

// InstanceID returns the cloud provider ID of the node with the specified NodeName.
Expand Down
20 changes: 19 additions & 1 deletion pkg/cloudprovider/providers/openstack/openstack_instances.go
Expand Up @@ -116,7 +116,25 @@ func (i *Instances) ExternalID(name types.NodeName) (string, error) {
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (i *Instances) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, cloudprovider.NotImplemented
instanceID, err := instanceIDFromProviderID(providerID)
if err != nil {
return false, err
}

server, err := servers.Get(i.compute, instanceID).Extract()
if err != nil {
if isNotFound(err) {
return false, nil
}
return false, err
}

if server.Status != "ACTIVE" {
glog.Warningf("the instance %s is not active", instanceID)
return false, nil
}

return true, nil
}

// InstanceID returns the kubelet's cloud provider ID.
Expand Down
30 changes: 29 additions & 1 deletion pkg/cloudprovider/providers/vsphere/vsphere.go
Expand Up @@ -380,7 +380,35 @@ func (vs *VSphere) ExternalID(nodeName k8stypes.NodeName) (string, error) {
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (vs *VSphere) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, cloudprovider.NotImplemented
vmName := path.Base(providerID)
nodeName := vmNameToNodeName(vmName)
// Create context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Ensure client is logged in and session is valid
err := vs.conn.Connect(ctx)
if err != nil {
return false, err
}
vm, err := vs.getVMByName(ctx, nodeName)
if err != nil {
if vclib.IsNotFound(err) {
return false, nil
}
glog.Errorf("Failed to get VM object for node: %q. err: +%v", nodeNameToVMName(nodeName), err)
return false, err
}

isActive, err := vm.IsActive(ctx)
if err != nil {
glog.Errorf("Failed to check whether node %q is active. err: %+v.", nodeNameToVMName(nodeName), err)
return false, err
}
if !isActive {
return false, nil
}

return true, nil
}

// InstanceID returns the cloud provider ID of the node with the specified Name.
Expand Down

0 comments on commit 462087f

Please sign in to comment.