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