mirror of https://github.com/k3s-io/k3s
Merge pull request #45313 from realfake/cloudprovider-gce-metadata
Automatic merge from submit-queue GCE for cloud-controller-manager **What this PR does / why we need it**: This implements the `NodeAddressesByProviderID`and `InstanceTypeByProviderID` methods used by the cloud-controller-manager to the GCE provider. **Release note**: ```release-note NONE ```pull/6/head
commit
07dac20cc6
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package gce
|
package gce
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"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.
|
// 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
|
// i.e. metadata service and other local methods cannot be used here
|
||||||
func (gce *GCECloud) NodeAddressesByProviderID(providerID string) ([]v1.NodeAddress, error) {
|
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
|
// 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
|
// node that is requesting this ID. i.e. metadata service and other local
|
||||||
// methods cannot be used here
|
// methods cannot be used here
|
||||||
func (gce *GCECloud) InstanceTypeByProviderID(providerID string) (string, error) {
|
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).
|
// ExternalID returns the cloud provider ID of the node with the specified NodeName (deprecated).
|
||||||
|
@ -339,18 +366,29 @@ func (gce *GCECloud) getInstancesByNames(names []string) ([]*gceInstance, error)
|
||||||
func (gce *GCECloud) getInstanceByName(name string) (*gceInstance, error) {
|
func (gce *GCECloud) getInstanceByName(name string) (*gceInstance, error) {
|
||||||
// Avoid changing behaviour when not managing multiple zones
|
// Avoid changing behaviour when not managing multiple zones
|
||||||
for _, zone := range gce.managedZones {
|
for _, zone := range gce.managedZones {
|
||||||
name = canonicalizeInstanceName(name)
|
instance, err := gce.getInstanceFromProjectInZoneByName(gce.projectID, zone, name)
|
||||||
mc := newInstancesMetricContext("get", zone)
|
|
||||||
res, err := gce.service.Instances.Get(gce.projectID, zone, name).Do()
|
|
||||||
mc.Observe(err)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("getInstanceByName: failed to get instance %s; err: %v", name, err)
|
|
||||||
|
|
||||||
if isHTTPErrorCode(err, http.StatusNotFound) {
|
if isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
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{
|
return &gceInstance{
|
||||||
Zone: lastComponent(res.Zone),
|
Zone: lastComponent(res.Zone),
|
||||||
Name: res.Name,
|
Name: res.Name,
|
||||||
|
@ -360,9 +398,6 @@ func (gce *GCECloud) getInstanceByName(name string) (*gceInstance, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, cloudprovider.InstanceNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInstanceIDViaMetadata() (string, error) {
|
func getInstanceIDViaMetadata() (string, error) {
|
||||||
result, err := metadata.Get("instance/hostname")
|
result, err := metadata.Get("instance/hostname")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -158,3 +158,93 @@ func TestCreateFirewallFails(t *testing.T) {
|
||||||
t.Errorf("error expected when creating firewall without any tags found")
|
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
|
package gce
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
@ -35,6 +37,8 @@ type gceInstance struct {
|
||||||
Type string
|
Type string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var providerIdRE = regexp.MustCompile(`^` + ProviderName + `://([^/]+)/([^/]+)/([^/]+)$`)
|
||||||
|
|
||||||
func getProjectAndZone() (string, string, error) {
|
func getProjectAndZone() (string, string, error) {
|
||||||
result, err := metadata.Get("instance/zone")
|
result, err := metadata.Get("instance/zone")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -100,3 +104,14 @@ func isHTTPErrorCode(err error, code int) bool {
|
||||||
apiErr, ok := err.(*googleapi.Error)
|
apiErr, ok := err.(*googleapi.Error)
|
||||||
return ok && apiErr.Code == code
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue