-
Notifications
You must be signed in to change notification settings - Fork 38.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GCE for cloud-controller-manager #45313
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,6 @@ limitations under the License. | |
package gce | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"strconv" | ||
|
@@ -62,15 +61,43 @@ 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 | ||
// 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) { | ||
return "", errors.New("unimplemented") | ||
project, zone, name, err := splitProviderID(providerID) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if err is not nil here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if zone is unknown (empty)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The provider id is a concatinated string There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please return the error and fail fast |
||
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 { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. did you check if it was doable with url.Parse BTW? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is doable with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use a regular expression rather than a series of string splits? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I use regexp only for non trivial things to parse. But a simple regex could easily enhance the readability of this function. I'd go with something like this |
||
matches := providerIdRE.FindStringSubmatch(providerID) | ||
if len(matches) != 4 { | ||
return "", "", "", errors.New("error splitting providerID") | ||
} | ||
return matches[1], matches[2], matches[3], nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a chance that there are multiple internal IPs?
In that case you should loop through
instance.NetworkInterfaces
hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation states:
An array of configurations for this interface. [...]. Only one interface is supported per instance.