-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconftpl_config.go
170 lines (154 loc) · 4.22 KB
/
conftpl_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
package confclient
import (
"bytes"
"fmt"
"github.com/BurntSushi/toml"
log "github.com/Sirupsen/logrus"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"text/template"
)
type TemplateConfigFile struct {
Tpl TemplateConfig `toml:"template"`
}
type TemplateConfig struct {
Src string `toml:"src"`
Name string
Dest string `toml:"dest"`
TempDest string
Uid int `toml:"uid"`
Gid int `toml:"gid"`
FileMode os.FileMode
Mode string `toml:"mode"`
CheckCmd string `toml:"check_cmd"`
}
func (t *TemplateConfig) Process(funcMap map[string]interface{}) error {
log.WithFields(log.Fields{"file": t.Src}).Info("Processing template")
tmpl, err := template.New(filepath.Base(t.Src)).Funcs(funcMap).ParseFiles(t.Src)
if err != nil {
return fmt.Errorf("Error parsing template %s: %s", t.Src, err)
}
var buffer bytes.Buffer
if err = tmpl.Execute(&buffer, nil); err != nil {
return fmt.Errorf("Cannot execute template %s: %s", t.Src, err)
}
var tmpfile *os.File
if t.TempDest != "" {
tmpfile, err = os.OpenFile(t.TempDest, os.O_WRONLY|os.O_CREATE, t.FileMode)
if err != nil {
return fmt.Errorf("Cannot open temporary file %s: %s", t.TempDest, err)
}
} else {
tmpfile, err = ioutil.TempFile("/tmp", filepath.Base(t.Src))
if err != nil {
return fmt.Errorf("Cannot create temporary file: %s", err)
}
t.TempDest = tmpfile.Name()
}
if _, err := tmpfile.Write(buffer.Bytes()); err != nil {
return fmt.Errorf("Cannot write to temp file %s: %s", tmpfile.Name(), err)
}
if err := tmpfile.Close(); err != nil {
return fmt.Errorf("Error closing temp file: %s", err)
}
if t.CheckCmd != "" {
err := t.Validate()
if err != nil {
os.Remove(t.TempDest)
return fmt.Errorf("Validation failed for %s: %s", t.Src, err)
}
}
if t.Dest == "" {
// No destination - spew to stdout
os.Remove(tmpfile.Name())
fmt.Printf("%s", buffer.String())
return nil
} else {
// Rename to destination file
os.Chmod(t.TempDest, t.FileMode)
os.Chown(t.TempDest, t.Uid, t.Gid)
err := os.Rename(t.TempDest, t.Dest)
if err != nil {
return fmt.Errorf("Cannot rename %s to %s: %s", t.TempDest, t.Dest, err)
}
}
return nil
}
func (t *TemplateConfig) Validate() error {
if t.CheckCmd == "" {
return nil
}
var cmdBuffer bytes.Buffer
data := make(map[string]string)
data["src"] = t.TempDest
tmpl, err := template.New("checkcmd").Parse(t.CheckCmd)
if err != nil {
return err
}
if err := tmpl.Execute(&cmdBuffer, data); err != nil {
return err
}
log.Debug("Running " + cmdBuffer.String())
c := exec.Command("/bin/sh", "-c", cmdBuffer.String())
/*
mycmd := strings.Replace(t.CheckCmd, "FILE", t.TempDest, -1)
log.Infof("Running verify: %s", mycmd)
c := exec.Command("/bin/sh", "-c", mycmd)
*/
output, err := c.CombinedOutput()
if err != nil {
return fmt.Errorf("%s\nOutput: %s", err, string(output))
}
log.Debugf("%q", string(output))
return nil
}
type TemplateConfigs []*TemplateConfig
func (c *Client) LoadConfigFiles() (TemplateConfigs, error) {
log.Infof("Reading config from: '%s'", c.ConfigDir)
var tcs TemplateConfigs
dh, err := os.Open(c.ConfigDir)
if err != nil {
return tcs, fmt.Errorf("Cannot open dir %s: %s", c.ConfigDir, err)
}
files, err := dh.Readdir(-1)
if err != nil {
return tcs, fmt.Errorf("Cannot read dir %s: %s", c.ConfigDir, err)
}
for _, fi := range files {
tc, err := c.LoadConfigFile(filepath.Join(c.ConfigDir, fi.Name()))
if err != nil {
return nil, fmt.Errorf("Cannot load config file %s: %s", filepath.Join(c.ConfigDir, fi.Name()), err)
}
tcs = append(tcs, tc)
}
return tcs, nil
}
func (c *Client) LoadConfigFile(path string) (*TemplateConfig, error) {
tc := &TemplateConfigFile{TemplateConfig{Uid: -1, Gid: -1}}
log.Infof("Loading config %s", path)
_, err := toml.DecodeFile(path, &tc)
if err != nil {
return nil, fmt.Errorf("Cannot parse config %s: %s", path, err)
}
tr := tc.Tpl
tr.Name = tr.Src
if tr.Uid == -1 {
tr.Uid = os.Geteuid()
}
if tr.Gid == -1 {
tr.Gid = os.Getegid()
}
if tr.Mode != "" {
mode, err := strconv.ParseUint(tr.Mode, 0, 32)
if err != nil {
return nil, err
}
tr.FileMode = os.FileMode(mode)
}
tr.Src = filepath.Join(c.TemplateDir, tr.Src)
tr.TempDest = fmt.Sprintf("%s.tmp", tr.Dest)
return &tr, nil
}