From 462087fd74ab3f94a4a82955d07fd0ca6605f9ad Mon Sep 17 00:00:00 2001 From: FengyunPan Date: Fri, 20 Oct 2017 14:59:28 +0800 Subject: [PATCH] Implement InstanceExistsByProviderID() for cloud providers Fix #51406 If cloud providers(like aws, gce etc...) implement ExternalID() and support getting instance by ProviderID , they also implement InstanceExistsByProviderID(). --- pkg/cloudprovider/providers/aws/aws.go | 28 ++++++++++++++- .../providers/azure/azure_instances.go | 15 +++++++- .../providers/gce/gce_instances.go | 36 +++++++++++++++---- .../openstack/openstack_instances.go | 20 ++++++++++- .../providers/vsphere/vsphere.go | 30 +++++++++++++++- 5 files changed, 119 insertions(+), 10 deletions(-) diff --git a/pkg/cloudprovider/providers/aws/aws.go b/pkg/cloudprovider/providers/aws/aws.go index 65c360f7e0..94f4323a1b 100644 --- a/pkg/cloudprovider/providers/aws/aws.go +++ b/pkg/cloudprovider/providers/aws/aws.go @@ -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. diff --git a/pkg/cloudprovider/providers/azure/azure_instances.go b/pkg/cloudprovider/providers/azure/azure_instances.go index ea85388ca4..0af7eec292 100644 --- a/pkg/cloudprovider/providers/azure/azure_instances.go +++ b/pkg/cloudprovider/providers/azure/azure_instances.go @@ -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) { diff --git a/pkg/cloudprovider/providers/gce/gce_instances.go b/pkg/cloudprovider/providers/gce/gce_instances.go index f55b06d6c4..a0f872aee5 100644 --- a/pkg/cloudprovider/providers/gce/gce_instances.go +++ b/pkg/cloudprovider/providers/gce/gce_instances.go @@ -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 } @@ -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. diff --git a/pkg/cloudprovider/providers/openstack/openstack_instances.go b/pkg/cloudprovider/providers/openstack/openstack_instances.go index 68876de57f..3cf1733b32 100644 --- a/pkg/cloudprovider/providers/openstack/openstack_instances.go +++ b/pkg/cloudprovider/providers/openstack/openstack_instances.go @@ -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. diff --git a/pkg/cloudprovider/providers/vsphere/vsphere.go b/pkg/cloudprovider/providers/vsphere/vsphere.go index b896835779..575a8708d9 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere.go @@ -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.