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