~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/instance/instance.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package instance
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "math"
 
9
        "strconv"
 
10
        "strings"
 
11
 
 
12
        "github.com/juju/utils/arch"
 
13
 
 
14
        "github.com/juju/juju/network"
 
15
        "github.com/juju/juju/status"
 
16
)
 
17
 
 
18
// An instance Id is a provider-specific identifier associated with an
 
19
// instance (physical or virtual machine allocated in the provider).
 
20
type Id string
 
21
 
 
22
// InstanceStatus represents the status for a provider instance.
 
23
type InstanceStatus struct {
 
24
        Status  status.Status
 
25
        Message string
 
26
}
 
27
 
 
28
// UnknownId can be used to explicitly specify the instance ID does not matter.
 
29
const UnknownId Id = ""
 
30
 
 
31
// Instance represents the the realization of a machine in state.
 
32
type Instance interface {
 
33
        // Id returns a provider-generated identifier for the Instance.
 
34
        Id() Id
 
35
 
 
36
        // Status returns the provider-specific status for the instance.
 
37
        Status() InstanceStatus
 
38
 
 
39
        // Addresses returns a list of hostnames or ip addresses
 
40
        // associated with the instance.
 
41
        Addresses() ([]network.Address, error)
 
42
 
 
43
        // OpenPorts opens the given port ranges on the instance, which
 
44
        // should have been started with the given machine id.
 
45
        OpenPorts(machineId string, ports []network.PortRange) error
 
46
 
 
47
        // ClosePorts closes the given port ranges on the instance, which
 
48
        // should have been started with the given machine id.
 
49
        ClosePorts(machineId string, ports []network.PortRange) error
 
50
 
 
51
        // Ports returns the set of port ranges open on the instance,
 
52
        // which should have been started with the given machine id. The
 
53
        // port ranges are returned as sorted by network.SortPortRanges().
 
54
        Ports(machineId string) ([]network.PortRange, error)
 
55
}
 
56
 
 
57
// HardwareCharacteristics represents the characteristics of the instance (if known).
 
58
// Attributes that are nil are unknown or not supported.
 
59
type HardwareCharacteristics struct {
 
60
        Arch     *string   `json:"arch,omitempty" yaml:"arch,omitempty"`
 
61
        Mem      *uint64   `json:"mem,omitempty" yaml:"mem,omitempty"`
 
62
        RootDisk *uint64   `json:"root-disk,omitempty" yaml:"rootdisk,omitempty"`
 
63
        CpuCores *uint64   `json:"cpu-cores,omitempty" yaml:"cpucores,omitempty"`
 
64
        CpuPower *uint64   `json:"cpu-power,omitempty" yaml:"cpupower,omitempty"`
 
65
        Tags     *[]string `json:"tags,omitempty" yaml:"tags,omitempty"`
 
66
 
 
67
        AvailabilityZone *string `json:"availability-zone,omitempty" yaml:"availabilityzone,omitempty"`
 
68
}
 
69
 
 
70
func (hc HardwareCharacteristics) String() string {
 
71
        var strs []string
 
72
        if hc.Arch != nil {
 
73
                strs = append(strs, fmt.Sprintf("arch=%s", *hc.Arch))
 
74
        }
 
75
        if hc.CpuCores != nil {
 
76
                strs = append(strs, fmt.Sprintf("cpu-cores=%d", *hc.CpuCores))
 
77
        }
 
78
        if hc.CpuPower != nil {
 
79
                strs = append(strs, fmt.Sprintf("cpu-power=%d", *hc.CpuPower))
 
80
        }
 
81
        if hc.Mem != nil {
 
82
                strs = append(strs, fmt.Sprintf("mem=%dM", *hc.Mem))
 
83
        }
 
84
        if hc.RootDisk != nil {
 
85
                strs = append(strs, fmt.Sprintf("root-disk=%dM", *hc.RootDisk))
 
86
        }
 
87
        if hc.Tags != nil && len(*hc.Tags) > 0 {
 
88
                strs = append(strs, fmt.Sprintf("tags=%s", strings.Join(*hc.Tags, ",")))
 
89
        }
 
90
        if hc.AvailabilityZone != nil && *hc.AvailabilityZone != "" {
 
91
                strs = append(strs, fmt.Sprintf("availability-zone=%s", *hc.AvailabilityZone))
 
92
        }
 
93
        return strings.Join(strs, " ")
 
94
}
 
95
 
 
96
// Implement gnuflag.Value
 
97
func (hc *HardwareCharacteristics) Set(s string) error {
 
98
        parsed, err := ParseHardware(s)
 
99
        if err != nil {
 
100
                return err
 
101
        }
 
102
        *hc = parsed
 
103
        return nil
 
104
}
 
105
 
 
106
// MustParseHardware constructs a HardwareCharacteristics from the supplied arguments,
 
107
// as Parse, but panics on failure.
 
108
func MustParseHardware(args ...string) HardwareCharacteristics {
 
109
        hc, err := ParseHardware(args...)
 
110
        if err != nil {
 
111
                panic(err)
 
112
        }
 
113
        return hc
 
114
}
 
115
 
 
116
// ParseHardware constructs a HardwareCharacteristics from the supplied arguments,
 
117
// each of which must contain only spaces and name=value pairs. If any
 
118
// name is specified more than once, an error is returned.
 
119
func ParseHardware(args ...string) (HardwareCharacteristics, error) {
 
120
        hc := HardwareCharacteristics{}
 
121
        for _, arg := range args {
 
122
                raws := strings.Split(strings.TrimSpace(arg), " ")
 
123
                for _, raw := range raws {
 
124
                        if raw == "" {
 
125
                                continue
 
126
                        }
 
127
                        if err := hc.setRaw(raw); err != nil {
 
128
                                return HardwareCharacteristics{}, err
 
129
                        }
 
130
                }
 
131
        }
 
132
        return hc, nil
 
133
}
 
134
 
 
135
// setRaw interprets a name=value string and sets the supplied value.
 
136
func (hc *HardwareCharacteristics) setRaw(raw string) error {
 
137
        eq := strings.Index(raw, "=")
 
138
        if eq <= 0 {
 
139
                return fmt.Errorf("malformed characteristic %q", raw)
 
140
        }
 
141
        name, str := raw[:eq], raw[eq+1:]
 
142
        var err error
 
143
        switch name {
 
144
        case "arch":
 
145
                err = hc.setArch(str)
 
146
        case "cpu-cores":
 
147
                err = hc.setCpuCores(str)
 
148
        case "cpu-power":
 
149
                err = hc.setCpuPower(str)
 
150
        case "mem":
 
151
                err = hc.setMem(str)
 
152
        case "root-disk":
 
153
                err = hc.setRootDisk(str)
 
154
        case "tags":
 
155
                err = hc.setTags(str)
 
156
        case "availability-zone":
 
157
                err = hc.setAvailabilityZone(str)
 
158
        default:
 
159
                return fmt.Errorf("unknown characteristic %q", name)
 
160
        }
 
161
        if err != nil {
 
162
                return fmt.Errorf("bad %q characteristic: %v", name, err)
 
163
        }
 
164
        return nil
 
165
}
 
166
 
 
167
func (hc *HardwareCharacteristics) setArch(str string) error {
 
168
        if hc.Arch != nil {
 
169
                return fmt.Errorf("already set")
 
170
        }
 
171
        if str != "" && !arch.IsSupportedArch(str) {
 
172
                return fmt.Errorf("%q not recognized", str)
 
173
        }
 
174
        hc.Arch = &str
 
175
        return nil
 
176
}
 
177
 
 
178
func (hc *HardwareCharacteristics) setCpuCores(str string) (err error) {
 
179
        if hc.CpuCores != nil {
 
180
                return fmt.Errorf("already set")
 
181
        }
 
182
        hc.CpuCores, err = parseUint64(str)
 
183
        return
 
184
}
 
185
 
 
186
func (hc *HardwareCharacteristics) setCpuPower(str string) (err error) {
 
187
        if hc.CpuPower != nil {
 
188
                return fmt.Errorf("already set")
 
189
        }
 
190
        hc.CpuPower, err = parseUint64(str)
 
191
        return
 
192
}
 
193
 
 
194
func (hc *HardwareCharacteristics) setMem(str string) (err error) {
 
195
        if hc.Mem != nil {
 
196
                return fmt.Errorf("already set")
 
197
        }
 
198
        hc.Mem, err = parseSize(str)
 
199
        return
 
200
}
 
201
 
 
202
func (hc *HardwareCharacteristics) setRootDisk(str string) (err error) {
 
203
        if hc.RootDisk != nil {
 
204
                return fmt.Errorf("already set")
 
205
        }
 
206
        hc.RootDisk, err = parseSize(str)
 
207
        return
 
208
}
 
209
 
 
210
func (hc *HardwareCharacteristics) setTags(str string) (err error) {
 
211
        if hc.Tags != nil {
 
212
                return fmt.Errorf("already set")
 
213
        }
 
214
        hc.Tags = parseTags(str)
 
215
        return
 
216
}
 
217
 
 
218
func (hc *HardwareCharacteristics) setAvailabilityZone(str string) error {
 
219
        if hc.AvailabilityZone != nil {
 
220
                return fmt.Errorf("already set")
 
221
        }
 
222
        if str != "" {
 
223
                hc.AvailabilityZone = &str
 
224
        }
 
225
        return nil
 
226
}
 
227
 
 
228
// parseTags returns the tags in the value s
 
229
func parseTags(s string) *[]string {
 
230
        if s == "" {
 
231
                return &[]string{}
 
232
        }
 
233
        tags := strings.Split(s, ",")
 
234
        return &tags
 
235
}
 
236
 
 
237
func parseUint64(str string) (*uint64, error) {
 
238
        var value uint64
 
239
        if str != "" {
 
240
                if val, err := strconv.ParseUint(str, 10, 64); err != nil {
 
241
                        return nil, fmt.Errorf("must be a non-negative integer")
 
242
                } else {
 
243
                        value = uint64(val)
 
244
                }
 
245
        }
 
246
        return &value, nil
 
247
}
 
248
 
 
249
func parseSize(str string) (*uint64, error) {
 
250
        var value uint64
 
251
        if str != "" {
 
252
                mult := 1.0
 
253
                if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
 
254
                        str = str[:len(str)-1]
 
255
                        mult = m
 
256
                }
 
257
                val, err := strconv.ParseFloat(str, 64)
 
258
                if err != nil || val < 0 {
 
259
                        return nil, fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
 
260
                }
 
261
                val *= mult
 
262
                value = uint64(math.Ceil(val))
 
263
        }
 
264
        return &value, nil
 
265
}
 
266
 
 
267
var mbSuffixes = map[string]float64{
 
268
        "M": 1,
 
269
        "G": 1024,
 
270
        "T": 1024 * 1024,
 
271
        "P": 1024 * 1024 * 1024,
 
272
}