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