mirror of https://github.com/k3s-io/k3s
Merge pull request #50858 from andrewsykim/49308
Automatic merge from submit-queue (batch tested with PRs 51148, 50816, 49741, 50858, 51223) cloudprovider.Zones should support external cloud providers **What this PR does / why we need it**: Provides methods in cloudprovider.Zones that allows external cloud providers to set the correct zone labels to nodes. Part of https://github.com/kubernetes/kubernetes/issues/48690 **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes https://github.com/kubernetes/kubernetes/issues/49308 **Special notes for your reviewer**: Should help with getting ccm/external cloud providers to beta. **Release note**: ```release-note cloudprovider.Zones should support external cloud providers ``` cc @luxas @wlan0 @thockinpull/6/head
commit
909a0984f1
|
@ -184,5 +184,18 @@ type Zone struct {
|
||||||
// Zones is an abstract, pluggable interface for zone enumeration.
|
// Zones is an abstract, pluggable interface for zone enumeration.
|
||||||
type Zones interface {
|
type Zones interface {
|
||||||
// GetZone returns the Zone containing the current failure zone and locality region that the program is running in
|
// GetZone returns the Zone containing the current failure zone and locality region that the program is running in
|
||||||
|
// In most cases, this method is called from the kubelet querying a local metadata service to aquire its zone.
|
||||||
|
// For the case of external cloud providers, use GetZoneByProviderID or GetZoneByNodeName since GetZone
|
||||||
|
// can no longer be called from the kubelets.
|
||||||
GetZone() (Zone, error)
|
GetZone() (Zone, error)
|
||||||
|
|
||||||
|
// GetZoneByProviderID returns the Zone containing the current zone and locality region of the node specified by providerId
|
||||||
|
// This method is particularly used in the context of external cloud providers where node initialization must be down
|
||||||
|
// outside the kubelets.
|
||||||
|
GetZoneByProviderID(providerID string) (Zone, error)
|
||||||
|
|
||||||
|
// GetZoneByNodeName returns the Zone containing the current zone and locality region of the node specified by node name
|
||||||
|
// This method is particularly used in the context of external cloud providers where node initialization must be down
|
||||||
|
// outside the kubelets.
|
||||||
|
GetZoneByNodeName(nodeName types.NodeName) (Zone, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1201,6 +1201,20 @@ func (c *Cloud) GetZone() (cloudprovider.Zone, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetZoneByProviderID implements Zones.GetZoneByProviderID
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (c *Cloud) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByProviderID not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneByNodeName implements Zones.GetZoneByNodeName
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (c *Cloud) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByNodeName not imeplemented")
|
||||||
|
}
|
||||||
|
|
||||||
// Abstraction around AWS Instance Types
|
// Abstraction around AWS Instance Types
|
||||||
// There isn't an API to get information for a particular instance type (that I know of)
|
// There isn't an API to get information for a particular instance type (that I know of)
|
||||||
type awsInstanceType struct {
|
type awsInstanceType struct {
|
||||||
|
|
|
@ -18,11 +18,13 @@ package azure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -55,6 +57,20 @@ func (az *Cloud) GetZone() (cloudprovider.Zone, error) {
|
||||||
return zone, nil
|
return zone, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetZoneByProviderID implements Zones.GetZoneByProviderID
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (az *Cloud) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByProviderID not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneByNodeName implements Zones.GetZoneByNodeName
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (az *Cloud) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByNodeName not imeplemented")
|
||||||
|
}
|
||||||
|
|
||||||
func fetchFaultDomain() (*string, error) {
|
func fetchFaultDomain() (*string, error) {
|
||||||
resp, err := http.Get(instanceInfoURL)
|
resp, err := http.Get(instanceInfoURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -19,6 +19,7 @@ go_library(
|
||||||
"//vendor/github.com/xanzy/go-cloudstack/cloudstack:go_default_library",
|
"//vendor/github.com/xanzy/go-cloudstack/cloudstack:go_default_library",
|
||||||
"//vendor/gopkg.in/gcfg.v1:go_default_library",
|
"//vendor/gopkg.in/gcfg.v1:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,15 @@ limitations under the License.
|
||||||
package cloudstack
|
package cloudstack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/xanzy/go-cloudstack/cloudstack"
|
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||||
"gopkg.in/gcfg.v1"
|
"gopkg.in/gcfg.v1"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
)
|
)
|
||||||
|
@ -130,3 +133,17 @@ func (cs *CSCloud) GetZone() (cloudprovider.Zone, error) {
|
||||||
glog.V(2).Infof("Current zone is %v", cs.zone)
|
glog.V(2).Infof("Current zone is %v", cs.zone)
|
||||||
return cloudprovider.Zone{Region: cs.zone}, nil
|
return cloudprovider.Zone{Region: cs.zone}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetZoneByProviderID implements Zones.GetZoneByProviderID
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (cs *CSCloud) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByProviderID not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneByNodeName implements Zones.GetZoneByNodeName
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (cs *CSCloud) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByNodeName not imeplemented")
|
||||||
|
}
|
||||||
|
|
|
@ -252,6 +252,22 @@ func (f *FakeCloud) GetZone() (cloudprovider.Zone, error) {
|
||||||
return f.Zone, f.Err
|
return f.Zone, f.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetZoneByProviderID implements Zones.GetZoneByProviderID
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (f *FakeCloud) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
|
||||||
|
f.addCall("get-zone-by-provider-id")
|
||||||
|
return f.Zone, f.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneByNodeName implements Zones.GetZoneByNodeName
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (f *FakeCloud) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Zone, error) {
|
||||||
|
f.addCall("get-zone-by-node-name")
|
||||||
|
return f.Zone, f.Err
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FakeCloud) ListRoutes(clusterName string) ([]*cloudprovider.Route, error) {
|
func (f *FakeCloud) ListRoutes(clusterName string) ([]*cloudprovider.Route, error) {
|
||||||
f.Lock.Lock()
|
f.Lock.Lock()
|
||||||
defer f.Lock.Unlock()
|
defer f.Lock.Unlock()
|
||||||
|
|
|
@ -17,12 +17,14 @@ limitations under the License.
|
||||||
package gce
|
package gce
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func newZonesMetricContext(request, region string) *metricContext {
|
func newZonesMetricContext(request, region string) *metricContext {
|
||||||
|
@ -37,6 +39,20 @@ func (gce *GCECloud) GetZone() (cloudprovider.Zone, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetZoneByProviderID implements Zones.GetZoneByProviderID
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (gce *GCECloud) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByProviderID not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneByNodeName implements Zones.GetZoneByNodeName
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (gce *GCECloud) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByNodeName not imeplemented")
|
||||||
|
}
|
||||||
|
|
||||||
// ListZonesInRegion returns all zones in a GCP region
|
// ListZonesInRegion returns all zones in a GCP region
|
||||||
func (gce *GCECloud) ListZonesInRegion(region string) ([]*compute.Zone, error) {
|
func (gce *GCECloud) ListZonesInRegion(region string) ([]*compute.Zone, error) {
|
||||||
mc := newZonesMetricContext("list", region)
|
mc := newZonesMetricContext("list", region)
|
||||||
|
|
|
@ -549,6 +549,20 @@ func (os *OpenStack) GetZone() (cloudprovider.Zone, error) {
|
||||||
return zone, nil
|
return zone, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetZoneByProviderID implements Zones.GetZoneByProviderID
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (os *OpenStack) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByProviderID not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneByNodeName implements Zones.GetZoneByNodeName
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (os *OpenStack) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByNodeName not imeplemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (os *OpenStack) Routes() (cloudprovider.Routes, bool) {
|
func (os *OpenStack) Routes() (cloudprovider.Routes, bool) {
|
||||||
glog.V(4).Info("openstack.Routes() called")
|
glog.V(4).Info("openstack.Routes() called")
|
||||||
|
|
||||||
|
|
|
@ -521,6 +521,20 @@ func (pc *PCCloud) GetZone() (cloudprovider.Zone, error) {
|
||||||
return pc.Zone, nil
|
return pc.Zone, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetZoneByProviderID implements Zones.GetZoneByProviderID
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (pc *PCCloud) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByProviderID not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneByNodeName implements Zones.GetZoneByNodeName
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (pc *PCCloud) GetZoneByNodeName(nodeName k8stypes.NodeName) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByNodeName not imeplemented")
|
||||||
|
}
|
||||||
|
|
||||||
// Routes returns a false since the interface is not supported for photon controller.
|
// Routes returns a false since the interface is not supported for photon controller.
|
||||||
func (pc *PCCloud) Routes() (cloudprovider.Routes, bool) {
|
func (pc *PCCloud) Routes() (cloudprovider.Routes, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
|
|
|
@ -554,6 +554,20 @@ func (os *Rackspace) GetZone() (cloudprovider.Zone, error) {
|
||||||
return cloudprovider.Zone{Region: os.region}, nil
|
return cloudprovider.Zone{Region: os.region}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetZoneByProviderID implements Zones.GetZoneByProviderID
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (os *Rackspace) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByProviderID not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneByNodeName implements Zones.GetZoneByNodeName
|
||||||
|
// This is particularly useful in external cloud providers where the kubelet
|
||||||
|
// does not initialize node data.
|
||||||
|
func (os *Rackspace) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Zone, error) {
|
||||||
|
return cloudprovider.Zone{}, errors.New("GetZoneByNodeName not imeplemented")
|
||||||
|
}
|
||||||
|
|
||||||
// Create a volume of given size (in GiB)
|
// Create a volume of given size (in GiB)
|
||||||
func (rs *Rackspace) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, error) {
|
func (rs *Rackspace) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, error) {
|
||||||
return "", "", errors.New("unimplemented")
|
return "", "", errors.New("unimplemented")
|
||||||
|
|
|
@ -321,7 +321,7 @@ func (cnc *CloudNodeController) AddCloudNode(obj interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if zones, ok := cnc.cloud.Zones(); ok {
|
if zones, ok := cnc.cloud.Zones(); ok {
|
||||||
zone, err := zones.GetZone()
|
zone, err := getZoneByProviderIDOrName(zones, curNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get zone from cloud provider: %v", err)
|
return fmt.Errorf("failed to get zone from cloud provider: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -430,3 +430,18 @@ func getInstanceTypeByProviderIDOrName(instances cloudprovider.Instances, node *
|
||||||
}
|
}
|
||||||
return instanceType, err
|
return instanceType, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getZoneByProviderIDorName will attempt to get the zone of node using its providerID
|
||||||
|
// then it's name. If both attempts fail, an error is returned
|
||||||
|
func getZoneByProviderIDOrName(zones cloudprovider.Zones, node *v1.Node) (cloudprovider.Zone, error) {
|
||||||
|
zone, err := zones.GetZoneByProviderID(node.Spec.ProviderID)
|
||||||
|
if err != nil {
|
||||||
|
providerIDErr := err
|
||||||
|
zone, err = zones.GetZoneByNodeName(types.NodeName(node.Name))
|
||||||
|
if err != nil {
|
||||||
|
return cloudprovider.Zone{}, fmt.Errorf("Zone: Error fetching by providerID: %v Error fetching by NodeName: %v", providerIDErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue