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 }