Skip to content
This repository was archived by the owner on Mar 22, 2018. It is now read-only.

Commit 325671b

Browse files
authored
Merge branch 'master' into master
2 parents 68bea98 + ba83c3f commit 325671b

14 files changed

Lines changed: 386 additions & 145 deletions

File tree

pkg/cloudprovider/providers/openstack/metadata.go

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,25 @@ import (
3232
"k8s.io/utils/exec"
3333
)
3434

35-
// metadataUrl is URL to OpenStack metadata server. It's hardcoded IPv4
36-
// link-local address as documented in "OpenStack Cloud Administrator Guide",
37-
// chapter Compute - Networking with nova-network.
38-
// https://docs.openstack.org/admin-guide/compute-networking-nova.html#metadata-service
39-
const metadataUrl = "http://169.254.169.254/openstack/2012-08-10/meta_data.json"
40-
41-
// Config drive is defined as an iso9660 or vfat (deprecated) drive
42-
// with the "config-2" label.
43-
// http://docs.openstack.org/user-guide/cli-config-drive.html
44-
const configDriveLabel = "config-2"
45-
const configDrivePath = "openstack/2012-08-10/meta_data.json"
35+
const (
36+
// metadataUrl is URL to OpenStack metadata server. It's hardcoded IPv4
37+
// link-local address as documented in "OpenStack Cloud Administrator Guide",
38+
// chapter Compute - Networking with nova-network.
39+
// https://docs.openstack.org/admin-guide/compute-networking-nova.html#metadata-service
40+
metadataUrl = "http://169.254.169.254/openstack/2012-08-10/meta_data.json"
41+
42+
// metadataID is used as an identifier on the metadata search order configuration.
43+
metadataID = "metadataService"
44+
45+
// Config drive is defined as an iso9660 or vfat (deprecated) drive
46+
// with the "config-2" label.
47+
// http://docs.openstack.org/user-guide/cli-config-drive.html
48+
configDriveLabel = "config-2"
49+
configDrivePath = "openstack/2012-08-10/meta_data.json"
50+
51+
// configDriveID is used as an identifier on the metadata search order configuration.
52+
configDriveID = "configDrive"
53+
)
4654

4755
var ErrBadMetadata = errors.New("Invalid OpenStack metadata, got empty uuid")
4856

@@ -141,12 +149,28 @@ func getMetadataFromMetadataService() (*Metadata, error) {
141149
// Metadata is fixed for the current host, so cache the value process-wide
142150
var metadataCache *Metadata
143151

144-
func getMetadata() (*Metadata, error) {
152+
func getMetadata(order string) (*Metadata, error) {
145153
if metadataCache == nil {
146-
md, err := getMetadataFromConfigDrive()
147-
if err != nil {
148-
md, err = getMetadataFromMetadataService()
154+
var md *Metadata
155+
var err error
156+
157+
elements := strings.Split(order, ",")
158+
for _, id := range elements {
159+
id = strings.TrimSpace(id)
160+
switch id {
161+
case configDriveID:
162+
md, err = getMetadataFromConfigDrive()
163+
case metadataID:
164+
md, err = getMetadataFromMetadataService()
165+
default:
166+
err = fmt.Errorf("%s is not a valid metadata search order option. Supported options are %s and %s", id, configDriveID, metadataID)
167+
}
168+
169+
if err == nil {
170+
break
171+
}
149172
}
173+
150174
if err != nil {
151175
return nil, err
152176
}

pkg/cloudprovider/providers/openstack/openstack.go

Lines changed: 112 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ import (
4949
"k8s.io/kubernetes/pkg/controller"
5050
)
5151

52-
const ProviderName = "openstack"
52+
const (
53+
ProviderName = "openstack"
54+
AvailabilityZone = "availability_zone"
55+
)
5356

5457
var ErrNotFound = errors.New("Failed to find object")
5558
var ErrMultipleResults = errors.New("Multiple results where only one expected")
@@ -97,13 +100,18 @@ type RouterOpts struct {
97100
RouterId string `gcfg:"router-id"` // required
98101
}
99102

103+
type MetadataOpts struct {
104+
SearchOrder string `gcfg:"search-order"`
105+
}
106+
100107
// OpenStack is an implementation of cloud provider Interface for OpenStack.
101108
type OpenStack struct {
102-
provider *gophercloud.ProviderClient
103-
region string
104-
lbOpts LoadBalancerOpts
105-
bsOpts BlockStorageOpts
106-
routeOpts RouterOpts
109+
provider *gophercloud.ProviderClient
110+
region string
111+
lbOpts LoadBalancerOpts
112+
bsOpts BlockStorageOpts
113+
routeOpts RouterOpts
114+
metadataOpts MetadataOpts
107115
// InstanceID of the server where this OpenStack object is instantiated.
108116
localInstanceID string
109117
}
@@ -125,6 +133,7 @@ type Config struct {
125133
LoadBalancer LoadBalancerOpts
126134
BlockStorage BlockStorageOpts
127135
Route RouterOpts
136+
Metadata MetadataOpts
128137
}
129138

130139
func init() {
@@ -178,6 +187,7 @@ func readConfig(config io.Reader) (Config, error) {
178187
// Set default values for config params
179188
cfg.BlockStorage.BSVersion = "auto"
180189
cfg.BlockStorage.TrustDevicePath = false
190+
cfg.Metadata.SearchOrder = fmt.Sprintf("%s,%s", configDriveID, metadataID)
181191

182192
err := gcfg.ReadInto(&cfg, config)
183193
return cfg, err
@@ -195,7 +205,7 @@ func (c *Caller) Call(f func()) {
195205
}
196206
}
197207

198-
func readInstanceID() (string, error) {
208+
func readInstanceID(searchOrder string) (string, error) {
199209
// Try to find instance ID on the local filesystem (created by cloud-init)
200210
const instanceIDFile = "/var/lib/cloud/data/instance-id"
201211
idBytes, err := ioutil.ReadFile(instanceIDFile)
@@ -209,7 +219,7 @@ func readInstanceID() (string, error) {
209219
// Fall through to metadata server lookup
210220
}
211221

212-
md, err := getMetadata()
222+
md, err := getMetadata(searchOrder)
213223
if err != nil {
214224
return "", err
215225
}
@@ -243,6 +253,10 @@ func checkOpenStackOpts(openstackOpts *OpenStack) error {
243253
}
244254
}
245255

256+
if err := checkMetadataSearchOrder(openstackOpts.metadataOpts.SearchOrder); err != nil {
257+
return err
258+
}
259+
246260
return nil
247261
}
248262

@@ -277,11 +291,12 @@ func newOpenStack(cfg Config) (*OpenStack, error) {
277291
}
278292

279293
os := OpenStack{
280-
provider: provider,
281-
region: cfg.Global.Region,
282-
lbOpts: cfg.LoadBalancer,
283-
bsOpts: cfg.BlockStorage,
284-
routeOpts: cfg.Route,
294+
provider: provider,
295+
region: cfg.Global.Region,
296+
lbOpts: cfg.LoadBalancer,
297+
bsOpts: cfg.BlockStorage,
298+
routeOpts: cfg.Route,
299+
metadataOpts: cfg.Metadata,
285300
}
286301

287302
err = checkOpenStackOpts(&os)
@@ -481,7 +496,6 @@ func (os *OpenStack) HasClusterID() bool {
481496
func (os *OpenStack) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
482497
glog.V(4).Info("openstack.LoadBalancer() called")
483498

484-
// TODO: Search for and support Rackspace loadbalancer API, and others.
485499
network, err := os.NewNetworkV2()
486500
if err != nil {
487501
return nil, false
@@ -517,6 +531,9 @@ func (os *OpenStack) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
517531
if lbVersion == "v2" {
518532
return &LbaasV2{LoadBalancer{network, compute, os.lbOpts}}, true
519533
} else if lbVersion == "v1" {
534+
// Since LBaaS v1 is deprecated in the OpenStack Liberty release, so deprecate LBaaSV1 at V1.8, then remove LBaaSV1 after V1.9.
535+
// Reference OpenStack doc: https://docs.openstack.org/mitaka/networking-guide/config-lbaas.html
536+
glog.Warningf("The LBaaS v1 of OpenStack cloud provider has been deprecated, Please use LBaaS v2")
520537
return &LbaasV1{LoadBalancer{network, compute, os.lbOpts}}, true
521538
} else {
522539
glog.Warningf("Config error: unrecognised lb-version \"%v\"", lbVersion)
@@ -534,8 +551,9 @@ func (os *OpenStack) Zones() (cloudprovider.Zones, bool) {
534551

535552
return os, true
536553
}
554+
537555
func (os *OpenStack) GetZone() (cloudprovider.Zone, error) {
538-
md, err := getMetadata()
556+
md, err := getMetadata(os.metadataOpts.SearchOrder)
539557
if err != nil {
540558
return cloudprovider.Zone{}, err
541559
}
@@ -549,6 +567,60 @@ func (os *OpenStack) GetZone() (cloudprovider.Zone, error) {
549567
return zone, nil
550568
}
551569

570+
// GetZoneByProviderID implements Zones.GetZoneByProviderID
571+
// This is particularly useful in external cloud providers where the kubelet
572+
// does not initialize node data.
573+
func (os *OpenStack) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
574+
instanceID, err := instanceIDFromProviderID(providerID)
575+
if err != nil {
576+
return cloudprovider.Zone{}, err
577+
}
578+
579+
compute, err := os.NewComputeV2()
580+
if err != nil {
581+
return cloudprovider.Zone{}, err
582+
}
583+
584+
srv, err := servers.Get(compute, instanceID).Extract()
585+
if err != nil {
586+
return cloudprovider.Zone{}, err
587+
}
588+
589+
zone := cloudprovider.Zone{
590+
FailureDomain: srv.Metadata[AvailabilityZone],
591+
Region: os.region,
592+
}
593+
glog.V(4).Infof("The instance %s in zone %v", srv.Name, zone)
594+
595+
return zone, nil
596+
}
597+
598+
// GetZoneByNodeName implements Zones.GetZoneByNodeName
599+
// This is particularly useful in external cloud providers where the kubelet
600+
// does not initialize node data.
601+
func (os *OpenStack) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Zone, error) {
602+
compute, err := os.NewComputeV2()
603+
if err != nil {
604+
return cloudprovider.Zone{}, err
605+
}
606+
607+
srv, err := getServerByName(compute, nodeName)
608+
if err != nil {
609+
if err == ErrNotFound {
610+
return cloudprovider.Zone{}, cloudprovider.InstanceNotFound
611+
}
612+
return cloudprovider.Zone{}, err
613+
}
614+
615+
zone := cloudprovider.Zone{
616+
FailureDomain: srv.Metadata[AvailabilityZone],
617+
Region: os.region,
618+
}
619+
glog.V(4).Infof("The instance %s in zone %v", srv.Name, zone)
620+
621+
return zone, nil
622+
}
623+
552624
func (os *OpenStack) Routes() (cloudprovider.Routes, bool) {
553625
glog.V(4).Info("openstack.Routes() called")
554626

@@ -684,3 +756,28 @@ func (os *OpenStack) volumeService(forceVersion string) (volumeService, error) {
684756
return nil, errors.New(err_txt)
685757
}
686758
}
759+
760+
func checkMetadataSearchOrder(order string) error {
761+
if order == "" {
762+
return errors.New("Invalid value in section [Metadata] with key `search-order`. Value cannot be empty")
763+
}
764+
765+
elements := strings.Split(order, ",")
766+
if len(elements) > 2 {
767+
return errors.New("Invalid value in section [Metadata] with key `search-order`. Value cannot contain more than 2 elements")
768+
}
769+
770+
for _, id := range elements {
771+
id = strings.TrimSpace(id)
772+
switch id {
773+
case configDriveID:
774+
case metadataID:
775+
default:
776+
errTxt := "Invalid element '%s' found in section [Metadata] with key `search-order`." +
777+
"Supported elements include '%s' and '%s'"
778+
return fmt.Errorf(errTxt, id, configDriveID, metadataID)
779+
}
780+
}
781+
782+
return nil
783+
}

0 commit comments

Comments
 (0)