Skip to content

Commit d29469c

Browse files
committed
Add support to pass env vars to in addition to args to configure cmk
1 parent fad5ae6 commit d29469c

4 files changed

Lines changed: 78 additions & 10 deletions

File tree

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,27 @@ If cloudmonkey is being upgraded from a version lower than v6.0.0, it must be no
7979
that the cloudmonkey configuration path is changed from `~/.cloudmonkey/config` to
8080
`~/.cmk/config` and a default `localcloud` profile is created. One must first set up basic configurations such as apikey/secretkey/username/password/url for the required profile(s) as required
8181

82+
### Environment Variables
83+
84+
`cmk` supports environment variables that mirror its CLI flags. CLI flags take
85+
precedence over environment variables, which take precedence over values in the
86+
config file.
87+
88+
| Environment variable | Flag | Description |
89+
|----------------------|------|-------------|
90+
| `CMK_CONFIG` | `-c` | Config file path |
91+
| `CMK_PROFILE` | `-p` | Server profile |
92+
| `CMK_URL` | `-u` | CloudStack's API endpoint URL |
93+
| `CMK_API_KEY` | `-k` | CloudStack user's API key |
94+
| `CMK_SECRET_KEY` | `-s` | CloudStack user's secret key |
95+
| `CMK_OUTPUT` | `-o` | API response output format |
96+
| `CMK_DEBUG` | `-d` | Enable debug mode when set to a boolean true value (e.g. `true` or `1`) |
97+
98+
`CMK_CONFIG` must point to an existing config file, and `CMK_PROFILE` must name
99+
an existing profile in the config; otherwise `cmk` exits with an error. A profile
100+
selected via `CMK_PROFILE` applies only to that invocation and is not persisted
101+
to the config file.
102+
82103
### License
83104

84105
Licensed to the Apache Software Foundation (ASF) under one

cmd/command.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ CloudMonkey (cmk) 🐵 is a command line interface for Apache CloudStack.
6565
Allowed flags:
6666
-h Show this help message or API doc when specified after an API
6767
-v Print version
68-
-o API response output format: json, text, table, column, csv
69-
-p Server profile
70-
-d Enable debug mode
71-
-c Different config file path
72-
-u CloudStack's API endpoint URL
73-
-s CloudStack user's secret Key
74-
-k CloudStack user's API Key
68+
-o API response output format: json, text, table, column, csv (env: CMK_OUTPUT)
69+
-p Server profile (env: CMK_PROFILE)
70+
-d Enable debug mode (env: CMK_DEBUG)
71+
-c Different config file path (env: CMK_CONFIG)
72+
-u CloudStack's API endpoint URL (env: CMK_URL)
73+
-s CloudStack user's secret key (env: CMK_SECRET_KEY)
74+
-k CloudStack user's API key (env: CMK_API_KEY)
75+
76+
CLI flags take precedence over their environment variables.
7577
7678
Default commands:
7779
%s

cmk.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"flag"
2222
"fmt"
2323
"os"
24+
"strconv"
2425
"strings"
2526

2627
"github.com/apache/cloudstack-cloudmonkey/cli"
@@ -48,11 +49,36 @@ func main() {
4849
profile := flag.String("p", "", "server profile")
4950
configFilePath := flag.String("c", "", "config file path")
5051
acsURL := flag.String("u", config.DefaultACSAPIEndpoint, "cloudStack's API endpoint URL")
51-
apiKey := flag.String("k", "", "cloudStack user's API Key")
52-
secretKey := flag.String("s", "", "cloudStack user's secret Key")
52+
apiKey := flag.String("k", "", "cloudStack user's API key")
53+
secretKey := flag.String("s", "", "cloudStack user's secret key")
5354
flag.Parse()
5455
args := flag.Args()
5556

57+
// Fall back to environment variables for flags not passed on the
58+
// command line; CLI flags take precedence over environment variables.
59+
passedFlags := make(map[string]bool)
60+
flag.Visit(func(f *flag.Flag) {
61+
passedFlags[f.Name] = true
62+
})
63+
fallbackToEnvVar := func(flagName string, flagValue *string, envVar string) {
64+
if !passedFlags[flagName] {
65+
if value := os.Getenv(envVar); value != "" {
66+
*flagValue = value
67+
}
68+
}
69+
}
70+
fallbackToEnvVar("c", configFilePath, config.ConfigFileEnvVar)
71+
fallbackToEnvVar("p", profile, config.ProfileEnvVar)
72+
fallbackToEnvVar("u", acsURL, config.URLEnvVar)
73+
fallbackToEnvVar("k", apiKey, config.APIKeyEnvVar)
74+
fallbackToEnvVar("s", secretKey, config.SecretKeyEnvVar)
75+
fallbackToEnvVar("o", outputFormat, config.OutputEnvVar)
76+
if !passedFlags["d"] {
77+
if value, err := strconv.ParseBool(strings.TrimSpace(os.Getenv(config.DebugEnvVar))); err == nil {
78+
*debug = value
79+
}
80+
}
81+
5682
cfg := config.NewConfig(configFilePath)
5783

5884
if *showVersion {

config/config.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,25 @@ var nonEmptyConfigKeys = map[string]bool{
5656
// DefaultACSAPIEndpoint is the default API endpoint for CloudStack.
5757
const DefaultACSAPIEndpoint = "http://localhost:8080/client/api"
5858

59+
// Environment variables that mirror CLI flags; flags take precedence.
60+
const (
61+
// ConfigFileEnvVar sets the config file path when -c is not passed
62+
ConfigFileEnvVar = "CMK_CONFIG"
63+
// ProfileEnvVar sets the server profile when -p is not passed
64+
ProfileEnvVar = "CMK_PROFILE"
65+
// URLEnvVar sets CloudStack's API endpoint URL when -u is not passed
66+
URLEnvVar = "CMK_URL"
67+
// APIKeyEnvVar sets CloudStack user's API key when -k is not passed
68+
APIKeyEnvVar = "CMK_API_KEY"
69+
// SecretKeyEnvVar sets CloudStack user's secret key when -s is not passed
70+
SecretKeyEnvVar = "CMK_SECRET_KEY"
71+
// OutputEnvVar sets the API response output format when -o is not passed
72+
OutputEnvVar = "CMK_OUTPUT"
73+
// DebugEnvVar enables debug mode when set to a boolean true value
74+
// (e.g. true or 1) and -d is not passed
75+
DebugEnvVar = "CMK_DEBUG"
76+
)
77+
5978
// ServerProfile describes a management server
6079
type ServerProfile struct {
6180
URL string `ini:"url"`
@@ -435,7 +454,7 @@ func NewConfig(configFilePath *string) *Config {
435454
if *configFilePath != "" {
436455
defaultConf.ConfigFile, _ = filepath.Abs(*configFilePath)
437456
if _, err := os.Stat(defaultConf.ConfigFile); os.IsNotExist(err) {
438-
fmt.Println("Config file doesn't exist.")
457+
fmt.Printf("Config file '%s' doesn't exist.\n", defaultConf.ConfigFile)
439458
os.Exit(1)
440459
}
441460
}

0 commit comments

Comments
 (0)