Skip to content

Commit 3caa2e3

Browse files
Merge pull request #132 from shiftstack/merge-bot-master
Merge https://github.com/kubernetes/cloud-provider-openstack:master into master
2 parents cb769eb + 102c13f commit 3caa2e3

File tree

13 files changed

+159
-39
lines changed

13 files changed

+159
-39
lines changed

charts/openstack-cloud-controller-manager/templates/_helpers.tpl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,27 @@ Create cloud-config makro.
5151
{{- define "cloudConfig" -}}
5252
[Global]
5353
{{- range $key, $value := .Values.cloudConfig.global }}
54-
{{ $key }} = {{ $value }}
54+
{{ $key }} = {{ $value | quote }}
5555
{{- end }}
5656

5757
[Networking]
5858
{{- range $key, $value := .Values.cloudConfig.networking }}
59-
{{ $key }} = {{ $value }}
59+
{{ $key }} = {{ $value | quote }}
6060
{{- end }}
6161

6262
[LoadBalancer]
6363
{{- range $key, $value := .Values.cloudConfig.loadBalancer }}
64-
{{ $key }} = {{ $value }}
64+
{{ $key }} = {{ $value | quote }}
6565
{{- end }}
6666

6767
[BlockStorage]
6868
{{- range $key, $value := .Values.cloudConfig.blockStorage }}
69-
{{ $key }} = {{ $value }}
69+
{{ $key }} = {{ $value | quote }}
7070
{{- end }}
7171

7272
[Metadata]
7373
{{- range $key, $value := .Values.cloudConfig.metadata }}
74-
{{ $key }} = {{ $value }}
74+
{{ $key }} = {{ $value | quote }}
7575
{{- end }}
7676
{{- end }}
7777

charts/openstack-cloud-controller-manager/templates/daemonset.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ apiVersion: apps/v1
22
kind: DaemonSet
33
metadata:
44
name: {{ include "occm.name" . }}
5+
namespace: {{ .Release.Namespace }}
56
labels:
67
{{- include "occm.labels" . | nindent 4 }}
78
spec:

charts/openstack-cloud-controller-manager/templates/secret.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ apiVersion: v1
33
kind: Secret
44
metadata:
55
name: {{ .Values.secret.name | default "cloud-config" }}
6+
namespace: {{ .Release.Namespace }}
67
type: Opaque
78
data:
89
{{ if .Values.cloudConfigContents -}}

charts/openstack-cloud-controller-manager/templates/service-sm.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ metadata:
55
labels:
66
{{- include "occm.labels" . | nindent 4 }}
77
name: {{ include "occm.name" . }}
8+
namespace: {{ .Release.Namespace }}
89
spec:
910
ports:
1011
- name: http

charts/openstack-cloud-controller-manager/templates/serviceaccount.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ apiVersion: v1
22
kind: ServiceAccount
33
metadata:
44
name: openstack-cloud-controller-manager
5+
namespace: {{ .Release.Namespace }}

charts/openstack-cloud-controller-manager/templates/servicemonitor.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ metadata:
55
labels:
66
{{- include "occm.labels" . | nindent 4 }}
77
name: {{ include "occm.name" . }}
8+
namespace: {{ .Release.Namespace }}
89
spec:
910
endpoints:
1011
- bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token

docs/openstack-cloud-controller-manager/expose-applications-using-loadbalancer-type-service.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ Request Body:
114114

115115
VIP subnet ID of load balancer created.
116116

117+
- `loadbalancer.openstack.org/member-subnet-id`
118+
119+
Member subnet ID of the load balancer created.
120+
117121
- `loadbalancer.openstack.org/network-id`
118122

119123
The network ID which will allocate virtual IP for loadbalancer.

docs/openstack-cloud-controller-manager/using-openstack-cloud-controller-manager.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,10 @@ Although the openstack-cloud-controller-manager was initially implemented with N
200200
Optional. If specified, only "v2" is supported.
201201
202202
* `subnet-id`
203-
ID of the Neutron subnet on which to create load balancer VIP, this ID is also used to create pool members.
203+
ID of the Neutron subnet on which to create load balancer VIP. This ID is also used to create pool members, if `member-subnet-id` is not set.
204+
205+
* `member-subnet-id`
206+
ID of the Neutron network on which to create the members of the load balancer. The load balancer gets another network port on this subnet. Defaults to `subnet-id` if not set.
204207
205208
* `network-id`
206209
ID of the Neutron network on which to create load balancer VIP, not needed if `subnet-id` is set.
@@ -243,6 +246,7 @@ Although the openstack-cloud-controller-manager was initially implemented with N
243246
* floating-subnet-tags. The same with `floating-subnet-tags` option above.
244247
* network-id. The same with `network-id` option above.
245248
* subnet-id. The same with `subnet-id` option above.
249+
* member-subnet-id. The same with `member-subnet-id` option above.
246250
247251
* `enable-ingress-hostname`
248252
@@ -285,6 +289,10 @@ NOTE:
285289
286290
Not all OpenStack clouds provide both configuration drive and metadata service though and only one or the other may be available which is why the default is to check both. Especially, the metadata on the config drive may grow stale over time, whereas the metadata service always provides the most up to date data.
287291
292+
### Multi region support (alpha)
293+
294+
* environment variable `OS_CCM_REGIONAL` is set to `true` - allow CCM to set ProviderID with region name `${ProviderName}://${REGION}/${instance-id}`. Default: false.
295+
288296
## Exposing applications using services of LoadBalancer type
289297
290298
Refer to [Exposing applications using services of LoadBalancer type](./expose-applications-using-loadbalancer-type-service.md)

pkg/ingress/utils/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func stringSlicesEqual(x, y []string) bool {
7474

7575
// GetNodeID get instance ID from the Node spec.
7676
func GetNodeID(node *apiv1.Node) (string, error) {
77-
var providerIDRegexp = regexp.MustCompile(`^openstack:///([^/]+)$`)
77+
var providerIDRegexp = regexp.MustCompile(`^openstack://(?:[^/]*)/([^/]+)$`)
7878

7979
matches := providerIDRegexp.FindStringSubmatch(node.Spec.ProviderID)
8080
if len(matches) != 2 {

pkg/openstack/instances.go

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"net"
23-
"os"
23+
sysos "os"
2424
"regexp"
2525
"sort"
2626
"strings"
@@ -46,13 +46,16 @@ import (
4646

4747
// Instances encapsulates an implementation of Instances for OpenStack.
4848
type Instances struct {
49-
compute *gophercloud.ServiceClient
50-
opts metadata.Opts
51-
networkingOpts NetworkingOpts
49+
compute *gophercloud.ServiceClient
50+
region string
51+
regionProviderID bool
52+
opts metadata.Opts
53+
networkingOpts NetworkingOpts
5254
}
5355

5456
const (
55-
instanceShutoff = "SHUTOFF"
57+
instanceShutoff = "SHUTOFF"
58+
RegionalProviderIDEnv = "OS_CCM_REGIONAL"
5659
)
5760

5861
var _ cloudprovider.Instances = &Instances{}
@@ -77,10 +80,17 @@ func (os *OpenStack) instances() (*Instances, bool) {
7780
return nil, false
7881
}
7982

83+
regionalProviderID := false
84+
if isRegionalProviderID := sysos.Getenv(RegionalProviderIDEnv); isRegionalProviderID == "true" {
85+
regionalProviderID = true
86+
}
87+
8088
return &Instances{
81-
compute: compute,
82-
opts: os.metadataOpts,
83-
networkingOpts: os.networkingOpts,
89+
compute: compute,
90+
region: os.epOpts.Region,
91+
regionProviderID: regionalProviderID,
92+
opts: os.metadataOpts,
93+
networkingOpts: os.networkingOpts,
8494
}, true
8595
}
8696

@@ -128,14 +138,19 @@ func (i *Instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v
128138
// This method will not be called from the node that is requesting this ID. i.e. metadata service
129139
// and other local methods cannot be used here
130140
func (i *Instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) {
131-
klog.V(4).Infof("NodeAddressesByProviderID (%v) called", providerID)
132-
133-
instanceID, err := instanceIDFromProviderID(providerID)
141+
klog.V(4).Infof("NodeAddressesByProviderID(%v) called", providerID)
134142

143+
instanceID, instanceRegion, err := instanceIDFromProviderID(providerID)
135144
if err != nil {
136145
return []v1.NodeAddress{}, err
137146
}
138147

148+
if instanceRegion != "" && instanceRegion != i.region {
149+
klog.V(4).Infof("NodeAddressesByProviderID(%v) has foreign region %v, skipped", providerID, instanceRegion)
150+
151+
return []v1.NodeAddress{}, nil
152+
}
153+
139154
mc := metrics.NewMetricContext("server", "get")
140155
server, err := servers.Get(i.compute, instanceID).Extract()
141156

@@ -162,12 +177,18 @@ func (i *Instances) InstanceExists(ctx context.Context, node *v1.Node) (bool, er
162177
return i.InstanceExistsByProviderID(ctx, node.Spec.ProviderID)
163178
}
164179

165-
func instanceExistsByProviderID(ctx context.Context, compute *gophercloud.ServiceClient, providerID string) (bool, error) {
166-
instanceID, err := instanceIDFromProviderID(providerID)
180+
func instanceExistsByProviderID(ctx context.Context, compute *gophercloud.ServiceClient, providerID string, region string) (bool, error) {
181+
instanceID, instanceRegion, err := instanceIDFromProviderID(providerID)
167182
if err != nil {
168183
return false, err
169184
}
170185

186+
if instanceRegion != "" && instanceRegion != region {
187+
klog.V(4).Infof("instanceExistsByProviderID(%v) has foreign region %v, skipped", providerID, instanceRegion)
188+
189+
return true, nil
190+
}
191+
171192
mc := metrics.NewMetricContext("server", "get")
172193
_, err = servers.Get(compute, instanceID).Extract()
173194
if mc.ObserveRequest(err) != nil {
@@ -183,7 +204,7 @@ func instanceExistsByProviderID(ctx context.Context, compute *gophercloud.Servic
183204
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists.
184205
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
185206
func (i *Instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
186-
return instanceExistsByProviderID(ctx, i.compute, providerID)
207+
return instanceExistsByProviderID(ctx, i.compute, providerID, i.region)
187208
}
188209

189210
// InstanceShutdown returns true if the instances is in safe state to detach volumes.
@@ -192,12 +213,16 @@ func (i *Instances) InstanceShutdown(ctx context.Context, node *v1.Node) (bool,
192213
return i.InstanceShutdownByProviderID(ctx, node.Spec.ProviderID)
193214
}
194215

195-
func instanceShutdownByProviderID(ctx context.Context, compute *gophercloud.ServiceClient, providerID string) (bool, error) {
196-
instanceID, err := instanceIDFromProviderID(providerID)
216+
func instanceShutdownByProviderID(ctx context.Context, compute *gophercloud.ServiceClient, providerID string, region string) (bool, error) {
217+
instanceID, instanceRegion, err := instanceIDFromProviderID(providerID)
197218
if err != nil {
198219
return false, err
199220
}
200221

222+
if instanceRegion != "" && instanceRegion != region {
223+
return false, fmt.Errorf("ProviderID \"%s\" didn't match supported region \"%s\"", providerID, region)
224+
}
225+
201226
mc := metrics.NewMetricContext("server", "get")
202227
server, err := servers.Get(compute, instanceID).Extract()
203228
if mc.ObserveRequest(err) != nil {
@@ -214,16 +239,20 @@ func instanceShutdownByProviderID(ctx context.Context, compute *gophercloud.Serv
214239
// InstanceShutdownByProviderID returns true if the instances is in safe state to detach volumes.
215240
// It is the only state, where volumes can be detached immediately.
216241
func (i *Instances) InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) {
217-
return instanceShutdownByProviderID(ctx, i.compute, providerID)
242+
return instanceShutdownByProviderID(ctx, i.compute, providerID, i.region)
218243
}
219244

220245
// InstanceMetadata returns metadata of the specified instance.
221246
func (i *Instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
222-
instanceID, err := instanceIDFromProviderID(node.Spec.ProviderID)
247+
instanceID, instanceRegion, err := instanceIDFromProviderID(node.Spec.ProviderID)
223248
if err != nil {
224249
return nil, err
225250
}
226251

252+
if instanceRegion != "" && instanceRegion != i.region {
253+
return nil, fmt.Errorf("ProviderID \"%s\" didn't match supported region \"%s\"", node.Spec.ProviderID, i.region)
254+
}
255+
227256
mc := metrics.NewMetricContext("server", "get")
228257
srv, err := servers.Get(i.compute, instanceID).Extract()
229258
if mc.ObserveRequest(err) != nil {
@@ -260,6 +289,11 @@ func (i *Instances) InstanceID(ctx context.Context, name types.NodeName) (string
260289
}
261290
return "", err
262291
}
292+
293+
if i.regionProviderID {
294+
return i.region + "/" + srv.ID, nil
295+
}
296+
263297
// In the future it is possible to also return an endpoint as:
264298
// <endpoint>/<instanceid>
265299
return "/" + srv.ID, nil
@@ -269,12 +303,15 @@ func (i *Instances) InstanceID(ctx context.Context, name types.NodeName) (string
269303
// This method will not be called from the node that is requesting this ID. i.e. metadata service
270304
// and other local methods cannot be used here
271305
func (i *Instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
272-
instanceID, err := instanceIDFromProviderID(providerID)
273-
306+
instanceID, instanceRegion, err := instanceIDFromProviderID(providerID)
274307
if err != nil {
275308
return "", err
276309
}
277310

311+
if instanceRegion != "" && instanceRegion != i.region {
312+
return "", fmt.Errorf("ProviderID \"%s\" didn't match supported region \"%s\"", providerID, i.region)
313+
}
314+
278315
mc := metrics.NewMetricContext("server", "get")
279316
server, err := servers.Get(i.compute, instanceID).Extract()
280317

@@ -335,23 +372,24 @@ func isValidLabelValue(v string) bool {
335372
}
336373

337374
// If Instances.InstanceID or cloudprovider.GetInstanceProviderID is changed, the regexp should be changed too.
338-
var providerIDRegexp = regexp.MustCompile(`^` + ProviderName + `:///([^/]+)$`)
375+
var providerIDRegexp = regexp.MustCompile(`^` + ProviderName + `://([^/]*)/([^/]+)$`)
339376

340377
// instanceIDFromProviderID splits a provider's id and return instanceID.
341-
// A providerID is build out of '${ProviderName}:///${instance-id}'which contains ':///'.
378+
// A providerID is build out of '${ProviderName}:///${instance-id}' which contains ':///'.
379+
// or '${ProviderName}://${region}/${instance-id}' which contains '://'.
342380
// See cloudprovider.GetInstanceProviderID and Instances.InstanceID.
343-
func instanceIDFromProviderID(providerID string) (instanceID string, err error) {
381+
func instanceIDFromProviderID(providerID string) (instanceID string, region string, err error) {
344382

345383
// https://github.com/kubernetes/kubernetes/issues/85731
346384
if providerID != "" && !strings.Contains(providerID, "://") {
347385
providerID = ProviderName + "://" + providerID
348386
}
349387

350388
matches := providerIDRegexp.FindStringSubmatch(providerID)
351-
if len(matches) != 2 {
352-
return "", fmt.Errorf("ProviderID \"%s\" didn't match expected format \"openstack:///InstanceID\"", providerID)
389+
if len(matches) != 3 {
390+
return "", "", fmt.Errorf("ProviderID \"%s\" didn't match expected format \"openstack://region/InstanceID\"", providerID)
353391
}
354-
return matches[1], nil
392+
return matches[2], matches[1], nil
355393
}
356394

357395
// AddToNodeAddresses appends the NodeAddresses to the passed-by-pointer slice,
@@ -414,7 +452,7 @@ func readInstanceID(searchOrder string) (string, error) {
414452

415453
// Try to find instance ID on the local filesystem (created by cloud-init)
416454
const instanceIDFile = "/var/lib/cloud/data/instance-id"
417-
idBytes, err := os.ReadFile(instanceIDFile)
455+
idBytes, err := sysos.ReadFile(instanceIDFile)
418456
if err == nil {
419457
instanceID := string(idBytes)
420458
instanceID = strings.TrimSpace(instanceID)

0 commit comments

Comments
 (0)