-
Notifications
You must be signed in to change notification settings - Fork 87
/
config.go
293 lines (250 loc) · 6.69 KB
/
config.go
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package config
import (
"encoding/json"
"fmt"
"os"
"time"
"github.com/civo/civogo"
"github.com/civo/cli/common"
"github.com/mitchellh/go-homedir"
)
// Config describes the configuration for Civo's CLI
type Config struct {
APIKeys map[string]string `json:"apikeys"`
Meta Metadata `json:"meta"`
RegionToFeatures map[string]civogo.Feature `json:"region_to_features"`
}
// Metadata describes the metadata for Civo's CLI
type Metadata struct {
Admin bool `json:"admin"`
CurrentAPIKey string `json:"current_apikey"`
DefaultRegion string `json:"default_region"`
LatestReleaseCheck time.Time `json:"latest_release_check"`
URL string `json:"url"`
LastCmdExecuted time.Time `json:"last_command_executed"`
}
// Current contains the parsed ~/.civo.json file
var Current Config
// Filename is set to a full filename if the default config
// file is overridden by a command-line switch
var Filename string
// ReadConfig reads in config file and ENV variables if set.
func ReadConfig() {
filename, found := os.LookupEnv("CIVO_CONFIG")
if found {
Filename = filename
}
if Filename != "" {
loadConfig(Filename)
} else {
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
loadConfig(fmt.Sprintf("%s/%s", home, ".civo.json"))
}
}
func loadConfig(filename string) {
var err error
err = checkConfigFile(filename)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
configFile, err := os.Open(filename)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
jsonParser := json.NewDecoder(configFile)
err = jsonParser.Decode(&Current)
if err != nil {
Current.Meta.Admin = false
Current.Meta.DefaultRegion = "LON1"
Current.Meta.URL = "https://api.civo.com"
Current.Meta.LastCmdExecuted = time.Now()
fileContend, jsonErr := json.Marshal(Current)
if jsonErr != nil {
fmt.Printf("Error parsing the JSON")
os.Exit(1)
}
err = os.WriteFile(filename, fileContend, 0600)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
if Current.APIKeys == nil {
Current.APIKeys = map[string]string{}
}
if token, found := os.LookupEnv("CIVO_TOKEN"); found && token != "" {
Current.APIKeys["tempKey"] = token
Current.Meta.CurrentAPIKey = "tempKey"
}
if Current.Meta.CurrentAPIKey != "" && Current.RegionToFeatures == nil {
Current.RegionToFeatures, err = regionsToFeature()
if err != nil {
fmt.Printf("Error getting supported regions to feature %s \n", err)
os.Exit(1)
}
dataBytes, err := json.Marshal(Current)
if err != nil {
fmt.Printf("Error parsing JSON %s \n", err)
os.Exit(1)
}
err = os.WriteFile(filename, dataBytes, 0600)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
if time.Since(Current.Meta.LatestReleaseCheck) > (24 * time.Hour) {
Current.Meta.LatestReleaseCheck = time.Now()
if Current.Meta.CurrentAPIKey != "" {
Current.RegionToFeatures, err = regionsToFeature()
if err != nil {
fmt.Printf("Error getting supported regions to feature %s \n", err)
os.Exit(1)
}
}
dataBytes, err := json.Marshal(Current)
if err != nil {
fmt.Printf("Error parsing JSON %s \n", err)
os.Exit(1)
}
err = os.WriteFile(filename, dataBytes, 0600)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
common.CheckVersionUpdate()
}
}
// SaveConfig saves the current configuration back out to a JSON file in
// either ~/.civo.json or Filename if one was set
func SaveConfig() {
var filename string
if Filename != "" {
filename = Filename
} else {
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
filename = fmt.Sprintf("%s/%s", home, ".civo.json")
}
dataBytes, err := json.Marshal(Current)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = os.WriteFile(filename, dataBytes, 0600)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if err := os.Chmod(filename, 0600); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func checkConfigFile(filename string) error {
curr := Config{APIKeys: map[string]string{}}
curr.Meta = Metadata{
Admin: false,
DefaultRegion: "NYC1",
URL: "https://api.civo.com",
LastCmdExecuted: time.Now(),
}
if Current.Meta.CurrentAPIKey != "" {
var err error
curr.RegionToFeatures, err = regionsToFeature()
if err != nil {
return err
}
}
fileContend, jsonErr := json.Marshal(curr)
if jsonErr != nil {
fmt.Printf("Error parsing the JSON")
os.Exit(1)
}
file, err := os.Stat(filename)
if os.IsNotExist(err) {
_, err := os.Create(filename)
if err != nil {
return err
}
err = os.WriteFile(filename, fileContend, 0600)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
} else {
size := file.Size()
if size == 0 {
err = os.WriteFile(filename, fileContend, 0600)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
}
if err := os.Chmod(filename, 0600); err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
}
// regionsToFeature get the region to supported features map
func regionsToFeature() (map[string]civogo.Feature, error) {
regionsToFeature := map[string]civogo.Feature{}
client, err := CivoAPIClient()
if err != nil {
fmt.Printf("Creating the connection to Civo's API failed with %s", err)
return regionsToFeature, err
}
regions, err := client.ListRegions()
if err != nil {
fmt.Printf("Unable to list regions: %s", err)
return regionsToFeature, err
}
for _, region := range regions {
regionsToFeature[region.Code] = region.Features
}
return regionsToFeature, nil
}
// DefaultAPIKey returns the current default API key
func DefaultAPIKey() string {
if Current.Meta.CurrentAPIKey != "" {
return Current.APIKeys[Current.Meta.CurrentAPIKey]
}
return ""
}
// CivoAPIClient returns a civogo client using the current default API key
func CivoAPIClient() (*civogo.Client, error) {
apiKey := DefaultAPIKey()
if apiKey == "" {
fmt.Printf("Error: Creating the connection to Civo's API failed because no API key is supplied. This is required to authenticate requests. Please go to https://dashboard.civo.com/security to obtain your API key, then save it using the command 'civo apikey save YOUR_API_KEY'.\n")
return nil, fmt.Errorf("no API Key supplied, this is required")
}
cliClient, err := civogo.NewClientWithURL(apiKey, Current.Meta.URL, Current.Meta.DefaultRegion)
if err != nil {
return nil, err
}
var version string
res, skip := common.VersionCheck(common.GithubClient())
if !skip {
version = *res.TagName
} else {
version = "0.0.0"
}
// Update the user agent to include the version of the CLI
cliComponent := &civogo.Component{
Name: "civo-cli",
Version: version,
}
cliClient.SetUserAgent(cliComponent)
return cliClient, nil
}