github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/azure/instancetype.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package azure
     5  
     6  import (
     7  	"github.com/Azure/azure-sdk-for-go/arm/compute"
     8  	"github.com/Azure/go-autorest/autorest/to"
     9  	"github.com/juju/errors"
    10  	"github.com/juju/utils/arch"
    11  
    12  	"github.com/juju/juju/constraints"
    13  	"github.com/juju/juju/environs/instances"
    14  	"github.com/juju/juju/provider/azure/internal/imageutils"
    15  )
    16  
    17  const defaultMem = 1024 // 1GiB
    18  
    19  // newInstanceType creates an InstanceType based on a VirtualMachineSize.
    20  func newInstanceType(size compute.VirtualMachineSize) instances.InstanceType {
    21  	// We're not doing real costs for now; just made-up, relative
    22  	// costs, to ensure we choose the right VMs given matching
    23  	// constraints. This was based on the pricing for West US,
    24  	// and assumes that all regions have the same relative costs.
    25  	//
    26  	// DS is the same price as D, but is targeted at Premium Storage.
    27  	// Likewise for GS and G. We put the premium storage variants
    28  	// directly after their non-premium counterparts.
    29  	machineSizeCost := []string{
    30  		"Standard_A0",
    31  		"Standard_A1",
    32  		"Standard_D1",
    33  		"Standard_DS1",
    34  		"Standard_D1_v2",
    35  		"Standard_A2",
    36  		"Standard_D2",
    37  		"Standard_DS2",
    38  		"Standard_D2_v2",
    39  		"Standard_D11",
    40  		"Standard_DS11",
    41  		"Standard_D11_v2",
    42  		"Standard_A3",
    43  		"Standard_D3",
    44  		"Standard_DS3",
    45  		"Standard_D3_v2",
    46  		"Standard_D12",
    47  		"Standard_DS12",
    48  		"Standard_D12_v2",
    49  		"Standard_A5", // Yes, A5 is cheaper than A4.
    50  		"Standard_A4",
    51  		"Standard_A6",
    52  		"Standard_G1",
    53  		"Standard_GS1",
    54  		"Standard_D4",
    55  		"Standard_DS4",
    56  		"Standard_D4_v2",
    57  		"Standard_D13",
    58  		"Standard_DS13",
    59  		"Standard_D13_v2",
    60  		"Standard_A7",
    61  		"Standard_A10",
    62  		"Standard_G2",
    63  		"Standard_GS2",
    64  		"Standard_D5_v2",
    65  		"Standard_D14",
    66  		"Standard_DS14",
    67  		"Standard_D14_v2",
    68  		"Standard_A8",
    69  		"Standard_A11",
    70  		"Standard_G3",
    71  		"Standard_GS3",
    72  		"Standard_A9",
    73  		"Standard_G4",
    74  		"Standard_GS4",
    75  		"Standard_GS5",
    76  		"Standard_G5",
    77  
    78  		// Basic instances are less capable than standard
    79  		// ones, so we don't want to be providing them as
    80  		// a default. This is achieved by costing them at
    81  		// a higher price, even though they are cheaper
    82  		// in reality.
    83  		"Basic_A0",
    84  		"Basic_A1",
    85  		"Basic_A2",
    86  		"Basic_A3",
    87  		"Basic_A4",
    88  	}
    89  
    90  	// Anything not in the list is more expensive that is in the list.
    91  	cost := len(machineSizeCost)
    92  	sizeName := to.String(size.Name)
    93  	for i, name := range machineSizeCost {
    94  		if sizeName == name {
    95  			cost = i
    96  			break
    97  		}
    98  	}
    99  	if cost == len(machineSizeCost) {
   100  		logger.Debugf("found unknown VM size %q", sizeName)
   101  	}
   102  
   103  	vtype := "Hyper-V"
   104  	return instances.InstanceType{
   105  		Id:       sizeName,
   106  		Name:     sizeName,
   107  		Arches:   []string{arch.AMD64},
   108  		CpuCores: uint64(to.Int32(size.NumberOfCores)),
   109  		Mem:      uint64(to.Int32(size.MemoryInMB)),
   110  		// NOTE(axw) size.OsDiskSizeInMB is the *maximum*
   111  		// OS-disk size. When we create a VM, we can create
   112  		// one that is smaller.
   113  		RootDisk: mbToMib(uint64(to.Int32(size.OsDiskSizeInMB))),
   114  		Cost:     uint64(cost),
   115  		VirtType: &vtype,
   116  		// tags are not currently supported by azure
   117  	}
   118  }
   119  
   120  func mbToMib(mb uint64) uint64 {
   121  	b := mb * 1000 * 1000
   122  	return uint64(float64(b) / 1024 / 1024)
   123  }
   124  
   125  // findInstanceSpec returns the InstanceSpec that best satisfies the supplied
   126  // InstanceConstraint.
   127  //
   128  // NOTE(axw) for now we ignore simplestreams altogether, and go straight to
   129  // Azure's image registry.
   130  func findInstanceSpec(
   131  	client compute.VirtualMachineImagesClient,
   132  	instanceTypesMap map[string]instances.InstanceType,
   133  	constraint *instances.InstanceConstraint,
   134  	imageStream string,
   135  ) (*instances.InstanceSpec, error) {
   136  
   137  	if !constraintHasArch(constraint, arch.AMD64) {
   138  		// Azure only supports AMD64.
   139  		return nil, errors.NotFoundf("%s in arch constraints", arch.AMD64)
   140  	}
   141  
   142  	image, err := imageutils.SeriesImage(constraint.Series, imageStream, constraint.Region, client)
   143  	if err != nil {
   144  		return nil, errors.Trace(err)
   145  	}
   146  	images := []instances.Image{*image}
   147  
   148  	instanceTypes := make([]instances.InstanceType, 0, len(instanceTypesMap))
   149  	for _, instanceType := range instanceTypesMap {
   150  		instanceTypes = append(instanceTypes, instanceType)
   151  	}
   152  	constraint.Constraints = defaultToBaselineSpec(constraint.Constraints)
   153  	return instances.FindInstanceSpec(images, constraint, instanceTypes)
   154  }
   155  
   156  func constraintHasArch(constraint *instances.InstanceConstraint, arch string) bool {
   157  	for _, constraintArch := range constraint.Arches {
   158  		if constraintArch == arch {
   159  			return true
   160  		}
   161  	}
   162  	return false
   163  }
   164  
   165  // If you specify no constraints at all, you're going to get the smallest
   166  // instance type available. In practice that one's a bit small, so unless
   167  // the constraints are deliberately set lower, this gives you a set of
   168  // baseline constraints that are just slightly more ambitious than that.
   169  func defaultToBaselineSpec(constraint constraints.Value) constraints.Value {
   170  	result := constraint
   171  	if !result.HasInstanceType() && result.Mem == nil {
   172  		var value uint64 = defaultMem
   173  		result.Mem = &value
   174  	}
   175  	return result
   176  }