Skip to content

Commit

Permalink
[cinder-csi-plugin] Allow --cloud-config to be given multiple times
Browse files Browse the repository at this point in the history
This change allows cinder-csi-plugin to be invoked with multiple config
files. These will be parsed sequentially in the order specified. Values
in later config files override values in earlier config files.

This makes 'layered' configurations simpler to manage. For example a
base configuration containing authentication information and a per-node
override configuration which applies only to a single node. Keeping
these in separate files simplifies the task of changing the base
configuration for all nodes.
  • Loading branch information
mdbooth committed Apr 12, 2021
1 parent 4ea5df6 commit f86cfc3
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 29 deletions.
4 changes: 2 additions & 2 deletions cmd/cinder-csi-plugin/main.go
Expand Up @@ -34,7 +34,7 @@ import (
var (
endpoint string
nodeID string
cloudconfig string
cloudconfig []string
cluster string
)

Expand Down Expand Up @@ -80,7 +80,7 @@ func main() {
cmd.PersistentFlags().StringVar(&endpoint, "endpoint", "", "CSI endpoint")
cmd.MarkPersistentFlagRequired("endpoint")

cmd.PersistentFlags().StringVar(&cloudconfig, "cloud-config", "", "CSI driver cloud config")
cmd.PersistentFlags().StringSliceVar(&cloudconfig, "cloud-config", nil, "CSI driver cloud config")
cmd.MarkPersistentFlagRequired("cloud-config")

cmd.PersistentFlags().StringVar(&cluster, "cluster", "", "The identifier of the cluster that the plugin is running in.")
Expand Down
43 changes: 24 additions & 19 deletions pkg/csi/cinder/openstack/openstack.go
Expand Up @@ -90,28 +90,33 @@ func logcfg(cfg Config) {
klog.Infof("Block storage opts: %v", cfg.BlockStorage)
}

// GetConfigFromFile retrieves config options from file
func GetConfigFromFile(configFilePath string) (Config, error) {
// GetConfigFromFiles retrieves config options from file
func GetConfigFromFiles(configFilePaths []string) (Config, error) {
var cfg Config
config, err := os.Open(configFilePath)
if err != nil {
klog.Errorf("Failed to open OpenStack configuration file: %v", err)
return cfg, err
}
defer config.Close()

err = gcfg.FatalOnly(gcfg.ReadInto(&cfg, config))
if err != nil {
klog.Errorf("Failed to read OpenStack configuration file: %v", err)
return cfg, err
// Read all specified config files in order. Values from later config files
// will overwrite values from earlier ones.
for _, configFilePath := range configFilePaths {
config, err := os.Open(configFilePath)
if err != nil {
klog.Errorf("Failed to open OpenStack configuration file: %v", err)
return cfg, err
}
defer config.Close()

err = gcfg.FatalOnly(gcfg.ReadInto(&cfg, config))
if err != nil {
klog.Errorf("Failed to read OpenStack configuration file: %v", err)
return cfg, err
}
}

// Update the config with data from clouds.yaml if UseClouds is enabled
if cfg.Global.UseClouds {
if cfg.Global.CloudsFile != "" {
os.Setenv("OS_CLIENT_CONFIG_FILE", cfg.Global.CloudsFile)
}
err = client.ReadClouds(&cfg.Global)
err := client.ReadClouds(&cfg.Global)
if err != nil {
return cfg, err
}
Expand All @@ -124,20 +129,20 @@ func GetConfigFromFile(configFilePath string) (Config, error) {
const defaultMaxVolAttachLimit int64 = 256

var OsInstance IOpenStack = nil
var configFile = "/etc/cloud.conf"
var configFiles = []string{"/etc/cloud.conf"}
var cfg Config

func InitOpenStackProvider(cfgFile string) {
configFile = cfgFile
klog.V(2).Infof("InitOpenStackProvider configFile: %s", configFile)
func InitOpenStackProvider(cfgFiles []string) {
configFiles = cfgFiles
klog.V(2).Infof("InitOpenStackProvider configFiles: %s", configFiles)
}

// CreateOpenStackProvider creates Openstack Instance
func CreateOpenStackProvider() (IOpenStack, error) {
// Get config from file
cfg, err := GetConfigFromFile(configFile)
cfg, err := GetConfigFromFiles(configFiles)
if err != nil {
klog.Errorf("GetConfigFromFile %s failed with error: %v", configFile, err)
klog.Errorf("GetConfigFromFiles %s failed with error: %v", configFiles, err)
return nil, err
}
logcfg(cfg)
Expand Down
48 changes: 40 additions & 8 deletions pkg/csi/cinder/openstack/openstack_test.go
Expand Up @@ -28,6 +28,7 @@ import (
)

var fakeFileName = "cloud.conf"
var fakeOverrideFileName = "cloud-override.conf"
var fakeUserName = "user"
var fakePassword = "pass"
var fakeAuthUrl = "https://169.254.169.254/identity/v3"
Expand All @@ -37,8 +38,8 @@ var fakeRegion = "RegionOne"
var fakeCAfile = "fake-ca.crt"
var fakeCloudName = "openstack"

// Test GetConfigFromFile
func TestGetConfigFromFile(t *testing.T) {
// Test GetConfigFromFiles
func TestGetConfigFromFiles(t *testing.T) {
// init file
var fakeFileContent = `
[Global]
Expand Down Expand Up @@ -76,10 +77,41 @@ rescan-on-resize=true`
expectedOpts.Global.Region = fakeRegion
expectedOpts.BlockStorage.RescanOnResize = true

// Invoke GetConfigFromFile
actualAuthOpts, err := GetConfigFromFile(fakeFileName)
// Invoke GetConfigFromFiles
actualAuthOpts, err := GetConfigFromFiles([]string{fakeFileName})
if err != nil {
t.Errorf("failed to GetConfigFromFile: %v", err)
t.Errorf("failed to GetConfigFromFiles: %v", err)
}

// Assert
assert.Equal(expectedOpts, actualAuthOpts)

// Create an override config file
var fakeOverrideFileContent = `
[BlockStorage]
rescan-on-resize=false`

f, err = os.Create(fakeOverrideFileName)
if err != nil {
t.Errorf("failed to create file: %v", err)
}

_, err = f.WriteString(fakeOverrideFileContent)
f.Close()
if err != nil {
t.Errorf("failed to write file: %v", err)
}
defer os.Remove(fakeOverrideFileName)

// expectedOpts should reflect the overriden value of rescan-on-resize. All
// other values should be the same as before because they come from the
// 'base' configuration
expectedOpts.BlockStorage.RescanOnResize = false

// Invoke GetConfigFromFiles with both the base and override config files
actualAuthOpts, err = GetConfigFromFiles([]string{fakeFileName, fakeOverrideFileName})
if err != nil {
t.Errorf("failed to GetConfigFromFiles: %v", err)
}

// Assert
Expand Down Expand Up @@ -130,10 +162,10 @@ rescan-on-resize=true`
expectedOpts.Global.Cloud = fakeCloudName
expectedOpts.BlockStorage.RescanOnResize = true

// Invoke GetConfigFromFile
actualAuthOpts, err := GetConfigFromFile(fakeFileName)
// Invoke GetConfigFromFiles
actualAuthOpts, err := GetConfigFromFiles([]string{fakeFileName})
if err != nil {
t.Errorf("failed to GetConfigFromFile: %v", err)
t.Errorf("failed to GetConfigFromFiles: %v", err)
}

// Assert
Expand Down

0 comments on commit f86cfc3

Please sign in to comment.