~rogpeppe/juju-core/438-local-instance-Addresses

« back to all changes in this revision

Viewing changes to cloudinit/cloudinit.go

  • Committer: Roger Peppe
  • Date: 2011-12-07 17:03:34 UTC
  • mto: (25.3.4 go-trunk)
  • mto: This revision was merged to the branch mainline in revision 27.
  • Revision ID: roger.peppe@canonical.com-20111207170334-soasb88g2x5mpkf5
add cloudinit package

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// The cloudinit package implements a way of creating
 
2
// a cloudinit configuration file.
 
3
// See https://help.ubuntu.com/community/CloudInit.
 
4
package cloudinit
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        yaml "launchpad.net/goyaml"
 
9
        "reflect"
 
10
)
 
11
 
 
12
// Config represents a set of cloud-init configuration options.
 
13
type Config struct {
 
14
        attrs map[string]interface{}
 
15
}
 
16
 
 
17
// New returns a new Config with no options set.
 
18
func New() *Config {
 
19
        return &Config{make(map[string]interface{})}
 
20
}
 
21
 
 
22
// Render returns the cloudinit configuration as a YAML file.
 
23
func (cfg *Config) Render() ([]byte, error) {
 
24
        data, err := yaml.Marshal(cfg.attrs)
 
25
        if err != nil {
 
26
                return nil, err
 
27
        }
 
28
        return append([]byte("#cloud-config\n"), data...), nil
 
29
}
 
30
 
 
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.
 
34
type Option struct {
 
35
        Name  string
 
36
        Value interface{}
 
37
}
 
38
 
 
39
// Add sets the given configuration option in cfg.
 
40
func (cfg *Config) Set(opt Option) {
 
41
        if opt.Value != nil {
 
42
                cfg.attrs[opt.Name] = opt.Value
 
43
        }
 
44
}
 
45
 
 
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) {
 
49
        if opt.Value == nil {
 
50
                return
 
51
        }
 
52
        old := cfg.attrs[opt.Name]
 
53
        if old == nil {
 
54
                cfg.attrs[opt.Name] = opt.Value
 
55
                return
 
56
        }
 
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))
 
60
        }
 
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()))
 
64
        }
 
65
 
 
66
        cfg.attrs[opt.Name] = reflect.AppendSlice(oldv, v).Interface()
 
67
}
 
68
 
 
69
// source is Key, or KeyId and KeyServer
 
70
type source struct {
 
71
        Source    string `yaml:"source"`
 
72
        Key       string `yaml:"key,omitempty"`
 
73
        KeyId     string `yaml:"keyid,omitempty"`
 
74
        KeyServer string `yaml:"keyserver,omitempty"`
 
75
}
 
76
 
 
77
// Source represents a source option to AptSources.
 
78
type Source struct {
 
79
        source source
 
80
}
 
81
 
 
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{
 
85
                Source: name,
 
86
                Key:    key,
 
87
        }}
 
88
}
 
89
 
 
90
// NewSource creates a Source with the given name from a key id
 
91
// and a key server.
 
92
func NewSourceWithKeyId(name, keyId, keyServer string) *Source {
 
93
        return &Source{source: source{
 
94
                Source:    name,
 
95
                KeyId:     keyId,
 
96
                KeyServer: keyServer,
 
97
        }}
 
98
}
 
99
 
 
100
// Command represents a shell command.
 
101
type Command struct {
 
102
        literal string
 
103
        args    []string
 
104
}
 
105
 
 
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}
 
111
}
 
112
 
 
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}
 
119
}
 
120
 
 
121
// GetYAML implements yaml.Getter
 
122
func (t *Command) GetYAML() (tag string, value interface{}) {
 
123
        if t.args != nil {
 
124
                return "", t.args
 
125
        }
 
126
        return "", t.literal
 
127
}
 
128
 
 
129
// KeyType represents the type of an SSH Key.
 
130
type KeyType int
 
131
 
 
132
const (
 
133
        _ KeyType = iota
 
134
        RSA
 
135
        DSA
 
136
 
 
137
        Private KeyType = 1 << 3
 
138
        Public  KeyType = 0 << 3
 
139
 
 
140
        RSAPrivate = RSA | Private
 
141
        RSAPublic  = RSA | Public
 
142
        DSAPrivate = DSA | Private
 
143
        DSAPublic  = DSA | Public
 
144
)
 
145
 
 
146
var _ yaml.Getter = Key{}
 
147
 
 
148
// Key represents an SSH Key with the given type and associated key data.
 
149
type Key struct {
 
150
        Type KeyType
 
151
        Data string
 
152
}
 
153
 
 
154
// GetYaml implements yaml.Getter
 
155
func (k Key) GetYAML() (tag string, value interface{}) {
 
156
        return "", []string{k.Type.String(), k.Data}
 
157
}
 
158
 
 
159
func (t KeyType) String() string {
 
160
        var s string
 
161
        switch t &^ (Private | Public) {
 
162
        case RSA:
 
163
                s = "rsa"
 
164
        case DSA:
 
165
                s = "dsa"
 
166
        default:
 
167
                panic("unknown key type")
 
168
        }
 
169
        if t&Private != 0 {
 
170
                s += "_private"
 
171
        } else {
 
172
                s += "_public"
 
173
        }
 
174
        return s
 
175
}
 
176
 
 
177
// OutputSpec represents the destination of a command.
 
178
// Each of Stdout and Stderr can take one of the following forms:
 
179
// >>file
 
180
//      appends to file
 
181
// >file
 
182
//      overwrites file
 
183
// |command
 
184
//      pipes to the given command.
 
185
// If Stderr is "&1", it will be directed to the same
 
186
// place as Stdout.
 
187
type OutputSpec struct {
 
188
        Stdout string
 
189
        Stderr string
 
190
}
 
191
 
 
192
var _ yaml.Getter = (*OutputSpec)(nil)
 
193
 
 
194
func (o *OutputSpec) GetYAML() (tag string, value interface{}) {
 
195
        if o.Stdout == o.Stderr {
 
196
                return "", o.Stdout
 
197
        }
 
198
        return "", []string{o.Stdout, o.Stderr}
 
199
}
 
200
 
 
201
// maybe returns x if yes is true, otherwise it returns nil.
 
202
func maybe(yes bool, x interface{}) interface{} {
 
203
        if yes {
 
204
                return x
 
205
        }
 
206
        return nil
 
207
}