@@ -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
5457var ErrNotFound = errors .New ("Failed to find object" )
5558var 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.
101108type 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
130139func 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 {
481496func (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+
537555func (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+
552624func (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