// createInternalSubnet creates an internal subnet for the specified resource group, // within the specified virtual network. // // NOTE(axw) this method expects an up-to-date VirtualNetwork, and expects that are // no concurrent subnet additions to the virtual network. At the moment we have only // three places where we modify subnets: at bootstrap, when a new environment is // created, and when an environment is destroyed. func createInternalSubnet( client network.ManagementClient, resourceGroup string, vnet *network.VirtualNetwork, location string, tags map[string]string, ) (*network.Subnet, error) { nextAddressPrefix := (*vnet.Properties.AddressSpace.AddressPrefixes)[0] if vnet.Properties.Subnets != nil { if len(*vnet.Properties.Subnets) == len(*vnet.Properties.AddressSpace.AddressPrefixes) { return nil, errors.Errorf( "no available address prefixes in vnet %q", to.String(vnet.Name), ) } addressPrefixesInUse := make(set.Strings) for _, subnet := range *vnet.Properties.Subnets { addressPrefixesInUse.Add(to.String(subnet.Properties.AddressPrefix)) } for _, addressPrefix := range *vnet.Properties.AddressSpace.AddressPrefixes { if !addressPrefixesInUse.Contains(addressPrefix) { nextAddressPrefix = addressPrefix break } } } // Create a network security group for the environment. There is only // one NSG per environment (there's a limit of 100 per subscription), // in which we manage rules for each exposed machine. securityRules := []network.SecurityRule{sshSecurityRule} securityGroupParams := network.SecurityGroup{ Location: to.StringPtr(location), Tags: toTagsPtr(tags), Properties: &network.SecurityGroupPropertiesFormat{ SecurityRules: &securityRules, }, } securityGroupClient := network.SecurityGroupsClient{client} securityGroupName := internalSecurityGroupName logger.Debugf("creating security group %q", securityGroupName) nsg, err := securityGroupClient.CreateOrUpdate( resourceGroup, securityGroupName, securityGroupParams, ) if err != nil { return nil, errors.Annotatef(err, "creating security group %q", securityGroupName) } // Now create a subnet with the next available address prefix, and // associate the subnet with the NSG created above. subnetName := internalSubnetName subnetParams := network.Subnet{ Properties: &network.SubnetPropertiesFormat{ AddressPrefix: to.StringPtr(nextAddressPrefix), NetworkSecurityGroup: &network.SubResource{nsg.ID}, }, } logger.Debugf("creating subnet %q (%s)", subnetName, nextAddressPrefix) subnetClient := network.SubnetsClient{client} subnet, err := subnetClient.CreateOrUpdate( resourceGroup, internalNetworkName, subnetName, subnetParams, ) if err != nil { return nil, errors.Annotatef(err, "creating subnet %q", subnetName) } return &subnet, nil }
// createInternalSubnet creates an internal subnet for the specified resource group, // within the specified virtual network. // // Subnets are tied to the resource group of the virtual network, so we must create // them all in the controller resource group. We create the network security group // for the subnet in the environment's resource group. // // NOTE(axw) this method expects an up-to-date VirtualNetwork, and expects that are // no concurrent subnet additions to the virtual network. At the moment we have only // three places where we modify subnets: at bootstrap, when a new environment is // created, and when an environment is destroyed. func createInternalSubnet( client network.ManagementClient, resourceGroup, controllerResourceGroup string, vnet *network.VirtualNetwork, location string, tags map[string]string, ) (*network.Subnet, error) { nextAddressPrefix := (*vnet.Properties.AddressSpace.AddressPrefixes)[0] if vnet.Properties.Subnets != nil { if len(*vnet.Properties.Subnets) == len(*vnet.Properties.AddressSpace.AddressPrefixes) { return nil, errors.Errorf( "no available address prefixes in vnet %q", to.String(vnet.Name), ) } addressPrefixesInUse := make(set.Strings) for _, subnet := range *vnet.Properties.Subnets { addressPrefixesInUse.Add(to.String(subnet.Properties.AddressPrefix)) } for _, addressPrefix := range *vnet.Properties.AddressSpace.AddressPrefixes { if !addressPrefixesInUse.Contains(addressPrefix) { nextAddressPrefix = addressPrefix break } } } // Create a network security group for the environment. There is only // one NSG per environment (there's a limit of 100 per subscription), // in which we manage rules for each exposed machine. securityRules := []network.SecurityRule{sshSecurityRule} securityGroupParams := network.SecurityGroup{ Location: to.StringPtr(location), Tags: toTagsPtr(tags), Properties: &network.SecurityGroupPropertiesFormat{ SecurityRules: &securityRules, }, } securityGroupClient := network.SecurityGroupsClient{client} securityGroupName := internalSecurityGroupName logger.Debugf("creating security group %q", securityGroupName) _, err := securityGroupClient.CreateOrUpdate( resourceGroup, securityGroupName, securityGroupParams, ) if err != nil { return nil, errors.Annotatef(err, "creating security group %q", securityGroupName) } // Now create a subnet with the next available address prefix. The // subnet must be created in the controller resource group, as it // must be co-located with the vnet. subnetName := resourceGroup subnetParams := network.Subnet{ Properties: &network.SubnetPropertiesFormat{ AddressPrefix: to.StringPtr(nextAddressPrefix), // NOTE(axw) we do NOT want to set the network security // group as default for the subnet, because that will // create a dependency from the controller resource // group to environment resource groups. Instead, we // set the NSG on NICs. }, } logger.Debugf("creating subnet %q (%s)", subnetName, nextAddressPrefix) subnetClient := network.SubnetsClient{client} subnet, err := subnetClient.CreateOrUpdate( controllerResourceGroup, internalNetworkName, subnetName, subnetParams, ) if err != nil { return nil, errors.Annotatef(err, "creating subnet %q", subnetName) } return &subnet, nil }