terraform/vendor/github.com/gophercloud/utils/openstack/clientconfig/utils.go

156 lines
4.2 KiB
Go

package clientconfig
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"reflect"
)
// defaultIfEmpty is a helper function to make it cleaner to set default value
// for strings.
func defaultIfEmpty(value string, defaultValue string) string {
if value == "" {
return defaultValue
}
return value
}
// mergeCLouds merges two Clouds recursively (the AuthInfo also gets merged).
// In case both Clouds define a value, the value in the 'override' cloud takes precedence
func mergeClouds(override, cloud interface{}) (*Cloud, error) {
overrideJson, err := json.Marshal(override)
if err != nil {
return nil, err
}
cloudJson, err := json.Marshal(cloud)
if err != nil {
return nil, err
}
var overrideInterface interface{}
err = json.Unmarshal(overrideJson, &overrideInterface)
if err != nil {
return nil, err
}
var cloudInterface interface{}
err = json.Unmarshal(cloudJson, &cloudInterface)
if err != nil {
return nil, err
}
var mergedCloud Cloud
mergedInterface := mergeInterfaces(overrideInterface, cloudInterface)
mergedJson, err := json.Marshal(mergedInterface)
json.Unmarshal(mergedJson, &mergedCloud)
return &mergedCloud, nil
}
// merges two interfaces. In cases where a value is defined for both 'overridingInterface' and
// 'inferiorInterface' the value in 'overridingInterface' will take precedence.
func mergeInterfaces(overridingInterface, inferiorInterface interface{}) interface{} {
switch overriding := overridingInterface.(type) {
case map[string]interface{}:
interfaceMap, ok := inferiorInterface.(map[string]interface{})
if !ok {
return overriding
}
for k, v := range interfaceMap {
if overridingValue, ok := overriding[k]; ok {
overriding[k] = mergeInterfaces(overridingValue, v)
} else {
overriding[k] = v
}
}
case []interface{}:
list, ok := inferiorInterface.([]interface{})
if !ok {
return overriding
}
for i := range list {
overriding = append(overriding, list[i])
}
return overriding
case nil:
// mergeClouds(nil, map[string]interface{...}) -> map[string]interface{...}
v, ok := inferiorInterface.(map[string]interface{})
if ok {
return v
}
}
// We don't want to override with empty values
if reflect.DeepEqual(overridingInterface, nil) || reflect.DeepEqual(reflect.Zero(reflect.TypeOf(overridingInterface)).Interface(), overridingInterface) {
return inferiorInterface
} else {
return overridingInterface
}
}
// findAndReadCloudsYAML attempts to locate a clouds.yaml file in the following
// locations:
//
// 1. OS_CLIENT_CONFIG_FILE
// 2. Current directory.
// 3. unix-specific user_config_dir (~/.config/openstack/clouds.yaml)
// 4. unix-specific site_config_dir (/etc/openstack/clouds.yaml)
//
// If found, the contents of the file is returned.
func findAndReadCloudsYAML() ([]byte, error) {
// OS_CLIENT_CONFIG_FILE
if v := os.Getenv("OS_CLIENT_CONFIG_FILE"); v != "" {
if ok := fileExists(v); ok {
return ioutil.ReadFile(v)
}
}
return findAndReadYAML("clouds.yaml")
}
func findAndReadPublicCloudsYAML() ([]byte, error) {
return findAndReadYAML("clouds-public.yaml")
}
func findAndReadSecureCloudsYAML() ([]byte, error) {
return findAndReadYAML("secure.yaml")
}
func findAndReadYAML(yamlFile string) ([]byte, error) {
// current directory
cwd, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("unable to determine working directory: %s", err)
}
filename := filepath.Join(cwd, yamlFile)
if ok := fileExists(filename); ok {
return ioutil.ReadFile(filename)
}
// unix user config directory: ~/.config/openstack.
if currentUser, err := user.Current(); err == nil {
homeDir := currentUser.HomeDir
if homeDir != "" {
filename := filepath.Join(homeDir, ".config/openstack/"+yamlFile)
if ok := fileExists(filename); ok {
return ioutil.ReadFile(filename)
}
}
}
// unix-specific site config directory: /etc/openstack.
if ok := fileExists("/etc/openstack/" + yamlFile); ok {
return ioutil.ReadFile("/etc/openstack/" + yamlFile)
}
return nil, fmt.Errorf("no " + yamlFile + " file found")
}
// fileExists checks for the existence of a file at a given location.
func fileExists(filename string) bool {
if _, err := os.Stat(filename); err == nil {
return true
}
return false
}