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 }