github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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/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 is the architecture of the processor. 61 Arch *string `json:"arch,omitempty" yaml:"arch,omitempty"` 62 63 // Mem is the size of RAM in megabytes. 64 Mem *uint64 `json:"mem,omitempty" yaml:"mem,omitempty"` 65 66 // RootDisk is the size of the disk in megabytes. 67 RootDisk *uint64 `json:"root-disk,omitempty" yaml:"rootdisk,omitempty"` 68 69 // CpuCores is the number of logical cores the processor has. 70 CpuCores *uint64 `json:"cpu-cores,omitempty" yaml:"cpucores,omitempty"` 71 72 // CpuPower is a relative representation of the speed of the processor. 73 CpuPower *uint64 `json:"cpu-power,omitempty" yaml:"cpupower,omitempty"` 74 75 // Tags is a list of strings that identify the machine. 76 Tags *[]string `json:"tags,omitempty" yaml:"tags,omitempty"` 77 78 // AvailabilityZone defines the zone in which the machine resides. 79 AvailabilityZone *string `json:"availability-zone,omitempty" yaml:"availabilityzone,omitempty"` 80 } 81 82 func (hc HardwareCharacteristics) String() string { 83 var strs []string 84 if hc.Arch != nil { 85 strs = append(strs, fmt.Sprintf("arch=%s", *hc.Arch)) 86 } 87 if hc.CpuCores != nil { 88 strs = append(strs, fmt.Sprintf("cores=%d", *hc.CpuCores)) 89 } 90 if hc.CpuPower != nil { 91 strs = append(strs, fmt.Sprintf("cpu-power=%d", *hc.CpuPower)) 92 } 93 if hc.Mem != nil { 94 strs = append(strs, fmt.Sprintf("mem=%dM", *hc.Mem)) 95 } 96 if hc.RootDisk != nil { 97 strs = append(strs, fmt.Sprintf("root-disk=%dM", *hc.RootDisk)) 98 } 99 if hc.Tags != nil && len(*hc.Tags) > 0 { 100 strs = append(strs, fmt.Sprintf("tags=%s", strings.Join(*hc.Tags, ","))) 101 } 102 if hc.AvailabilityZone != nil && *hc.AvailabilityZone != "" { 103 strs = append(strs, fmt.Sprintf("availability-zone=%s", *hc.AvailabilityZone)) 104 } 105 return strings.Join(strs, " ") 106 } 107 108 // MustParseHardware constructs a HardwareCharacteristics from the supplied arguments, 109 // as Parse, but panics on failure. 110 func MustParseHardware(args ...string) HardwareCharacteristics { 111 hc, err := ParseHardware(args...) 112 if err != nil { 113 panic(err) 114 } 115 return hc 116 } 117 118 // ParseHardware constructs a HardwareCharacteristics from the supplied arguments, 119 // each of which must contain only spaces and name=value pairs. If any 120 // name is specified more than once, an error is returned. 121 func ParseHardware(args ...string) (HardwareCharacteristics, error) { 122 hc := HardwareCharacteristics{} 123 for _, arg := range args { 124 raws := strings.Split(strings.TrimSpace(arg), " ") 125 for _, raw := range raws { 126 if raw == "" { 127 continue 128 } 129 if err := hc.setRaw(raw); err != nil { 130 return HardwareCharacteristics{}, err 131 } 132 } 133 } 134 return hc, nil 135 } 136 137 // setRaw interprets a name=value string and sets the supplied value. 138 func (hc *HardwareCharacteristics) setRaw(raw string) error { 139 eq := strings.Index(raw, "=") 140 if eq <= 0 { 141 return fmt.Errorf("malformed characteristic %q", raw) 142 } 143 name, str := raw[:eq], raw[eq+1:] 144 var err error 145 switch name { 146 case "arch": 147 err = hc.setArch(str) 148 case "cores": 149 err = hc.setCpuCores(str) 150 case "cpu-power": 151 err = hc.setCpuPower(str) 152 case "mem": 153 err = hc.setMem(str) 154 case "root-disk": 155 err = hc.setRootDisk(str) 156 case "tags": 157 err = hc.setTags(str) 158 case "availability-zone": 159 err = hc.setAvailabilityZone(str) 160 default: 161 return fmt.Errorf("unknown characteristic %q", name) 162 } 163 if err != nil { 164 return fmt.Errorf("bad %q characteristic: %v", name, err) 165 } 166 return nil 167 } 168 169 func (hc *HardwareCharacteristics) setArch(str string) error { 170 if hc.Arch != nil { 171 return fmt.Errorf("already set") 172 } 173 if str != "" && !arch.IsSupportedArch(str) { 174 return fmt.Errorf("%q not recognized", str) 175 } 176 hc.Arch = &str 177 return nil 178 } 179 180 func (hc *HardwareCharacteristics) setCpuCores(str string) (err error) { 181 if hc.CpuCores != nil { 182 return fmt.Errorf("already set") 183 } 184 hc.CpuCores, err = parseUint64(str) 185 return 186 } 187 188 func (hc *HardwareCharacteristics) setCpuPower(str string) (err error) { 189 if hc.CpuPower != nil { 190 return fmt.Errorf("already set") 191 } 192 hc.CpuPower, err = parseUint64(str) 193 return 194 } 195 196 func (hc *HardwareCharacteristics) setMem(str string) (err error) { 197 if hc.Mem != nil { 198 return fmt.Errorf("already set") 199 } 200 hc.Mem, err = parseSize(str) 201 return 202 } 203 204 func (hc *HardwareCharacteristics) setRootDisk(str string) (err error) { 205 if hc.RootDisk != nil { 206 return fmt.Errorf("already set") 207 } 208 hc.RootDisk, err = parseSize(str) 209 return 210 } 211 212 func (hc *HardwareCharacteristics) setTags(str string) (err error) { 213 if hc.Tags != nil { 214 return fmt.Errorf("already set") 215 } 216 hc.Tags = parseTags(str) 217 return 218 } 219 220 func (hc *HardwareCharacteristics) setAvailabilityZone(str string) error { 221 if hc.AvailabilityZone != nil { 222 return fmt.Errorf("already set") 223 } 224 if str != "" { 225 hc.AvailabilityZone = &str 226 } 227 return nil 228 } 229 230 // parseTags returns the tags in the value s 231 func parseTags(s string) *[]string { 232 if s == "" { 233 return &[]string{} 234 } 235 tags := strings.Split(s, ",") 236 return &tags 237 } 238 239 func parseUint64(str string) (*uint64, error) { 240 var value uint64 241 if str != "" { 242 if val, err := strconv.ParseUint(str, 10, 64); err != nil { 243 return nil, fmt.Errorf("must be a non-negative integer") 244 } else { 245 value = uint64(val) 246 } 247 } 248 return &value, nil 249 } 250 251 func parseSize(str string) (*uint64, error) { 252 var value uint64 253 if str != "" { 254 mult := 1.0 255 if m, ok := mbSuffixes[str[len(str)-1:]]; ok { 256 str = str[:len(str)-1] 257 mult = m 258 } 259 val, err := strconv.ParseFloat(str, 64) 260 if err != nil || val < 0 { 261 return nil, fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix") 262 } 263 val *= mult 264 value = uint64(math.Ceil(val)) 265 } 266 return &value, nil 267 } 268 269 var mbSuffixes = map[string]float64{ 270 "M": 1, 271 "G": 1024, 272 "T": 1024 * 1024, 273 "P": 1024 * 1024 * 1024, 274 }