1
// The cloudinit package implements a way of creating
2
// a cloudinit configuration file.
3
// See https://help.ubuntu.com/community/CloudInit.
8
yaml "launchpad.net/goyaml"
12
// Config represents a set of cloud-init configuration options.
14
attrs map[string]interface{}
17
// New returns a new Config with no options set.
19
return &Config{make(map[string]interface{})}
22
// Render returns the cloudinit configuration as a YAML file.
23
func (cfg *Config) Render() ([]byte, error) {
24
data, err := yaml.Marshal(cfg.attrs)
28
return append([]byte("#cloud-config\n"), data...), nil
31
// Option represents a cloudinit configuration option.
32
// If it is added to a Config, Name and Value will be marshalled as a top level
33
// attribute-value pair in the generated YAML.
39
// Add sets the given configuration option in cfg.
40
func (cfg *Config) Set(opt Option) {
42
cfg.attrs[opt.Name] = opt.Value
46
// Append appends the option's value to the existing value for
47
// that option in cfg. The value must be of slice type.
48
func (cfg *Config) Append(opt Option) {
52
old := cfg.attrs[opt.Name]
54
cfg.attrs[opt.Name] = opt.Value
57
v := reflect.ValueOf(opt.Value)
58
if v.Kind() != reflect.Slice {
59
panic(fmt.Errorf("cloudinit.Config.Append given option (%s) of non-slice type", opt.Name))
61
oldv := reflect.ValueOf(old)
62
if v.Type() != oldv.Type() {
63
panic(fmt.Errorf("cloudinit.Config.Append: mismatched type, expected %v got %v", oldv.Type(), v.Type()))
66
cfg.attrs[opt.Name] = reflect.AppendSlice(oldv, v).Interface()
69
// source is Key, or KeyId and KeyServer
71
Source string `yaml:"source"`
72
Key string `yaml:"key,omitempty"`
73
KeyId string `yaml:"keyid,omitempty"`
74
KeyServer string `yaml:"keyserver,omitempty"`
77
// Source represents a source option to AptSources.
82
// NewSource creates a Source with the given name from a key.
83
func NewSource(name string, key string) *Source {
84
return &Source{source: source{
90
// NewSource creates a Source with the given name from a key id
92
func NewSourceWithKeyId(name, keyId, keyServer string) *Source {
93
return &Source{source: source{
100
// Command represents a shell command.
101
type Command struct {
106
// NewLiteralCommand returns a Command which
107
// will run s as a shell command. Shell metacharacters
108
// in s will be interpreted by the shell.
109
func NewLiteralCommand(s string) *Command {
110
return &Command{literal: s}
113
// NewArgListCommand returns a Command which
114
// run the given command and arguments. Any
115
// shell metacharacters in the arguments will be
116
// appropriately quoted.
117
func NewArgListCommand(args ...string) *Command {
118
return &Command{args: args}
121
// GetYAML implements yaml.Getter
122
func (t *Command) GetYAML() (tag string, value interface{}) {
129
// KeyType represents the type of an SSH Key.
137
Private KeyType = 1 << 3
138
Public KeyType = 0 << 3
140
RSAPrivate = RSA | Private
141
RSAPublic = RSA | Public
142
DSAPrivate = DSA | Private
143
DSAPublic = DSA | Public
146
var _ yaml.Getter = Key{}
148
// Key represents an SSH Key with the given type and associated key data.
154
// GetYaml implements yaml.Getter
155
func (k Key) GetYAML() (tag string, value interface{}) {
156
return "", []string{k.Type.String(), k.Data}
159
func (t KeyType) String() string {
161
switch t &^ (Private | Public) {
167
panic("unknown key type")
177
// OutputSpec represents the destination of a command.
178
// Each of Stdout and Stderr can take one of the following forms:
184
// pipes to the given command.
185
// If Stderr is "&1", it will be directed to the same
187
type OutputSpec struct {
192
var _ yaml.Getter = (*OutputSpec)(nil)
194
func (o *OutputSpec) GetYAML() (tag string, value interface{}) {
195
if o.Stdout == o.Stderr {
198
return "", []string{o.Stdout, o.Stderr}
201
// maybe returns x if yes is true, otherwise it returns nil.
202
func maybe(yes bool, x interface{}) interface{} {