forked from eksctl-io/eksctl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcloudconfig.go
161 lines (132 loc) · 3.42 KB
/
cloudconfig.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
package cloudconfig
import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"github.com/kris-nova/logger"
"sigs.k8s.io/yaml"
)
const (
header = "#cloud-config"
// Shell defines the used shell
Shell = "/bin/bash"
scriptDir = "/var/lib/cloud/scripts/per-instance/"
defaultOwner = "root:root"
defaultScriptPermissions = "0755"
defaultFilePermissions = "0644"
)
// CloudConfig stores informaiton of the cloud config
type CloudConfig struct {
Commands []interface{} `json:"runcmd"`
Packages []string `json:"packages"`
WriteFiles []File `json:"write_files"`
}
// File stores information about the file
type File struct {
Content string `json:"content"`
Owner string `json:"owner"`
Path string `json:"path"`
Permissions string `json:"permissions"`
}
// New creates a new cloud config
func New() *CloudConfig {
return &CloudConfig{}
}
// AddPackages adds packages, which should be installed on the node
func (c *CloudConfig) AddPackages(pkgs ...string) {
c.Packages = append(c.Packages, pkgs...)
}
// AddCommands adds commands, which will be run on node start up
func (c *CloudConfig) AddCommands(cmds ...[]string) {
for _, cmd := range cmds {
c.Commands = append(c.Commands, cmd)
}
}
// AddCommand adds a command, which will be run on node start up
func (c *CloudConfig) AddCommand(cmd ...string) {
c.Commands = append(c.Commands, cmd)
}
// AddShellCommand adds a shell comannd, which will be run on node start up
func (c *CloudConfig) AddShellCommand(cmd string) {
c.Commands = append(c.Commands, []string{Shell, "-c", cmd})
}
// AddFile adds a file, which will be placed on the node
func (c *CloudConfig) AddFile(f File) {
if f.Owner == "" {
f.Owner = defaultOwner
}
if f.Permissions == "" {
f.Permissions = defaultFilePermissions
}
c.WriteFiles = append(c.WriteFiles, f)
}
// AddScript adds a scipt, which will be placed on the node
func (c *CloudConfig) AddScript(p, s string) {
c.AddFile(File{
Content: s,
Path: p,
Permissions: defaultScriptPermissions,
Owner: defaultOwner,
})
}
// RunScript adds and runs a script on the node
func (c *CloudConfig) RunScript(name, s string) {
p := scriptDir + name
c.AddScript(p, s)
c.AddCommand(p)
}
// Encode encodes the cloud config
func (c *CloudConfig) Encode() (string, error) {
data, err := yaml.Marshal(c)
if err != nil {
return "", err
}
data = append([]byte(fmt.Sprintln(header)), data...)
return encodeUserData(data)
}
func encodeUserData(data []byte) (string, error) {
var (
buf bytes.Buffer
gw = gzip.NewWriter(&buf)
)
if _, err := gw.Write(data); err != nil {
return "", err
}
if err := gw.Close(); err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(buf.Bytes()), nil
}
// DecodeCloudConfig decodes the cloud config
func DecodeCloudConfig(s string) (*CloudConfig, error) {
if s == "" {
return nil, fmt.Errorf("cannot decode empty string")
}
c := New()
data, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, err
}
gr, err := gzip.NewReader(ioutil.NopCloser(bytes.NewBuffer(data)))
if err != nil {
return nil, err
}
defer safeClose(gr)
data, err = ioutil.ReadAll(gr)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(data, c)
if err != nil {
return nil, err
}
return c, nil
}
func safeClose(c io.Closer) {
if err := c.Close(); err != nil {
logger.Debug("could not close file: %v", err)
}
}