github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/api/provisioner/machine.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package provisioner 5 6 import ( 7 "fmt" 8 9 "github.com/juju/names" 10 11 "github.com/juju/juju/api/watcher" 12 "github.com/juju/juju/apiserver/params" 13 "github.com/juju/juju/instance" 14 "github.com/juju/juju/storage" 15 ) 16 17 // Machine represents a juju machine as seen by the provisioner worker. 18 type Machine struct { 19 tag names.MachineTag 20 life params.Life 21 st *State 22 } 23 24 // Tag returns the machine's tag. 25 func (m *Machine) Tag() names.Tag { 26 return m.tag 27 } 28 29 // Id returns the machine id. 30 func (m *Machine) Id() string { 31 return m.tag.Id() 32 } 33 34 // String returns the machine as a string. 35 func (m *Machine) String() string { 36 return m.Id() 37 } 38 39 // Life returns the machine's lifecycle value. 40 func (m *Machine) Life() params.Life { 41 return m.life 42 } 43 44 // Refresh updates the cached local copy of the machine's data. 45 func (m *Machine) Refresh() error { 46 life, err := m.st.machineLife(m.tag) 47 if err != nil { 48 return err 49 } 50 m.life = life 51 return nil 52 } 53 54 // ProvisioningInfo returns the information required to provisiong a machine. 55 func (m *Machine) ProvisioningInfo() (*params.ProvisioningInfo, error) { 56 var results params.ProvisioningInfoResults 57 args := params.Entities{Entities: []params.Entity{{m.tag.String()}}} 58 err := m.st.facade.FacadeCall("ProvisioningInfo", args, &results) 59 if err != nil { 60 return nil, err 61 } 62 if len(results.Results) != 1 { 63 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 64 } 65 result := results.Results[0] 66 if result.Error != nil { 67 return nil, result.Error 68 } 69 return result.Result, nil 70 } 71 72 // SetStatus sets the status of the machine. 73 func (m *Machine) SetStatus(status params.Status, info string, data map[string]interface{}) error { 74 var result params.ErrorResults 75 args := params.SetStatus{ 76 Entities: []params.EntityStatus{ 77 {Tag: m.tag.String(), Status: status, Info: info, Data: data}, 78 }, 79 } 80 err := m.st.facade.FacadeCall("SetStatus", args, &result) 81 if err != nil { 82 return err 83 } 84 return result.OneError() 85 } 86 87 // Status returns the status of the machine. 88 func (m *Machine) Status() (params.Status, string, error) { 89 var results params.StatusResults 90 args := params.Entities{ 91 Entities: []params.Entity{{Tag: m.tag.String()}}, 92 } 93 err := m.st.facade.FacadeCall("Status", args, &results) 94 if err != nil { 95 return "", "", err 96 } 97 if len(results.Results) != 1 { 98 return "", "", fmt.Errorf("expected 1 result, got %d", len(results.Results)) 99 } 100 result := results.Results[0] 101 if result.Error != nil { 102 return "", "", result.Error 103 } 104 return result.Status, result.Info, nil 105 } 106 107 // EnsureDead sets the machine lifecycle to Dead if it is Alive or 108 // Dying. It does nothing otherwise. 109 func (m *Machine) EnsureDead() error { 110 var result params.ErrorResults 111 args := params.Entities{ 112 Entities: []params.Entity{{Tag: m.tag.String()}}, 113 } 114 err := m.st.facade.FacadeCall("EnsureDead", args, &result) 115 if err != nil { 116 return err 117 } 118 return result.OneError() 119 } 120 121 // Remove removes the machine from state. It will fail if the machine 122 // is not Dead. 123 func (m *Machine) Remove() error { 124 var result params.ErrorResults 125 args := params.Entities{ 126 Entities: []params.Entity{{Tag: m.tag.String()}}, 127 } 128 err := m.st.facade.FacadeCall("Remove", args, &result) 129 if err != nil { 130 return err 131 } 132 return result.OneError() 133 } 134 135 // Series returns the operating system series running on the machine. 136 // 137 // NOTE: Unlike state.Machine.Series(), this method returns an error 138 // as well, because it needs to do an API call. 139 func (m *Machine) Series() (string, error) { 140 var results params.StringResults 141 args := params.Entities{ 142 Entities: []params.Entity{{Tag: m.tag.String()}}, 143 } 144 err := m.st.facade.FacadeCall("Series", args, &results) 145 if err != nil { 146 return "", err 147 } 148 if len(results.Results) != 1 { 149 return "", fmt.Errorf("expected 1 result, got %d", len(results.Results)) 150 } 151 result := results.Results[0] 152 if result.Error != nil { 153 return "", result.Error 154 } 155 return result.Result, nil 156 } 157 158 // DistributionGroup returns a slice of instance.Ids 159 // that belong to the same distribution group as this 160 // Machine. The provisioner may use this information 161 // to distribute instances for high availability. 162 func (m *Machine) DistributionGroup() ([]instance.Id, error) { 163 var results params.DistributionGroupResults 164 args := params.Entities{ 165 Entities: []params.Entity{{Tag: m.tag.String()}}, 166 } 167 err := m.st.facade.FacadeCall("DistributionGroup", args, &results) 168 if err != nil { 169 return nil, err 170 } 171 if len(results.Results) != 1 { 172 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 173 } 174 result := results.Results[0] 175 if result.Error != nil { 176 return nil, result.Error 177 } 178 return result.Result, nil 179 } 180 181 // SetInstanceInfo sets the provider specific instance id, nonce, 182 // metadata, networks and interfaces for this machine. Once set, the 183 // instance id cannot be changed. 184 func (m *Machine) SetInstanceInfo( 185 id instance.Id, nonce string, characteristics *instance.HardwareCharacteristics, 186 networks []params.Network, interfaces []params.NetworkInterface, volumes []storage.BlockDevice, 187 ) error { 188 var result params.ErrorResults 189 args := params.InstancesInfo{ 190 Machines: []params.InstanceInfo{{ 191 Tag: m.tag.String(), 192 InstanceId: id, 193 Nonce: nonce, 194 Characteristics: characteristics, 195 Networks: networks, 196 Interfaces: interfaces, 197 Volumes: volumes, 198 }}, 199 } 200 err := m.st.facade.FacadeCall("SetInstanceInfo", args, &result) 201 if err != nil { 202 return err 203 } 204 return result.OneError() 205 } 206 207 // InstanceId returns the provider specific instance id for the 208 // machine or an CodeNotProvisioned error, if not set. 209 func (m *Machine) InstanceId() (instance.Id, error) { 210 var results params.StringResults 211 args := params.Entities{ 212 Entities: []params.Entity{{Tag: m.tag.String()}}, 213 } 214 err := m.st.facade.FacadeCall("InstanceId", args, &results) 215 if err != nil { 216 return "", err 217 } 218 if len(results.Results) != 1 { 219 return "", fmt.Errorf("expected 1 result, got %d", len(results.Results)) 220 } 221 result := results.Results[0] 222 if result.Error != nil { 223 return "", result.Error 224 } 225 return instance.Id(result.Result), nil 226 } 227 228 // SetPassword sets the machine's password. 229 func (m *Machine) SetPassword(password string) error { 230 var result params.ErrorResults 231 args := params.EntityPasswords{ 232 Changes: []params.EntityPassword{ 233 {Tag: m.tag.String(), Password: password}, 234 }, 235 } 236 err := m.st.facade.FacadeCall("SetPasswords", args, &result) 237 if err != nil { 238 return err 239 } 240 return result.OneError() 241 } 242 243 // WatchContainers returns a StringsWatcher that notifies of changes 244 // to the lifecycles of containers of the specified type on the machine. 245 func (m *Machine) WatchContainers(ctype instance.ContainerType) (watcher.StringsWatcher, error) { 246 if string(ctype) == "" { 247 return nil, fmt.Errorf("container type must be specified") 248 } 249 supported := false 250 for _, c := range instance.ContainerTypes { 251 if ctype == c { 252 supported = true 253 break 254 } 255 } 256 if !supported { 257 return nil, fmt.Errorf("unsupported container type %q", ctype) 258 } 259 var results params.StringsWatchResults 260 args := params.WatchContainers{ 261 Params: []params.WatchContainer{ 262 {MachineTag: m.tag.String(), ContainerType: string(ctype)}, 263 }, 264 } 265 err := m.st.facade.FacadeCall("WatchContainers", args, &results) 266 if err != nil { 267 return nil, err 268 } 269 if len(results.Results) != 1 { 270 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 271 } 272 result := results.Results[0] 273 if result.Error != nil { 274 return nil, result.Error 275 } 276 w := watcher.NewStringsWatcher(m.st.facade.RawAPICaller(), result) 277 return w, nil 278 } 279 280 // WatchAllContainers returns a StringsWatcher that notifies of changes 281 // to the lifecycles of all containers on the machine. 282 func (m *Machine) WatchAllContainers() (watcher.StringsWatcher, error) { 283 var results params.StringsWatchResults 284 args := params.WatchContainers{ 285 Params: []params.WatchContainer{ 286 {MachineTag: m.tag.String()}, 287 }, 288 } 289 err := m.st.facade.FacadeCall("WatchContainers", args, &results) 290 if err != nil { 291 return nil, err 292 } 293 if len(results.Results) != 1 { 294 return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results)) 295 } 296 result := results.Results[0] 297 if result.Error != nil { 298 return nil, result.Error 299 } 300 w := watcher.NewStringsWatcher(m.st.facade.RawAPICaller(), result) 301 return w, nil 302 } 303 304 // SetSupportedContainers updates the list of containers supported by this machine. 305 func (m *Machine) SetSupportedContainers(containerTypes ...instance.ContainerType) error { 306 var results params.ErrorResults 307 args := params.MachineContainersParams{ 308 Params: []params.MachineContainers{ 309 {MachineTag: m.tag.String(), ContainerTypes: containerTypes}, 310 }, 311 } 312 err := m.st.facade.FacadeCall("SetSupportedContainers", args, &results) 313 if err != nil { 314 return err 315 } 316 if len(results.Results) != 1 { 317 return fmt.Errorf("expected 1 result, got %d", len(results.Results)) 318 } 319 apiError := results.Results[0].Error 320 if apiError != nil { 321 return apiError 322 } 323 return nil 324 } 325 326 // SupportsNoContainers records the fact that this machine doesn't support any containers. 327 func (m *Machine) SupportsNoContainers() error { 328 return m.SetSupportedContainers([]instance.ContainerType{}...) 329 }