Implement providerID node functions for gce
*Add splitProviderID helper function *Add getInstanceFromProjectInZoneByName function *Implement gce InstanceTypeByProviderID *Implement gce NodeAddressesByProviderID
This commit is contained in:
		@@ -17,7 +17,6 @@ limitations under the License.
 | 
			
		||||
package gce
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
@@ -62,7 +61,27 @@ func (gce *GCECloud) NodeAddresses(_ types.NodeName) ([]v1.NodeAddress, error) {
 | 
			
		||||
// 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) NodeAddressesByProviderID(providerID string) ([]v1.NodeAddress, error) {
 | 
			
		||||
	return []v1.NodeAddress{}, errors.New("unimplemented")
 | 
			
		||||
	project, zone, name, err := splitProviderID(providerID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return []v1.NodeAddress{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	instance, err := gce.service.Instances.Get(project, zone, canonicalizeInstanceName(name)).Do()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return []v1.NodeAddress{}, fmt.Errorf("error while querying for providerID %q: %v", providerID, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(instance.NetworkInterfaces) < 1 {
 | 
			
		||||
		return []v1.NodeAddress{}, fmt.Errorf("could not find network interfaces for providerID %q", providerID)
 | 
			
		||||
	}
 | 
			
		||||
	networkInterface := instance.NetworkInterfaces[0]
 | 
			
		||||
 | 
			
		||||
	nodeAddresses := []v1.NodeAddress{{Type: v1.NodeInternalIP, Address: networkInterface.NetworkIP}}
 | 
			
		||||
	for _, config := range networkInterface.AccessConfigs {
 | 
			
		||||
		nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeExternalIP, Address: config.NatIP})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nodeAddresses, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InstanceTypeByProviderID returns the cloudprovider instance type of the node
 | 
			
		||||
@@ -70,7 +89,15 @@ func (gce *GCECloud) NodeAddressesByProviderID(providerID string) ([]v1.NodeAddr
 | 
			
		||||
// 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) {
 | 
			
		||||
	return "", errors.New("unimplemented")
 | 
			
		||||
	project, zone, name, err := splitProviderID(providerID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	instance, err := gce.getInstanceFromProjectInZoneByName(project, zone, name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return instance.Type, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExternalID returns the cloud provider ID of the node with the specified NodeName (deprecated).
 | 
			
		||||
@@ -339,30 +366,38 @@ func (gce *GCECloud) getInstancesByNames(names []string) ([]*gceInstance, error)
 | 
			
		||||
func (gce *GCECloud) getInstanceByName(name string) (*gceInstance, error) {
 | 
			
		||||
	// Avoid changing behaviour when not managing multiple zones
 | 
			
		||||
	for _, zone := range gce.managedZones {
 | 
			
		||||
		name = canonicalizeInstanceName(name)
 | 
			
		||||
		mc := newInstancesMetricContext("get", zone)
 | 
			
		||||
		res, err := gce.service.Instances.Get(gce.projectID, zone, name).Do()
 | 
			
		||||
		mc.Observe(err)
 | 
			
		||||
		instance, err := gce.getInstanceFromProjectInZoneByName(gce.projectID, zone, name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			glog.Errorf("getInstanceByName: failed to get instance %s; err: %v", name, err)
 | 
			
		||||
 | 
			
		||||
			if isHTTPErrorCode(err, http.StatusNotFound) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return &gceInstance{
 | 
			
		||||
			Zone:  lastComponent(res.Zone),
 | 
			
		||||
			Name:  res.Name,
 | 
			
		||||
			ID:    res.Id,
 | 
			
		||||
			Disks: res.Disks,
 | 
			
		||||
			Type:  lastComponent(res.MachineType),
 | 
			
		||||
		}, nil
 | 
			
		||||
		return instance, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, cloudprovider.InstanceNotFound
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gce *GCECloud) getInstanceFromProjectInZoneByName(project, zone, name string) (*gceInstance, error) {
 | 
			
		||||
	name = canonicalizeInstanceName(name)
 | 
			
		||||
	mc := newInstancesMetricContext("get", zone)
 | 
			
		||||
	res, err := gce.service.Instances.Get(project, zone, name).Do()
 | 
			
		||||
	mc.Observe(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Errorf("getInstanceFromProjectInZoneByName: failed to get instance %s; err: %v", name, err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &gceInstance{
 | 
			
		||||
		Zone:  lastComponent(res.Zone),
 | 
			
		||||
		Name:  res.Name,
 | 
			
		||||
		ID:    res.Id,
 | 
			
		||||
		Disks: res.Disks,
 | 
			
		||||
		Type:  lastComponent(res.MachineType),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getInstanceIDViaMetadata() (string, error) {
 | 
			
		||||
	result, err := metadata.Get("instance/hostname")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -158,3 +158,93 @@ func TestCreateFirewallFails(t *testing.T) {
 | 
			
		||||
		t.Errorf("error expected when creating firewall without any tags found")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSplitProviderID(t *testing.T) {
 | 
			
		||||
	providers := []struct {
 | 
			
		||||
		providerID string
 | 
			
		||||
 | 
			
		||||
		project  string
 | 
			
		||||
		zone     string
 | 
			
		||||
		instance string
 | 
			
		||||
 | 
			
		||||
		fail bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			providerID: ProviderName + "://project-example-164317/us-central1-f/kubernetes-node-fhx1",
 | 
			
		||||
			project:    "project-example-164317",
 | 
			
		||||
			zone:       "us-central1-f",
 | 
			
		||||
			instance:   "kubernetes-node-fhx1",
 | 
			
		||||
			fail:       false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			providerID: ProviderName + "://project-example.164317/us-central1-f/kubernetes-node-fhx1",
 | 
			
		||||
			project:    "project-example.164317",
 | 
			
		||||
			zone:       "us-central1-f",
 | 
			
		||||
			instance:   "kubernetes-node-fhx1",
 | 
			
		||||
			fail:       false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			providerID: ProviderName + "://project-example-164317/us-central1-fkubernetes-node-fhx1",
 | 
			
		||||
			project:    "",
 | 
			
		||||
			zone:       "",
 | 
			
		||||
			instance:   "",
 | 
			
		||||
			fail:       true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			providerID: ProviderName + ":/project-example-164317/us-central1-f/kubernetes-node-fhx1",
 | 
			
		||||
			project:    "",
 | 
			
		||||
			zone:       "",
 | 
			
		||||
			instance:   "",
 | 
			
		||||
			fail:       true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			providerID: "aws://project-example-164317/us-central1-f/kubernetes-node-fhx1",
 | 
			
		||||
			project:    "",
 | 
			
		||||
			zone:       "",
 | 
			
		||||
			instance:   "",
 | 
			
		||||
			fail:       true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			providerID: ProviderName + "://project-example-164317/us-central1-f/kubernetes-node-fhx1/",
 | 
			
		||||
			project:    "",
 | 
			
		||||
			zone:       "",
 | 
			
		||||
			instance:   "",
 | 
			
		||||
			fail:       true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			providerID: ProviderName + "://project-example.164317//kubernetes-node-fhx1",
 | 
			
		||||
			project:    "",
 | 
			
		||||
			zone:       "",
 | 
			
		||||
			instance:   "",
 | 
			
		||||
			fail:       true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			providerID: ProviderName + "://project-example.164317/kubernetes-node-fhx1",
 | 
			
		||||
			project:    "",
 | 
			
		||||
			zone:       "",
 | 
			
		||||
			instance:   "",
 | 
			
		||||
			fail:       true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range providers {
 | 
			
		||||
		project, zone, instance, err := splitProviderID(test.providerID)
 | 
			
		||||
		if (err != nil) != test.fail {
 | 
			
		||||
			t.Errorf("Expected to failt=%t, with pattern %v", test.fail, test)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.fail {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if project != test.project {
 | 
			
		||||
			t.Errorf("Expected %v, but got %v", test.project, project)
 | 
			
		||||
		}
 | 
			
		||||
		if zone != test.zone {
 | 
			
		||||
			t.Errorf("Expected %v, but got %v", test.zone, zone)
 | 
			
		||||
		}
 | 
			
		||||
		if instance != test.instance {
 | 
			
		||||
			t.Errorf("Expected %v, but got %v", test.instance, instance)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,9 @@ limitations under the License.
 | 
			
		||||
package gce
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/types"
 | 
			
		||||
@@ -35,6 +37,8 @@ type gceInstance struct {
 | 
			
		||||
	Type  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var providerIdRE = regexp.MustCompile(`^` + ProviderName + `://([^/]+)/([^/]+)/([^/]+)$`)
 | 
			
		||||
 | 
			
		||||
func getProjectAndZone() (string, string, error) {
 | 
			
		||||
	result, err := metadata.Get("instance/zone")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -100,3 +104,14 @@ func isHTTPErrorCode(err error, code int) bool {
 | 
			
		||||
	apiErr, ok := err.(*googleapi.Error)
 | 
			
		||||
	return ok && apiErr.Code == code
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// splitProviderID splits a provider's id into core components.
 | 
			
		||||
// A providerID is build out of '${ProviderName}://${project-id}/${zone}/${instance-name}'
 | 
			
		||||
// See cloudprovider.GetInstanceProviderID.
 | 
			
		||||
func splitProviderID(providerID string) (project, zone, instance string, err error) {
 | 
			
		||||
	matches := providerIdRE.FindStringSubmatch(providerID)
 | 
			
		||||
	if len(matches) != 4 {
 | 
			
		||||
		return "", "", "", errors.New("error splitting providerID")
 | 
			
		||||
	}
 | 
			
		||||
	return matches[1], matches[2], matches[3], nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user