Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[occm] Multi region openstack cluster #2595

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ The options in `Global` section are used for openstack-cloud-controller-manager
* `password`
Keystone user password. If you are using [Keystone application credential](https://docs.openstack.org/keystone/latest/user/application_credentials.html), this option is not required.
* `region`
Required. Keystone region name.
Required. Keystone region name. The name of region will be set in the `topology.kubernetes.io/region` label of the node.
* `regions`
Optional. Keystone region name, which is used to specify regions for the cloud provider where the instance is running. Can be specified multiple times.The region name may or may not be the same as the region name in the `region` option. They merge together at runtime.
* `domain-id`
Keystone user domain ID. If you are using [Keystone application credential](https://docs.openstack.org/keystone/latest/user/application_credentials.html), this option is not required.
* `domain-name`
Expand Down Expand Up @@ -317,7 +319,7 @@ Although the openstack-cloud-controller-manager was initially implemented with N
call](https://docs.openstack.org/api-ref/load-balancer/v2/?expanded=create-a-load-balancer-detail#creating-a-fully-populated-load-balancer).
Setting this option to true will create loadbalancers using serial API calls which first create an unpopulated
loadbalancer, then populate its listeners, pools and members. This is a compatibility option at the expense of
increased load on the OpenStack API. Default: false
increased load on the OpenStack API. Default: false

NOTE:

Expand Down
17 changes: 17 additions & 0 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"fmt"
"net/http"
"runtime"
"slices"
"strings"

"github.com/gophercloud/gophercloud/v2"
Expand Down Expand Up @@ -53,6 +54,7 @@ type AuthOpts struct {
UserDomainID string `gcfg:"user-domain-id" mapstructure:"user-domain-id" name:"os-userDomainID" value:"optional"`
UserDomainName string `gcfg:"user-domain-name" mapstructure:"user-domain-name" name:"os-userDomainName" value:"optional"`
Region string `name:"os-region"`
Regions []string `name:"os-regions" value:"optional"`
EndpointType gophercloud.Availability `gcfg:"os-endpoint-type" mapstructure:"os-endpoint-type" name:"os-endpointType" value:"optional"`
CAFile string `gcfg:"ca-file" mapstructure:"ca-file" name:"os-certAuthorityPath" value:"optional"`
TLSInsecure string `gcfg:"tls-insecure" mapstructure:"tls-insecure" name:"os-TLSInsecure" value:"optional" matches:"^true|false$"`
Expand Down Expand Up @@ -87,6 +89,7 @@ func LogCfg(authOpts AuthOpts) {
klog.V(5).Infof("UserDomainID: %s", authOpts.UserDomainID)
klog.V(5).Infof("UserDomainName: %s", authOpts.UserDomainName)
klog.V(5).Infof("Region: %s", authOpts.Region)
klog.V(5).Infof("Regions: %s", authOpts.Regions)
klog.V(5).Infof("EndpointType: %s", authOpts.EndpointType)
klog.V(5).Infof("CAFile: %s", authOpts.CAFile)
klog.V(5).Infof("CertFile: %s", authOpts.CertFile)
Expand Down Expand Up @@ -232,6 +235,20 @@ func ReadClouds(authOpts *AuthOpts) error {
authOpts.ApplicationCredentialName = replaceEmpty(authOpts.ApplicationCredentialName, cloud.AuthInfo.ApplicationCredentialName)
authOpts.ApplicationCredentialSecret = replaceEmpty(authOpts.ApplicationCredentialSecret, cloud.AuthInfo.ApplicationCredentialSecret)

regions := strings.Split(authOpts.Region, ",")
if len(regions) > 1 {
authOpts.Region = regions[0]
}

for _, r := range cloud.Regions {
// Support only single auth section in clouds.yaml
if r.Values.AuthInfo == nil && r.Name != authOpts.Region && !slices.Contains(regions, r.Name) {
regions = append(regions, r.Name)
}
}

authOpts.Regions = regions

return nil
}

Expand Down
12 changes: 11 additions & 1 deletion pkg/csi/cinder/openstack/openstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"net/http"
"os"
"slices"

"github.com/gophercloud/gophercloud/v2"
"github.com/gophercloud/gophercloud/v2/openstack"
Expand Down Expand Up @@ -126,7 +127,7 @@ func GetConfigFromFiles(configFilePaths []string) (Config, error) {
}
}

for _, global := range cfg.Global {
for idx, global := range cfg.Global {
// Update the config with data from clouds.yaml if UseClouds is enabled
if global.UseClouds {
if global.CloudsFile != "" {
Expand All @@ -138,6 +139,15 @@ func GetConfigFromFiles(configFilePaths []string) (Config, error) {
}
klog.V(5).Infof("Credentials are loaded from %s:", global.CloudsFile)
}

regions := []string{global.Region}
for _, region := range cfg.Global[idx].Regions {
if !slices.Contains(regions, region) {
regions = append(regions, region)
}
}

cfg.Global[idx].Regions = regions
}

return cfg, nil
Expand Down
9 changes: 9 additions & 0 deletions pkg/csi/cinder/openstack/openstack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ tenant-id=` + fakeTenantID + `
domain-id=` + fakeDomainID + `
ca-file=` + fakeCAfile + `
region=` + fakeRegion + `
regions=` + fakeRegion + `
[Global "cloud2"]
username=` + fakeUserName_cloud2 + `
password=` + fakePassword_cloud2 + `
Expand All @@ -76,6 +77,8 @@ tenant-id=` + fakeTenantID_cloud2 + `
domain-id=` + fakeDomainID_cloud2 + `
ca-file=` + fakeCAfile_cloud2 + `
region=` + fakeRegion_cloud2 + `
regions=` + fakeRegion_cloud2 + `
regions=` + fakeRegion_cloud2 + `
[Global "cloud3"]
username=` + fakeUserName_cloud3 + `
password=` + fakePassword_cloud3 + `
Expand Down Expand Up @@ -112,6 +115,7 @@ rescan-on-resize=true`
CAFile: fakeCAfile,
TenantID: fakeTenantID,
Region: fakeRegion,
Regions: []string{fakeRegion},
}
expectedOpts.Global["cloud2"] = &client.AuthOpts{
Username: fakeUserName_cloud2,
Expand All @@ -121,6 +125,7 @@ rescan-on-resize=true`
CAFile: fakeCAfile_cloud2,
TenantID: fakeTenantID_cloud2,
Region: fakeRegion_cloud2,
Regions: []string{fakeRegion_cloud2},
}
expectedOpts.Global["cloud3"] = &client.AuthOpts{
Username: fakeUserName_cloud3,
Expand All @@ -130,6 +135,7 @@ rescan-on-resize=true`
CAFile: fakeCAfile_cloud3,
TenantID: fakeTenantID_cloud3,
Region: fakeRegion_cloud3,
Regions: []string{fakeRegion_cloud3},
}

expectedOpts.BlockStorage.RescanOnResize = true
Expand Down Expand Up @@ -224,6 +230,7 @@ rescan-on-resize=true`
CAFile: fakeCAfile,
TenantID: fakeTenantID,
Region: fakeRegion,
Regions: []string{fakeRegion},
EndpointType: gophercloud.AvailabilityPublic,
UseClouds: true,
CloudsFile: wd + "/fixtures/clouds.yaml",
Expand All @@ -237,6 +244,7 @@ rescan-on-resize=true`
CAFile: fakeCAfile_cloud2,
TenantID: fakeTenantID_cloud2,
Region: fakeRegion_cloud2,
Regions: []string{fakeRegion_cloud2},
EndpointType: gophercloud.AvailabilityPublic,
UseClouds: true,
CloudsFile: wd + "/fixtures/clouds.yaml",
Expand All @@ -250,6 +258,7 @@ rescan-on-resize=true`
CAFile: fakeCAfile_cloud3,
TenantID: fakeTenantID_cloud3,
Region: fakeRegion_cloud3,
Regions: []string{fakeRegion_cloud3},
EndpointType: gophercloud.AvailabilityPublic,
UseClouds: true,
CloudsFile: wd + "/fixtures/clouds.yaml",
Expand Down
Loading