-
Notifications
You must be signed in to change notification settings - Fork 5
/
export.go
143 lines (118 loc) · 2.77 KB
/
export.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
package jsonconsul
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"time"
)
type JsonExport struct {
// KV Path in Consul
Prefix string
// Place to put the config file
ConfigFile string
// If we are overwriting the ConfigFile should we timestamp
// the versions so that there is a trail.
Timestamp bool
// Should we poll for consul changes.
Watch bool
// Should the output include the nodes in the included prefix?
IncludePrefix bool
// Parse the Values as Json
JsonValues bool
FlattenedKVs map[string]interface{}
currentJson []byte
}
func (c *JsonExport) ParseFlags(args []string) {
flags := flag.NewFlagSet(Name, flag.ContinueOnError)
flags.StringVar(&c.Prefix, "prefix", "", "What KV prefix should I track?")
flags.BoolVar(&c.Timestamp, "timestamp", false, "Should I create timestamped values of this")
flags.BoolVar(&c.IncludePrefix, "include-prefix", true, "Should I remove the prefix values when exporting?")
flags.BoolVar(&c.JsonValues, "json-values", true, "Have the values that are returned by Consul be parsed as json.")
flags.Parse(args)
leftovers := flags.Args()
if len(leftovers) != 0 {
c.ConfigFile = leftovers[0]
}
}
func (c *JsonExport) fileNameWithTimestamp() string {
return fmt.Sprintf("%s.%d", c.ConfigFile, int32(time.Now().Unix()))
}
func (c *JsonExport) WriteFile(newJson []byte) error {
if bytes.Equal(c.currentJson, newJson) {
// File didn't change.
return nil
}
fileName := c.ConfigFile
if c.Timestamp {
fileName = c.fileNameWithTimestamp()
}
err := ioutil.WriteFile(fileName, newJson, 0644)
if err != nil {
return err
}
// Symlink files
if c.Timestamp {
err = os.Symlink(fileName, c.ConfigFile)
if err != nil {
return err
}
}
c.currentJson = newJson
return nil
}
func (c *JsonExport) jsonifyValues(kvs map[string]interface{}) error {
for k, v := range kvs {
switch v.(type) {
case string:
var jsonVal interface{}
err := json.Unmarshal([]byte(v.(string)), &jsonVal)
if err != nil {
return err
}
kvs[k] = jsonVal
case map[string]interface{}:
if err := c.jsonifyValues(v.(map[string]interface{})); err != nil {
return err
}
}
}
return nil
}
func (c *JsonExport) GenerateJson() ([]byte, error) {
var (
err error
)
c.FlattenedKVs, err = consulToNestedMap(c.Prefix, c.IncludePrefix)
if err != nil {
return nil, err
}
if c.JsonValues {
err = c.jsonifyValues(c.FlattenedKVs)
if err != nil {
return nil, err
}
}
js, err := json.Marshal(c.FlattenedKVs)
if err != nil {
return nil, err
}
return js, nil
}
func (c *JsonExport) Run() error {
json, err := c.GenerateJson()
if err != nil {
return err
}
if c.ConfigFile == "" {
fmt.Println(string(json))
} else {
err := c.WriteFile(json)
if err != nil {
return err
}
}
return nil
}