// interfacePublicIPAddresses lists all public IP addresses in the resource // group, and returns a mapping from instance ID to the public IP addresses // associated with that instance. func instancePublicIPAddresses( callAPI callAPIFunc, resourceGroup string, pipClient network.PublicIPAddressesClient, ) (map[instance.Id][]network.PublicIPAddress, error) { var pipsResult network.PublicIPAddressListResult if err := callAPI(func() (autorest.Response, error) { var err error pipsResult, err = pipClient.List(resourceGroup) return pipsResult.Response, err }); err != nil { return nil, errors.Annotate(err, "listing public IP addresses") } if pipsResult.Value == nil || len(*pipsResult.Value) == 0 { return nil, nil } instancePips := make(map[instance.Id][]network.PublicIPAddress) for _, pip := range *pipsResult.Value { instanceId := instance.Id(toTags(pip.Tags)[jujuMachineNameTag]) instancePips[instanceId] = append(instancePips[instanceId], pip) } return instancePips, nil }
// setInstanceAddresses queries Azure for the NICs and public IPs associated // with the given set of instances. This assumes that the instances' // VirtualMachines are up-to-date, and that there are no concurrent accesses // to the instances. func setInstanceAddresses( pipClient network.PublicIPAddressesClient, resourceGroup string, instances []*azureInstance, nicsResult network.InterfaceListResult, ) (err error) { instanceNics := make(map[instance.Id][]network.Interface) instancePips := make(map[instance.Id][]network.PublicIPAddress) for _, inst := range instances { instanceNics[inst.Id()] = nil instancePips[inst.Id()] = nil } // When setAddresses returns without error, update each // instance's network interfaces and public IP addresses. setInstanceFields := func(inst *azureInstance) { inst.networkInterfaces = instanceNics[inst.Id()] inst.publicIPAddresses = instancePips[inst.Id()] } defer func() { if err != nil { return } for _, inst := range instances { setInstanceFields(inst) } }() // We do not rely on references because of how StopInstances works. // In order to not leak resources we must not delete the virtual // machine until after all of its dependencies are deleted. // // NICs and PIPs cannot be deleted until they have no references. // Thus, we cannot delete a PIP until there is no reference to it // in any NICs, and likewise we cannot delete a NIC until there // is no reference to it in any virtual machine. if nicsResult.Value != nil { for _, nic := range *nicsResult.Value { instanceId := instance.Id(toTags(nic.Tags)[jujuMachineNameTag]) if _, ok := instanceNics[instanceId]; !ok { continue } instanceNics[instanceId] = append(instanceNics[instanceId], nic) } } pipsResult, err := pipClient.List(resourceGroup) if err != nil { return errors.Annotate(err, "listing public IP addresses") } if pipsResult.Value != nil { for _, pip := range *pipsResult.Value { instanceId := instance.Id(toTags(pip.Tags)[jujuMachineNameTag]) if _, ok := instanceNics[instanceId]; !ok { continue } instancePips[instanceId] = append(instancePips[instanceId], pip) } } // Fields will be assigned to instances by the deferred call. return nil }