1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
package linodego
import (
"fmt"
"os"
"strings"
"gopkg.in/ini.v1"
)
const (
DefaultConfigProfile = "default"
)
var DefaultConfigPaths = []string{
"%s/.config/linode",
"%s/.config/linode-cli",
}
type ConfigProfile struct {
APIToken string `ini:"token"`
APIVersion string `ini:"api_version"`
APIURL string `ini:"api_url"`
}
type LoadConfigOptions struct {
Path string
Profile string
SkipLoadProfile bool
}
// LoadConfig loads a Linode config according to the option's argument.
// If no options are specified, the following defaults will be used:
// Path: ~/.config/linode
// Profile: default
func (c *Client) LoadConfig(options *LoadConfigOptions) error {
path, err := resolveValidConfigPath()
if err != nil {
return err
}
profileOption := DefaultConfigProfile
if options != nil {
if options.Path != "" {
path = options.Path
}
if options.Profile != "" {
profileOption = options.Profile
}
}
cfg, err := ini.Load(path)
if err != nil {
return err
}
defaultConfig := ConfigProfile{
APIToken: "",
APIURL: APIHost,
APIVersion: APIVersion,
}
if cfg.HasSection("default") {
err := cfg.Section("default").MapTo(&defaultConfig)
if err != nil {
return fmt.Errorf("failed to map default profile: %w", err)
}
}
result := make(map[string]ConfigProfile)
for _, profile := range cfg.Sections() {
name := strings.ToLower(profile.Name())
f := defaultConfig
if err := profile.MapTo(&f); err != nil {
return fmt.Errorf("failed to map values: %w", err)
}
result[name] = f
}
c.configProfiles = result
if !options.SkipLoadProfile {
if err := c.UseProfile(profileOption); err != nil {
return fmt.Errorf("unable to use profile %s: %w", profileOption, err)
}
}
return nil
}
// UseProfile switches client to use the specified profile.
// The specified profile must be already be loaded using client.LoadConfig(...)
func (c *Client) UseProfile(name string) error {
name = strings.ToLower(name)
profile, ok := c.configProfiles[name]
if !ok {
return fmt.Errorf("profile %s does not exist", name)
}
if profile.APIToken == "" {
return fmt.Errorf("unable to resolve linode_token for profile %s", name)
}
if profile.APIURL == "" {
return fmt.Errorf("unable to resolve linode_api_url for profile %s", name)
}
if profile.APIVersion == "" {
return fmt.Errorf("unable to resolve linode_api_version for profile %s", name)
}
c.SetToken(profile.APIToken)
c.SetBaseURL(profile.APIURL)
c.SetAPIVersion(profile.APIVersion)
c.selectedProfile = name
c.loadedProfile = name
return nil
}
func FormatConfigPath(path string) (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", err
}
return fmt.Sprintf(path, homeDir), nil
}
func resolveValidConfigPath() (string, error) {
for _, cfg := range DefaultConfigPaths {
p, err := FormatConfigPath(cfg)
if err != nil {
return "", err
}
if _, err = os.Stat(p); err != nil {
continue
}
return p, err
}
// An empty result may not be an error
return "", nil
}
|