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

Commit 228f842

Browse files
author
Kubernetes Submit Queue
authored
Merge pull request #52628 from richardalberto/metadata-search-order
Automatic merge from submit-queue (batch tested with PRs 53157, 52628). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Added openstack instance metadata search order **What this PR does / why we need it**: This PR adds a search order for the instance metadata retrieval on openstack. More information and discussion can be found on #52378 **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #52378 **Special notes for your reviewer**: **Release note**: ```release-note NONE ```
2 parents dfbbd7a + d07fdec commit 228f842

4 files changed

Lines changed: 146 additions & 32 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: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,18 @@ type RouterOpts struct {
100100
RouterId string `gcfg:"router-id"` // required
101101
}
102102

103+
type MetadataOpts struct {
104+
SearchOrder string `gcfg:"search-order"`
105+
}
106+
103107
// OpenStack is an implementation of cloud provider Interface for OpenStack.
104108
type OpenStack struct {
105-
provider *gophercloud.ProviderClient
106-
region string
107-
lbOpts LoadBalancerOpts
108-
bsOpts BlockStorageOpts
109-
routeOpts RouterOpts
109+
provider *gophercloud.ProviderClient
110+
region string
111+
lbOpts LoadBalancerOpts
112+
bsOpts BlockStorageOpts
113+
routeOpts RouterOpts
114+
metadataOpts MetadataOpts
110115
// InstanceID of the server where this OpenStack object is instantiated.
111116
localInstanceID string
112117
}
@@ -128,6 +133,7 @@ type Config struct {
128133
LoadBalancer LoadBalancerOpts
129134
BlockStorage BlockStorageOpts
130135
Route RouterOpts
136+
Metadata MetadataOpts
131137
}
132138

133139
func init() {
@@ -181,6 +187,7 @@ func readConfig(config io.Reader) (Config, error) {
181187
// Set default values for config params
182188
cfg.BlockStorage.BSVersion = "auto"
183189
cfg.BlockStorage.TrustDevicePath = false
190+
cfg.Metadata.SearchOrder = fmt.Sprintf("%s,%s", configDriveID, metadataID)
184191

185192
err := gcfg.ReadInto(&cfg, config)
186193
return cfg, err
@@ -198,7 +205,7 @@ func (c *Caller) Call(f func()) {
198205
}
199206
}
200207

201-
func readInstanceID() (string, error) {
208+
func readInstanceID(searchOrder string) (string, error) {
202209
// Try to find instance ID on the local filesystem (created by cloud-init)
203210
const instanceIDFile = "/var/lib/cloud/data/instance-id"
204211
idBytes, err := ioutil.ReadFile(instanceIDFile)
@@ -212,7 +219,7 @@ func readInstanceID() (string, error) {
212219
// Fall through to metadata server lookup
213220
}
214221

215-
md, err := getMetadata()
222+
md, err := getMetadata(searchOrder)
216223
if err != nil {
217224
return "", err
218225
}
@@ -246,6 +253,10 @@ func checkOpenStackOpts(openstackOpts *OpenStack) error {
246253
}
247254
}
248255

256+
if err := checkMetadataSearchOrder(openstackOpts.metadataOpts.SearchOrder); err != nil {
257+
return err
258+
}
259+
249260
return nil
250261
}
251262

@@ -280,11 +291,12 @@ func newOpenStack(cfg Config) (*OpenStack, error) {
280291
}
281292

282293
os := OpenStack{
283-
provider: provider,
284-
region: cfg.Global.Region,
285-
lbOpts: cfg.LoadBalancer,
286-
bsOpts: cfg.BlockStorage,
287-
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,
288300
}
289301

290302
err = checkOpenStackOpts(&os)
@@ -541,7 +553,7 @@ func (os *OpenStack) Zones() (cloudprovider.Zones, bool) {
541553
}
542554

543555
func (os *OpenStack) GetZone() (cloudprovider.Zone, error) {
544-
md, err := getMetadata()
556+
md, err := getMetadata(os.metadataOpts.SearchOrder)
545557
if err != nil {
546558
return cloudprovider.Zone{}, err
547559
}
@@ -744,3 +756,28 @@ func (os *OpenStack) volumeService(forceVersion string) (volumeService, error) {
744756
return nil, errors.New(err_txt)
745757
}
746758
}
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+
}

pkg/cloudprovider/providers/openstack/openstack_instances.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232

3333
type Instances struct {
3434
compute *gophercloud.ServiceClient
35+
opts MetadataOpts
3536
}
3637

3738
// Instances returns an implementation of Instances for OpenStack.
@@ -45,13 +46,16 @@ func (os *OpenStack) Instances() (cloudprovider.Instances, bool) {
4546

4647
glog.V(1).Info("Claiming to support Instances")
4748

48-
return &Instances{compute}, true
49+
return &Instances{
50+
compute: compute,
51+
opts: os.metadataOpts,
52+
}, true
4953
}
5054

5155
// Implementation of Instances.CurrentNodeName
5256
// Note this is *not* necessarily the same as hostname.
5357
func (i *Instances) CurrentNodeName(hostname string) (types.NodeName, error) {
54-
md, err := getMetadata()
58+
md, err := getMetadata(i.opts.SearchOrder)
5559
if err != nil {
5660
return "", err
5761
}
@@ -119,7 +123,7 @@ func (i *Instances) InstanceExistsByProviderID(providerID string) (bool, error)
119123
// InstanceID returns the kubelet's cloud provider ID.
120124
func (os *OpenStack) InstanceID() (string, error) {
121125
if len(os.localInstanceID) == 0 {
122-
id, err := readInstanceID()
126+
id, err := readInstanceID(os.metadataOpts.SearchOrder)
123127
if err != nil {
124128
return "", err
125129
}

pkg/cloudprovider/providers/openstack/openstack_test.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ func TestReadConfig(t *testing.T) {
101101
[BlockStorage]
102102
bs-version = auto
103103
trust-device-path = yes
104-
104+
[Metadata]
105+
search-order = configDrive, metadataService
105106
`))
106107
if err != nil {
107108
t.Fatalf("Should succeed when a valid config is provided: %s", err)
@@ -128,6 +129,9 @@ func TestReadConfig(t *testing.T) {
128129
if cfg.BlockStorage.BSVersion != "auto" {
129130
t.Errorf("incorrect bs.bs-version: %v", cfg.BlockStorage.BSVersion)
130131
}
132+
if cfg.Metadata.SearchOrder != "configDrive, metadataService" {
133+
t.Errorf("incorrect md.search-order: %v", cfg.Metadata.SearchOrder)
134+
}
131135
}
132136

133137
func TestToAuthOptions(t *testing.T) {
@@ -169,6 +173,9 @@ func TestCheckOpenStackOpts(t *testing.T) {
169173
ManageSecurityGroups: true,
170174
NodeSecurityGroupID: "b41d28c2-d02f-4e1e-8ffb-23b8e4f5c144",
171175
},
176+
metadataOpts: MetadataOpts{
177+
SearchOrder: configDriveID,
178+
},
172179
},
173180
expectedError: nil,
174181
},
@@ -187,6 +194,9 @@ func TestCheckOpenStackOpts(t *testing.T) {
187194
ManageSecurityGroups: true,
188195
NodeSecurityGroupID: "b41d28c2-d02f-4e1e-8ffb-23b8e4f5c144",
189196
},
197+
metadataOpts: MetadataOpts{
198+
SearchOrder: configDriveID,
199+
},
190200
},
191201
expectedError: nil,
192202
},
@@ -203,6 +213,9 @@ func TestCheckOpenStackOpts(t *testing.T) {
203213
ManageSecurityGroups: true,
204214
NodeSecurityGroupID: "b41d28c2-d02f-4e1e-8ffb-23b8e4f5c144",
205215
},
216+
metadataOpts: MetadataOpts{
217+
SearchOrder: configDriveID,
218+
},
206219
},
207220
expectedError: fmt.Errorf("monitor-delay not set in cloud provider config"),
208221
},
@@ -221,9 +234,43 @@ func TestCheckOpenStackOpts(t *testing.T) {
221234
MonitorMaxRetries: uint(3),
222235
ManageSecurityGroups: true,
223236
},
237+
metadataOpts: MetadataOpts{
238+
SearchOrder: configDriveID,
239+
},
224240
},
225241
expectedError: fmt.Errorf("node-security-group not set in cloud provider config"),
226242
},
243+
{
244+
name: "test5",
245+
openstackOpts: &OpenStack{
246+
provider: nil,
247+
metadataOpts: MetadataOpts{
248+
SearchOrder: "",
249+
},
250+
},
251+
expectedError: fmt.Errorf("Invalid value in section [Metadata] with key `search-order`. Value cannot be empty"),
252+
},
253+
{
254+
name: "test6",
255+
openstackOpts: &OpenStack{
256+
provider: nil,
257+
metadataOpts: MetadataOpts{
258+
SearchOrder: "value1,value2,value3",
259+
},
260+
},
261+
expectedError: fmt.Errorf("Invalid value in section [Metadata] with key `search-order`. Value cannot contain more than 2 elements"),
262+
},
263+
{
264+
name: "test7",
265+
openstackOpts: &OpenStack{
266+
provider: nil,
267+
metadataOpts: MetadataOpts{
268+
SearchOrder: "value1",
269+
},
270+
},
271+
expectedError: fmt.Errorf("Invalid element '%s' found in section [Metadata] with key `search-order`."+
272+
"Supported elements include '%s' and '%s'", "value1", configDriveID, metadataID),
273+
},
227274
}
228275

229276
for _, testcase := range tests {
@@ -374,6 +421,8 @@ func configFromEnv() (cfg Config, ok bool) {
374421
(cfg.Global.TenantId != "" || cfg.Global.TenantName != "" ||
375422
cfg.Global.DomainId != "" || cfg.Global.DomainName != ""))
376423

424+
cfg.Metadata.SearchOrder = fmt.Sprintf("%s,%s", configDriveID, metadataID)
425+
377426
return
378427
}
379428

0 commit comments

Comments
 (0)