32
32
// Note: we use Name and not Id, since all VM operations are in
33
33
// terms of the VM name (qualified by resource group). The ID is
34
34
// an internal detail.
35
return instance.Id(to.String(inst.VirtualMachine.Name))
35
return instance.Id(inst.vmName)
38
38
// Status is specified in the Instance interface.
39
39
func (inst *azureInstance) Status() instance.InstanceStatus {
40
// NOTE(axw) ideally we would use the power state, but that is only
41
// available when using the "instance view". Instance view is only
42
// delivered when explicitly requested, and you can only request it
43
// when querying a single VM. This means the results of AllInstances
44
// or Instances would have the instance view missing.
46
// TODO(axw) if the provisioning state is "Failed", then
47
// we should query the operation status and report the error
40
instanceStatus := status.Empty
41
message := inst.provisioningState
42
switch inst.provisioningState {
44
// TODO(axw) once a VM has been started, we should
45
// start using its power state to show if it's
46
// really running or not. This is just a nice to
47
// have, since we should not expect a VM to ever
49
instanceStatus = status.Running
51
case "Canceled", "Failed":
52
// TODO(axw) if the provisioning state is "Failed", then we
53
// should use the error message from the deployment description
54
// as the Message. The error details are not currently exposed
55
// in the Azure SDK. See:
56
// https://github.com/Azure/azure-sdk-for-go/issues/399
57
instanceStatus = status.ProvisioningError
62
instanceStatus = status.Provisioning
49
64
return instance.InstanceStatus{
50
Status: status.StatusEmpty,
51
Message: to.String(inst.Properties.ProvisioningState),
65
Status: instanceStatus,
56
70
// setInstanceAddresses queries Azure for the NICs and public IPs associated
58
72
// VirtualMachines are up-to-date, and that there are no concurrent accesses
59
73
// to the instances.
60
74
func setInstanceAddresses(
77
nicClient network.InterfacesClient,
61
78
pipClient network.PublicIPAddressesClient,
63
79
instances []*azureInstance,
64
nicsResult network.InterfaceListResult,
67
instanceNics := make(map[instance.Id][]network.Interface)
68
instancePips := make(map[instance.Id][]network.PublicIPAddress)
81
instanceNics, err := instanceNetworkInterfaces(
82
callAPI, resourceGroup, nicClient,
85
return errors.Annotate(err, "listing network interfaces")
87
instancePips, err := instancePublicIPAddresses(
88
callAPI, resourceGroup, pipClient,
91
return errors.Annotate(err, "listing public IP addresses")
69
93
for _, inst := range instances {
70
instanceNics[inst.Id()] = nil
71
instancePips[inst.Id()] = nil
74
// When setAddresses returns without error, update each
75
// instance's network interfaces and public IP addresses.
76
setInstanceFields := func(inst *azureInstance) {
77
94
inst.networkInterfaces = instanceNics[inst.Id()]
78
95
inst.publicIPAddresses = instancePips[inst.Id()]
84
for _, inst := range instances {
85
setInstanceFields(inst)
89
// We do not rely on references because of how StopInstances works.
90
// In order to not leak resources we must not delete the virtual
91
// machine until after all of its dependencies are deleted.
93
// NICs and PIPs cannot be deleted until they have no references.
94
// Thus, we cannot delete a PIP until there is no reference to it
95
// in any NICs, and likewise we cannot delete a NIC until there
96
// is no reference to it in any virtual machine.
98
if nicsResult.Value != nil {
99
for _, nic := range *nicsResult.Value {
100
instanceId := instance.Id(toTags(nic.Tags)[jujuMachineNameTag])
101
if _, ok := instanceNics[instanceId]; !ok {
104
instanceNics[instanceId] = append(instanceNics[instanceId], nic)
108
pipsResult, err := pipClient.List(resourceGroup)
110
return errors.Annotate(err, "listing public IP addresses")
112
if pipsResult.Value != nil {
113
for _, pip := range *pipsResult.Value {
114
instanceId := instance.Id(toTags(pip.Tags)[jujuMachineNameTag])
115
if _, ok := instanceNics[instanceId]; !ok {
118
instancePips[instanceId] = append(instancePips[instanceId], pip)
122
// Fields will be assigned to instances by the deferred call.
100
// instanceNetworkInterfaces lists all network interfaces in the resource
101
// group, and returns a mapping from instance ID to the network interfaces
102
// associated with that instance.
103
func instanceNetworkInterfaces(
105
resourceGroup string,
106
nicClient network.InterfacesClient,
107
) (map[instance.Id][]network.Interface, error) {
108
var nicsResult network.InterfaceListResult
109
if err := callAPI(func() (autorest.Response, error) {
111
nicsResult, err = nicClient.List(resourceGroup)
112
return nicsResult.Response, err
114
return nil, errors.Annotate(err, "listing network interfaces")
116
if nicsResult.Value == nil || len(*nicsResult.Value) == 0 {
119
instanceNics := make(map[instance.Id][]network.Interface)
120
for _, nic := range *nicsResult.Value {
121
instanceId := instance.Id(toTags(nic.Tags)[jujuMachineNameTag])
122
instanceNics[instanceId] = append(instanceNics[instanceId], nic)
124
return instanceNics, nil
127
// interfacePublicIPAddresses lists all public IP addresses in the resource
128
// group, and returns a mapping from instance ID to the public IP addresses
129
// associated with that instance.
130
func instancePublicIPAddresses(
132
resourceGroup string,
133
pipClient network.PublicIPAddressesClient,
134
) (map[instance.Id][]network.PublicIPAddress, error) {
135
var pipsResult network.PublicIPAddressListResult
136
if err := callAPI(func() (autorest.Response, error) {
138
pipsResult, err = pipClient.List(resourceGroup)
139
return pipsResult.Response, err
141
return nil, errors.Annotate(err, "listing public IP addresses")
143
if pipsResult.Value == nil || len(*pipsResult.Value) == 0 {
146
instancePips := make(map[instance.Id][]network.PublicIPAddress)
147
for _, pip := range *pipsResult.Value {
148
instanceId := instance.Id(toTags(pip.Tags)[jujuMachineNameTag])
149
instancePips[instanceId] = append(instancePips[instanceId], pip)
151
return instancePips, nil
126
154
// Addresses is specified in the Instance interface.
127
155
func (inst *azureInstance) Addresses() ([]jujunetwork.Address, error) {
128
156
addresses := make([]jujunetwork.Address, 0, len(inst.networkInterfaces)+len(inst.publicIPAddresses))