Example #1
0
func (v *azureVolumeSource) attachVolume(
	vm *compute.VirtualMachine,
	p storage.VolumeAttachmentParams,
) (_ *storage.VolumeAttachment, updated bool, _ error) {

	dataDisksRoot := dataDiskVhdRoot(v.env.config.location, v.env.config.storageAccount)
	dataDiskName := p.VolumeId
	vhdURI := dataDisksRoot + dataDiskName + vhdExtension

	var dataDisks []compute.DataDisk
	if vm.Properties.StorageProfile.DataDisks != nil {
		dataDisks = *vm.Properties.StorageProfile.DataDisks
	}
	for _, disk := range dataDisks {
		if to.String(disk.Name) != p.VolumeId {
			continue
		}
		if to.String(disk.Vhd.URI) != vhdURI {
			continue
		}
		// Disk is already attached.
		volumeAttachment := &storage.VolumeAttachment{
			p.Volume,
			p.Machine,
			storage.VolumeAttachmentInfo{
				BusAddress: diskBusAddress(to.Int(disk.Lun)),
			},
		}
		return volumeAttachment, false, nil
	}

	lun, err := nextAvailableLUN(vm)
	if err != nil {
		return nil, false, errors.Annotate(err, "choosing LUN")
	}

	dataDisk := compute.DataDisk{
		Lun:          to.IntPtr(lun),
		Name:         to.StringPtr(dataDiskName),
		Vhd:          &compute.VirtualHardDisk{to.StringPtr(vhdURI)},
		Caching:      compute.ReadWrite,
		CreateOption: compute.Attach,
	}
	dataDisks = append(dataDisks, dataDisk)
	vm.Properties.StorageProfile.DataDisks = &dataDisks

	volumeAttachment := storage.VolumeAttachment{
		p.Volume,
		p.Machine,
		storage.VolumeAttachmentInfo{
			BusAddress: diskBusAddress(lun),
		},
	}
	return &volumeAttachment, true, nil
}
Example #2
0
// nextSecurityRulePriority returns the next available priority in the given
// security group within a specified range.
func nextSecurityRulePriority(group network.SecurityGroup, min, max int) (int, error) {
	if group.Properties.SecurityRules == nil {
		return min, nil
	}
	for p := min; p <= max; p++ {
		var found bool
		for _, rule := range *group.Properties.SecurityRules {
			if to.Int(rule.Properties.Priority) == p {
				found = true
				break
			}
		}
		if !found {
			return p, nil
		}
	}
	return -1, errors.Errorf(
		"no priorities available in the range [%d, %d]", min, max,
	)
}
Example #3
0
func nextAvailableLUN(vm *compute.VirtualMachine) (int, error) {
	// Pick the smallest LUN not in use. We have to choose them in order,
	// or the disks don't show up.
	var inUse [32]bool
	if vm.Properties.StorageProfile.DataDisks != nil {
		for _, disk := range *vm.Properties.StorageProfile.DataDisks {
			lun := to.Int(disk.Lun)
			if lun < 0 || lun > 31 {
				logger.Warningf("ignore disk with invalid LUN: %+v", disk)
				continue
			}
			inUse[lun] = true
		}
	}
	for i, inUse := range inUse {
		if !inUse {
			return i, nil
		}
	}
	return -1, errors.New("all LUNs are in use")
}
Example #4
0
// newInstanceType creates an InstanceType based on a VirtualMachineSize.
func newInstanceType(size compute.VirtualMachineSize) instances.InstanceType {
	// We're not doing real costs for now; just made-up, relative
	// costs, to ensure we choose the right VMs given matching
	// constraints. This was based on the pricing for West US,
	// and assumes that all regions have the same relative costs.
	//
	// DS is the same price as D, but is targeted at Premium Storage.
	// Likewise for GS and G. We put the premium storage variants
	// directly after their non-premium counterparts.
	machineSizeCost := []string{
		"Standard_A0",
		"Standard_A1",
		"Standard_D1",
		"Standard_DS1",
		"Standard_D1_v2",
		"Standard_A2",
		"Standard_D2",
		"Standard_DS2",
		"Standard_D2_v2",
		"Standard_D11",
		"Standard_DS11",
		"Standard_D11_v2",
		"Standard_A3",
		"Standard_D3",
		"Standard_DS3",
		"Standard_D3_v2",
		"Standard_D12",
		"Standard_DS12",
		"Standard_D12_v2",
		"Standard_A5", // Yes, A5 is cheaper than A4.
		"Standard_A4",
		"Standard_A6",
		"Standard_G1",
		"Standard_GS1",
		"Standard_D4",
		"Standard_DS4",
		"Standard_D4_v2",
		"Standard_D13",
		"Standard_DS13",
		"Standard_D13_v2",
		"Standard_A7",
		"Standard_A10",
		"Standard_G2",
		"Standard_GS2",
		"Standard_D5_v2",
		"Standard_D14",
		"Standard_DS14",
		"Standard_D14_v2",
		"Standard_A8",
		"Standard_A11",
		"Standard_G3",
		"Standard_GS3",
		"Standard_A9",
		"Standard_G4",
		"Standard_GS4",
		"Standard_GS5",
		"Standard_G5",

		// Basic instances are less capable than standard
		// ones, so we don't want to be providing them as
		// a default. This is achieved by costing them at
		// a higher price, even though they are cheaper
		// in reality.
		"Basic_A0",
		"Basic_A1",
		"Basic_A2",
		"Basic_A3",
		"Basic_A4",
	}

	// Anything not in the list is more expensive that is in the list.
	cost := len(machineSizeCost)
	sizeName := to.String(size.Name)
	for i, name := range machineSizeCost {
		if sizeName == name {
			cost = i
			break
		}
	}
	if cost == len(machineSizeCost) {
		logger.Warningf("found unknown VM size %q", sizeName)
	}

	vtype := "Hyper-V"
	return instances.InstanceType{
		Id:       sizeName,
		Name:     sizeName,
		Arches:   []string{arch.AMD64},
		CpuCores: uint64(to.Int(size.NumberOfCores)),
		Mem:      uint64(to.Int(size.MemoryInMB)),
		// NOTE(axw) size.OsDiskSizeInMB is the maximum root disk
		// size, but the actual disk size is limited to the size
		// of the image/VHD that the machine is backed by. The
		// Azure Resource Manager APIs do not provide a way of
		// determining the image size.
		//
		// All of the published images that we use are ~30GiB.
		RootDisk: uint64(29495),
		Cost:     uint64(cost),
		VirtType: &vtype,
		// tags are not currently supported by azure
	}
}
Example #5
0
// Ports is specified in the Instance interface.
func (inst *azureInstance) Ports(machineId string) (ports []jujunetwork.PortRange, err error) {
	inst.env.mu.Lock()
	nsgClient := network.SecurityGroupsClient{inst.env.network}
	inst.env.mu.Unlock()

	securityGroupName := internalSecurityGroupName
	nsg, err := nsgClient.Get(inst.env.resourceGroup, securityGroupName)
	if err != nil {
		return nil, errors.Annotate(err, "querying network security group")
	}
	if nsg.Properties.SecurityRules == nil {
		return nil, nil
	}

	vmName := resourceName(names.NewMachineTag(machineId))
	prefix := instanceNetworkSecurityRulePrefix(instance.Id(vmName))
	for _, rule := range *nsg.Properties.SecurityRules {
		if rule.Properties.Direction != network.Inbound {
			continue
		}
		if rule.Properties.Access != network.Allow {
			continue
		}
		if to.Int(rule.Properties.Priority) <= securityRuleInternalMax {
			continue
		}
		if !strings.HasPrefix(to.String(rule.Name), prefix) {
			continue
		}

		var portRange jujunetwork.PortRange
		if *rule.Properties.DestinationPortRange == "*" {
			portRange.FromPort = 0
			portRange.ToPort = 65535
		} else {
			portRange, err = jujunetwork.ParsePortRange(
				*rule.Properties.DestinationPortRange,
			)
			if err != nil {
				return nil, errors.Annotatef(
					err, "parsing port range for security rule %q",
					to.String(rule.Name),
				)
			}
		}

		var protocols []string
		switch rule.Properties.Protocol {
		case network.SecurityRuleProtocolTCP:
			protocols = []string{"tcp"}
		case network.SecurityRuleProtocolUDP:
			protocols = []string{"udp"}
		default:
			protocols = []string{"tcp", "udp"}
		}
		for _, protocol := range protocols {
			portRange.Protocol = protocol
			ports = append(ports, portRange)
		}
	}
	return ports, nil
}