1206.2.1
by Martin Packman
Add copyright statement at the top of all go files bar thirdparty |
1 |
// Copyright 2011, 2012, 2013 Canonical Ltd.
|
2 |
// Licensed under the AGPLv3, see LICENCE file for details.
|
|
3 |
||
25.2.1
by Roger Peppe
add cloudinit package |
4 |
package cloudinit |
39.4.28
by Roger Peppe
remove log messages; go fmt |
5 |
|
39.4.10
by Roger Peppe
SSHAddAuthorizedKey becomes SSHAddAuthorizedKeys and |
6 |
import ( |
1590.1.1
by Sidnei da Silva
- Move addScripts and addFile from environments/cloudinit.go to cloudinit.Config methods. |
7 |
"fmt"
|
39.4.10
by Roger Peppe
SSHAddAuthorizedKey becomes SSHAddAuthorizedKeys and |
8 |
"strings"
|
1590.1.1
by Sidnei da Silva
- Move addScripts and addFile from environments/cloudinit.go to cloudinit.Config methods. |
9 |
|
10 |
"launchpad.net/juju-core/utils"
|
|
39.4.10
by Roger Peppe
SSHAddAuthorizedKey becomes SSHAddAuthorizedKeys and |
11 |
)
|
58.1.1
by Roger Peppe
allow SSHAddAuthorizedKeys to take multiple keys |
12 |
|
39.3.4
by Roger Peppe
add cloudinit.Config.SetAttr. |
13 |
// SetAttr sets an arbitrary attribute in the cloudinit config.
|
14 |
// If value is nil the attribute will be deleted; otherwise
|
|
15 |
// the value will be marshalled according to the rules
|
|
39.4.11
by Roger Peppe
remove admin-secret; make tests run (but not pass) |
16 |
// of the goyaml Marshal function.
|
39.3.4
by Roger Peppe
add cloudinit.Config.SetAttr. |
17 |
func (cfg *Config) SetAttr(name string, value interface{}) { |
18 |
cfg.set(name, value != nil, value) |
|
19 |
}
|
|
39.3.13
by Roger Peppe
gofmt |
20 |
|
25.2.8
by Roger Peppe
simplified key type. |
21 |
// SetUser sets the user name that will be used for some other options.
|
22 |
// The user will be assumed to already exist in the machine image.
|
|
23 |
// The default user is "ubuntu".
|
|
25.2.7
by Roger Peppe
changes in response to review |
24 |
func (cfg *Config) SetUser(user string) { |
25 |
cfg.set("user", user != "", user) |
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
26 |
}
|
27 |
||
25.2.8
by Roger Peppe
simplified key type. |
28 |
// SetAptUpgrade sets whether cloud-init runs "apt-get upgrade"
|
29 |
// on first boot.
|
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
30 |
func (cfg *Config) SetAptUpgrade(yes bool) { |
31 |
cfg.set("apt_upgrade", yes, yes) |
|
32 |
}
|
|
33 |
||
25.2.8
by Roger Peppe
simplified key type. |
34 |
// SetUpdate sets whether cloud-init runs "apt-get update"
|
35 |
// on first boot.
|
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
36 |
func (cfg *Config) SetAptUpdate(yes bool) { |
37 |
cfg.set("apt_update", yes, yes) |
|
38 |
}
|
|
39 |
||
1567.3.5
by Sidnei da Silva
- Add AddAptProxy to method |
40 |
// SetAptProxy sets the URL to be used as the apt
|
41 |
// proxy.
|
|
42 |
func (cfg *Config) SetAptProxy(url string) { |
|
43 |
cfg.set("apt_proxy", url != "", url) |
|
44 |
}
|
|
45 |
||
25.2.8
by Roger Peppe
simplified key type. |
46 |
// SetAptMirror sets the URL to be used as the apt
|
47 |
// mirror site. If not set, the URL is selected based
|
|
48 |
// on cloud metadata in EC2 - <region>.archive.ubuntu.com
|
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
49 |
func (cfg *Config) SetAptMirror(url string) { |
50 |
cfg.set("apt_mirror", url != "", url) |
|
51 |
}
|
|
52 |
||
25.2.8
by Roger Peppe
simplified key type. |
53 |
// SetAptPreserveSourcesList sets whether /etc/apt/sources.list
|
54 |
// is overwritten by the mirror. If true, SetAptMirror above
|
|
55 |
// will have no effect.
|
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
56 |
func (cfg *Config) SetAptPreserveSourcesList(yes bool) { |
57 |
cfg.set("apt_mirror", yes, yes) |
|
58 |
}
|
|
59 |
||
25.2.8
by Roger Peppe
simplified key type. |
60 |
// AddAptSource adds an apt source. The key holds the
|
61 |
// public key of the source, in the form expected by apt-key(8).
|
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
62 |
func (cfg *Config) AddAptSource(name, key string) { |
63 |
src, _ := cfg.attrs["apt_sources"].([]*source) |
|
64 |
cfg.attrs["apt_sources"] = append(src, |
|
65 |
&source{ |
|
66 |
Source: name, |
|
25.2.7
by Roger Peppe
changes in response to review |
67 |
Key: key, |
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
68 |
})
|
69 |
}
|
|
70 |
||
25.2.8
by Roger Peppe
simplified key type. |
71 |
// AddAptSource adds an apt source. The public key for the
|
72 |
// source is retrieved by fetching the given keyId from the
|
|
73 |
// GPG key server at the given address.
|
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
74 |
func (cfg *Config) AddAptSourceWithKeyId(name, keyId, keyServer string) { |
75 |
src, _ := cfg.attrs["apt_sources"].([]*source) |
|
76 |
cfg.attrs["apt_sources"] = append(src, |
|
77 |
&source{ |
|
78 |
Source: name, |
|
79 |
KeyId: keyId, |
|
80 |
KeyServer: keyServer, |
|
81 |
})
|
|
82 |
}
|
|
83 |
||
25.2.8
by Roger Peppe
simplified key type. |
84 |
// SetDebconfSelections provides preseeded debconf answers
|
85 |
// for the boot process. The given answers will be used as input
|
|
86 |
// to debconf-set-selections(1).
|
|
87 |
func (cfg *Config) SetDebconfSelections(answers string) { |
|
88 |
cfg.set("debconf_selections", answers != "", answers) |
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
89 |
}
|
90 |
||
25.2.8
by Roger Peppe
simplified key type. |
91 |
// AddPackage adds a package to be installed on first boot.
|
92 |
// If any packages are specified, "apt-get update"
|
|
93 |
// will be called.
|
|
25.2.7
by Roger Peppe
changes in response to review |
94 |
func (cfg *Config) AddPackage(name string) { |
1628.11.13
by Andrew Wilkins
Manual provisioning: use cloudinit, check if provisioned |
95 |
cfg.attrs["packages"] = append(cfg.Packages(), name) |
96 |
}
|
|
97 |
||
98 |
// Packages returns a list of packages that will be
|
|
99 |
// installed on first boot.
|
|
100 |
func (cfg *Config) Packages() []string { |
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
101 |
pkgs, _ := cfg.attrs["packages"].([]string) |
1628.11.13
by Andrew Wilkins
Manual provisioning: use cloudinit, check if provisioned |
102 |
return pkgs |
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
103 |
}
|
104 |
||
25.2.8
by Roger Peppe
simplified key type. |
105 |
func (cfg *Config) addCmd(kind string, c *command) { |
1628.11.13
by Andrew Wilkins
Manual provisioning: use cloudinit, check if provisioned |
106 |
cfg.attrs[kind] = append(cfg.getCmds(kind), c) |
107 |
}
|
|
108 |
||
109 |
func (cfg *Config) getCmds(kind string) []*command { |
|
25.2.8
by Roger Peppe
simplified key type. |
110 |
cmds, _ := cfg.attrs[kind].([]*command) |
1628.11.13
by Andrew Wilkins
Manual provisioning: use cloudinit, check if provisioned |
111 |
return cmds |
112 |
}
|
|
113 |
||
114 |
// RunCmds returns a list of commands that will be
|
|
115 |
// run at first boot.
|
|
116 |
//
|
|
117 |
// Each element in the resultant slice is either a
|
|
118 |
// string or []string, corresponding to how the command
|
|
119 |
// was added.
|
|
120 |
func (cfg *Config) RunCmds() []interface{} { |
|
121 |
cmds := cfg.getCmds("runcmd") |
|
122 |
result := make([]interface{}, len(cmds)) |
|
123 |
for i, cmd := range cmds { |
|
124 |
if cmd.args != nil { |
|
125 |
result[i] = append([]string{}, cmd.args...) |
|
126 |
} else { |
|
127 |
result[i] = cmd.literal |
|
128 |
}
|
|
129 |
}
|
|
130 |
return result |
|
25.2.8
by Roger Peppe
simplified key type. |
131 |
}
|
132 |
||
25.2.10
by Roger Peppe
updated options comments |
133 |
// AddRunCmd adds a command to be executed
|
134 |
// at first boot. The command will be run
|
|
135 |
// by the shell with any metacharacters retaining
|
|
136 |
// their special meaning (that is, no quoting takes place).
|
|
25.2.8
by Roger Peppe
simplified key type. |
137 |
func (cfg *Config) AddRunCmd(cmd string) { |
138 |
cfg.addCmd("runcmd", &command{literal: cmd}) |
|
139 |
}
|
|
140 |
||
141 |
// AddRunCmdArgs is like AddRunCmd except that the command
|
|
142 |
// will be executed with the given arguments properly quoted.
|
|
143 |
func (cfg *Config) AddRunCmdArgs(args ...string) { |
|
144 |
cfg.addCmd("runcmd", &command{args: args}) |
|
145 |
}
|
|
146 |
||
147 |
// AddBootCmd is like AddRunCmd except that the
|
|
148 |
// command will run very early in the boot process,
|
|
25.2.10
by Roger Peppe
updated options comments |
149 |
// and it will run on every boot, not just the first time.
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
150 |
func (cfg *Config) AddBootCmd(cmd string) { |
25.2.8
by Roger Peppe
simplified key type. |
151 |
cfg.addCmd("bootcmd", &command{literal: cmd}) |
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
152 |
}
|
153 |
||
25.2.8
by Roger Peppe
simplified key type. |
154 |
// AddBootCmdArgs is like AddBootCmd except that the command
|
155 |
// will be executed with the given arguments properly quoted.
|
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
156 |
func (cfg *Config) AddBootCmdArgs(args ...string) { |
25.2.8
by Roger Peppe
simplified key type. |
157 |
cfg.addCmd("bootcmd", &command{args: args}) |
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
158 |
}
|
159 |
||
25.2.8
by Roger Peppe
simplified key type. |
160 |
// SetDisableEC2Metadata sets whether access to the
|
161 |
// EC2 metadata service is disabled early in boot
|
|
162 |
// via a null route ( route del -host 169.254.169.254 reject).
|
|
25.2.7
by Roger Peppe
changes in response to review |
163 |
func (cfg *Config) SetDisableEC2Metadata(yes bool) { |
164 |
cfg.set("disable_ec2_metadata", yes, yes) |
|
165 |
}
|
|
166 |
||
25.2.8
by Roger Peppe
simplified key type. |
167 |
// SetFinalMessage sets to message that will be written
|
168 |
// when the system has finished booting for the first time.
|
|
169 |
// By default, the message is:
|
|
170 |
// "cloud-init boot finished at $TIMESTAMP. Up $UPTIME seconds".
|
|
25.2.7
by Roger Peppe
changes in response to review |
171 |
func (cfg *Config) SetFinalMessage(msg string) { |
172 |
cfg.set("final_message", msg != "", msg) |
|
173 |
}
|
|
174 |
||
25.2.8
by Roger Peppe
simplified key type. |
175 |
// SetLocale sets the locale; it defaults to en_US.UTF-8.
|
25.2.7
by Roger Peppe
changes in response to review |
176 |
func (cfg *Config) SetLocale(locale string) { |
177 |
cfg.set("locale", locale != "", locale) |
|
178 |
}
|
|
179 |
||
25.2.8
by Roger Peppe
simplified key type. |
180 |
// AddMount adds a mount point. The given
|
25.2.10
by Roger Peppe
updated options comments |
181 |
// arguments will be used as a line in /etc/fstab.
|
25.2.8
by Roger Peppe
simplified key type. |
182 |
func (cfg *Config) AddMount(args ...string) { |
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
183 |
mounts, _ := cfg.attrs["mounts"].([][]string) |
25.2.8
by Roger Peppe
simplified key type. |
184 |
cfg.attrs["mounts"] = append(mounts, args) |
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
185 |
}
|
186 |
||
25.2.8
by Roger Peppe
simplified key type. |
187 |
// OutputKind represents a destination for command output.
|
25.2.7
by Roger Peppe
changes in response to review |
188 |
type OutputKind string |
189 |
||
190 |
const ( |
|
191 |
OutInit OutputKind = "init" |
|
192 |
OutConfig OutputKind = "config" |
|
193 |
OutFinal OutputKind = "final" |
|
194 |
OutAll OutputKind = "all" |
|
195 |
)
|
|
196 |
||
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
197 |
// SetOutput specifies destination for command output.
|
198 |
// Valid values for the kind "init", "config", "final" and "all".
|
|
199 |
// Each of stdout and stderr can take one of the following forms:
|
|
25.2.10
by Roger Peppe
updated options comments |
200 |
// >>file
|
201 |
// appends to file
|
|
202 |
// >file
|
|
203 |
// overwrites file
|
|
204 |
// |command
|
|
205 |
// pipes to the given command.
|
|
25.2.7
by Roger Peppe
changes in response to review |
206 |
func (cfg *Config) SetOutput(kind OutputKind, stdout, stderr string) { |
207 |
out, _ := cfg.attrs["output"].(map[string]interface{}) |
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
208 |
if out == nil { |
209 |
out = make(map[string]interface{}) |
|
210 |
}
|
|
211 |
if stderr == "" { |
|
25.2.7
by Roger Peppe
changes in response to review |
212 |
out[string(kind)] = stdout |
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
213 |
} else { |
25.2.7
by Roger Peppe
changes in response to review |
214 |
out[string(kind)] = []string{stdout, stderr} |
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
215 |
}
|
216 |
cfg.attrs["output"] = out |
|
217 |
}
|
|
218 |
||
25.2.10
by Roger Peppe
updated options comments |
219 |
// AddSSHKey adds a pre-generated ssh key to the
|
25.2.8
by Roger Peppe
simplified key type. |
220 |
// server keyring. Keys that are added like this will be
|
221 |
// written to /etc/ssh and new random keys will not
|
|
222 |
// be generated.
|
|
223 |
func (cfg *Config) AddSSHKey(keyType SSHKeyType, keyData string) { |
|
224 |
keys, _ := cfg.attrs["ssh_keys"].(map[SSHKeyType]string) |
|
225 |
if keys == nil { |
|
226 |
keys = make(map[SSHKeyType]string) |
|
227 |
cfg.attrs["ssh_keys"] = keys |
|
228 |
}
|
|
229 |
keys[keyType] = keyData |
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
230 |
}
|
231 |
||
25.2.10
by Roger Peppe
updated options comments |
232 |
// SetDisableRoot sets whether ssh login is disabled to the root account
|
233 |
// via the ssh authorized key associated with the instance metadata.
|
|
234 |
// It is true by default.
|
|
235 |
func (cfg *Config) SetDisableRoot(disable bool) { |
|
25.2.1
by Roger Peppe
add cloudinit package |
236 |
// note that disable_root defaults to true, so we include
|
25.2.10
by Roger Peppe
updated options comments |
237 |
// the option only if disable is false.
|
238 |
cfg.set("disable_root", !disable, disable) |
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
239 |
}
|
240 |
||
39.4.10
by Roger Peppe
SSHAddAuthorizedKey becomes SSHAddAuthorizedKeys and |
241 |
// AddSSHAuthorizedKey adds a set of keys in
|
242 |
// ssh authorized_keys format (see ssh(8) for details)
|
|
243 |
// that will be added to ~/.ssh/authorized_keys for the
|
|
25.2.8
by Roger Peppe
simplified key type. |
244 |
// configured user (see SetUser).
|
39.4.10
by Roger Peppe
SSHAddAuthorizedKey becomes SSHAddAuthorizedKeys and |
245 |
func (cfg *Config) AddSSHAuthorizedKeys(keys string) { |
246 |
akeys, _ := cfg.attrs["ssh_authorized_keys"].([]string) |
|
247 |
lines := strings.Split(keys, "\n") |
|
248 |
for _, line := range lines { |
|
249 |
if line == "" || line[0] == '#' { |
|
250 |
continue
|
|
251 |
}
|
|
252 |
akeys = append(akeys, line) |
|
253 |
}
|
|
254 |
cfg.attrs["ssh_authorized_keys"] = akeys |
|
25.2.3
by Roger Peppe
move to more direct scheme for adding options. |
255 |
}
|
256 |
||
1590.1.1
by Sidnei da Silva
- Move addScripts and addFile from environments/cloudinit.go to cloudinit.Config methods. |
257 |
// AddScripts is a simple shorthand for calling AddRunCmd multiple times.
|
258 |
func (cfg *Config) AddScripts(scripts ...string) { |
|
259 |
for _, s := range scripts { |
|
260 |
cfg.AddRunCmd(s) |
|
261 |
}
|
|
262 |
}
|
|
263 |
||
264 |
// AddFile will add multiple run_cmd entries to safely set the contents of a
|
|
265 |
// specific file to the requested contents.
|
|
266 |
func (cfg *Config) AddFile(filename, data string, mode uint) { |
|
1682.2.1
by Andrew Wilkins
Use printf instead of echo shell builtin |
267 |
// Note: recent versions of cloud-init have the "write_files"
|
268 |
// module, which can write arbitrary files. We currently support
|
|
269 |
// 12.04 LTS, which uses an older version of cloud-init without
|
|
270 |
// this module.
|
|
1590.1.1
by Sidnei da Silva
- Move addScripts and addFile from environments/cloudinit.go to cloudinit.Config methods. |
271 |
p := shquote(filename) |
1682.2.1
by Andrew Wilkins
Use printf instead of echo shell builtin |
272 |
// Don't use the shell's echo builtin here; the interpretation
|
273 |
// of escape sequences differs between shells, namely bash and
|
|
274 |
// dash. Instead, we use printf (or we could use /bin/echo).
|
|
1590.1.1
by Sidnei da Silva
- Move addScripts and addFile from environments/cloudinit.go to cloudinit.Config methods. |
275 |
cfg.AddScripts( |
276 |
fmt.Sprintf("install -m %o /dev/null %s", mode, p), |
|
1682.2.2
by Andrew Wilkins
Single quote printf format |
277 |
fmt.Sprintf(`printf '%%s\n' %s > %s`, shquote(data), p), |
1590.1.1
by Sidnei da Silva
- Move addScripts and addFile from environments/cloudinit.go to cloudinit.Config methods. |
278 |
)
|
279 |
}
|
|
280 |
||
281 |
func shquote(p string) string { |
|
282 |
return utils.ShQuote(p) |
|
283 |
}
|
|
284 |
||
25.2.1
by Roger Peppe
add cloudinit package |
285 |
// TODO
|
286 |
// byobu
|
|
287 |
// grub_dpkg
|
|
288 |
// mcollective
|
|
289 |
// phone_home
|
|
290 |
// puppet
|
|
291 |
// resizefs
|
|
292 |
// rightscale_userdata
|
|
293 |
// rsyslog
|
|
294 |
// scripts_per_boot
|
|
295 |
// scripts_per_instance
|
|
296 |
// scripts_per_once
|
|
297 |
// scripts_user
|
|
298 |
// set_hostname
|
|
299 |
// set_passwords
|
|
300 |
// ssh_import_id
|
|
301 |
// timezone
|
|
302 |
// update_etc_hosts
|
|
303 |
// update_hostname
|