Permalink
Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
177 lines (161 sloc) 4.88 KB
// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package azure
import (
"github.com/Azure/azure-sdk-for-go/arm/compute"
"github.com/Azure/go-autorest/autorest/to"
"github.com/juju/errors"
"github.com/juju/utils/arch"
"github.com/juju/juju/constraints"
"github.com/juju/juju/environs/instances"
"github.com/juju/juju/provider/azure/internal/imageutils"
)
const defaultMem = 1024 // 1GiB
// 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.Debugf("found unknown VM size %q", sizeName)
}
vtype := "Hyper-V"
return instances.InstanceType{
Id: sizeName,
Name: sizeName,
Arches: []string{arch.AMD64},
CpuCores: uint64(to.Int32(size.NumberOfCores)),
Mem: uint64(to.Int32(size.MemoryInMB)),
// NOTE(axw) size.OsDiskSizeInMB is the *maximum*
// OS-disk size. When we create a VM, we can create
// one that is smaller.
RootDisk: mbToMib(uint64(to.Int32(size.OsDiskSizeInMB))),
Cost: uint64(cost),
VirtType: &vtype,
// tags are not currently supported by azure
}
}
func mbToMib(mb uint64) uint64 {
b := mb * 1000 * 1000
return uint64(float64(b) / 1024 / 1024)
}
// findInstanceSpec returns the InstanceSpec that best satisfies the supplied
// InstanceConstraint.
//
// NOTE(axw) for now we ignore simplestreams altogether, and go straight to
// Azure's image registry.
func findInstanceSpec(
client compute.VirtualMachineImagesClient,
instanceTypesMap map[string]instances.InstanceType,
constraint *instances.InstanceConstraint,
imageStream string,
) (*instances.InstanceSpec, error) {
if !constraintHasArch(constraint, arch.AMD64) {
// Azure only supports AMD64.
return nil, errors.NotFoundf("%s in arch constraints", arch.AMD64)
}
image, err := imageutils.SeriesImage(constraint.Series, imageStream, constraint.Region, client)
if err != nil {
return nil, errors.Trace(err)
}
images := []instances.Image{*image}
instanceTypes := make([]instances.InstanceType, 0, len(instanceTypesMap))
for _, instanceType := range instanceTypesMap {
instanceTypes = append(instanceTypes, instanceType)
}
constraint.Constraints = defaultToBaselineSpec(constraint.Constraints)
return instances.FindInstanceSpec(images, constraint, instanceTypes)
}
func constraintHasArch(constraint *instances.InstanceConstraint, arch string) bool {
for _, constraintArch := range constraint.Arches {
if constraintArch == arch {
return true
}
}
return false
}
// If you specify no constraints at all, you're going to get the smallest
// instance type available. In practice that one's a bit small, so unless
// the constraints are deliberately set lower, this gives you a set of
// baseline constraints that are just slightly more ambitious than that.
func defaultToBaselineSpec(constraint constraints.Value) constraints.Value {
result := constraint
if !result.HasInstanceType() && result.Mem == nil {
var value uint64 = defaultMem
result.Mem = &value
}
return result
}