github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/juju/testing/instance.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package testing 5 6 import ( 7 "github.com/juju/errors" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 "gopkg.in/juju/names.v2" 11 12 "github.com/juju/juju/api" 13 "github.com/juju/juju/cloudconfig/instancecfg" 14 "github.com/juju/juju/constraints" 15 "github.com/juju/juju/environs" 16 "github.com/juju/juju/environs/config" 17 "github.com/juju/juju/environs/imagemetadata" 18 "github.com/juju/juju/environs/simplestreams" 19 "github.com/juju/juju/environs/tools" 20 "github.com/juju/juju/instance" 21 "github.com/juju/juju/mongo" 22 "github.com/juju/juju/network" 23 "github.com/juju/juju/state/multiwatcher" 24 "github.com/juju/juju/testing" 25 coretools "github.com/juju/juju/tools" 26 ) 27 28 // FakeAPIInfo holds information about no state - it will always 29 // give an error when connected to. The machine id gives the machine id 30 // of the machine to be started. 31 func FakeAPIInfo(machineId string) *api.Info { 32 return &api.Info{ 33 Addrs: []string{"0.1.2.3:17777"}, 34 Tag: names.NewMachineTag(machineId), 35 Password: "unimportant", 36 CACert: testing.CACert, 37 ModelTag: testing.ModelTag, 38 } 39 } 40 41 // WaitAddresses waits until the specified instance has addresses, and returns them. 42 func WaitInstanceAddresses(env environs.Environ, instId instance.Id) ([]network.Address, error) { 43 for a := testing.LongAttempt.Start(); a.Next(); { 44 insts, err := env.Instances([]instance.Id{instId}) 45 if err != nil { 46 return nil, err 47 } 48 addresses, err := insts[0].Addresses() 49 if err != nil { 50 return nil, err 51 } 52 if len(addresses) > 0 { 53 return addresses, nil 54 } 55 } 56 return nil, errors.Errorf("timed out trying to get addresses for %v", instId) 57 } 58 59 // AssertStartControllerInstance is a test helper function that starts a 60 // controller instance with a plausible but invalid configuration, and 61 // checks that it succeeds. 62 func AssertStartControllerInstance( 63 c *gc.C, env environs.Environ, controllerUUID, machineId string, 64 ) ( 65 instance.Instance, *instance.HardwareCharacteristics, 66 ) { 67 params := environs.StartInstanceParams{ControllerUUID: controllerUUID} 68 err := fillinStartInstanceParams(env, machineId, true, ¶ms) 69 c.Assert(err, jc.ErrorIsNil) 70 result, err := env.StartInstance(params) 71 c.Assert(err, jc.ErrorIsNil) 72 return result.Instance, result.Hardware 73 } 74 75 // AssertStartInstance is a test helper function that starts an instance with a 76 // plausible but invalid configuration, and checks that it succeeds. 77 func AssertStartInstance( 78 c *gc.C, env environs.Environ, controllerUUID, machineId string, 79 ) ( 80 instance.Instance, *instance.HardwareCharacteristics, 81 ) { 82 inst, hc, _, err := StartInstance(env, controllerUUID, machineId) 83 c.Assert(err, jc.ErrorIsNil) 84 return inst, hc 85 } 86 87 // StartInstance is a test helper function that starts an instance with a plausible 88 // but invalid configuration, and returns the result of Environ.StartInstance. 89 func StartInstance( 90 env environs.Environ, controllerUUID, machineId string, 91 ) ( 92 instance.Instance, *instance.HardwareCharacteristics, []network.InterfaceInfo, error, 93 ) { 94 return StartInstanceWithConstraints(env, controllerUUID, machineId, constraints.Value{}) 95 } 96 97 // AssertStartInstanceWithConstraints is a test helper function that starts an instance 98 // with the given constraints, and a plausible but invalid configuration, and returns 99 // the result of Environ.StartInstance. 100 func AssertStartInstanceWithConstraints( 101 c *gc.C, env environs.Environ, controllerUUID, machineId string, cons constraints.Value, 102 ) ( 103 instance.Instance, *instance.HardwareCharacteristics, 104 ) { 105 inst, hc, _, err := StartInstanceWithConstraints(env, controllerUUID, machineId, cons) 106 c.Assert(err, jc.ErrorIsNil) 107 return inst, hc 108 } 109 110 // StartInstanceWithConstraints is a test helper function that starts an instance 111 // with the given constraints, and a plausible but invalid configuration, and returns 112 // the result of Environ.StartInstance. 113 func StartInstanceWithConstraints( 114 env environs.Environ, controllerUUID, machineId string, cons constraints.Value, 115 ) ( 116 instance.Instance, *instance.HardwareCharacteristics, []network.InterfaceInfo, error, 117 ) { 118 params := environs.StartInstanceParams{ControllerUUID: controllerUUID, Constraints: cons} 119 result, err := StartInstanceWithParams(env, machineId, params) 120 if err != nil { 121 return nil, nil, nil, errors.Trace(err) 122 } 123 return result.Instance, result.Hardware, result.NetworkInfo, nil 124 } 125 126 // StartInstanceWithParams is a test helper function that starts an instance 127 // with the given parameters, and a plausible but invalid configuration, and 128 // returns the result of Environ.StartInstance. The provided params's 129 // InstanceConfig and Tools field values will be ignored. 130 func StartInstanceWithParams( 131 env environs.Environ, machineId string, 132 params environs.StartInstanceParams, 133 ) ( 134 *environs.StartInstanceResult, error, 135 ) { 136 if err := fillinStartInstanceParams(env, machineId, false, ¶ms); err != nil { 137 return nil, err 138 } 139 return env.StartInstance(params) 140 } 141 142 func fillinStartInstanceParams(env environs.Environ, machineId string, isController bool, params *environs.StartInstanceParams) error { 143 if params.ControllerUUID == "" { 144 return errors.New("missing controller UUID in start instance parameters") 145 } 146 preferredSeries := config.PreferredSeries(env.Config()) 147 agentVersion, ok := env.Config().AgentVersion() 148 if !ok { 149 return errors.New("missing agent version in model config") 150 } 151 filter := coretools.Filter{ 152 Number: agentVersion, 153 Series: preferredSeries, 154 } 155 if params.Constraints.Arch != nil { 156 filter.Arch = *params.Constraints.Arch 157 } 158 stream := tools.PreferredStream(&agentVersion, env.Config().Development(), env.Config().AgentStream()) 159 possibleTools, err := tools.FindTools(env, -1, -1, stream, filter) 160 if err != nil { 161 return errors.Trace(err) 162 } 163 164 if params.ImageMetadata == nil { 165 if err := SetImageMetadata( 166 env, 167 possibleTools.AllSeries(), 168 possibleTools.Arches(), 169 ¶ms.ImageMetadata, 170 ); err != nil { 171 return errors.Trace(err) 172 } 173 } 174 175 machineNonce := "fake_nonce" 176 apiInfo := FakeAPIInfo(machineId) 177 instanceConfig, err := instancecfg.NewInstanceConfig( 178 testing.ControllerTag, 179 machineId, 180 machineNonce, 181 imagemetadata.ReleasedStream, 182 preferredSeries, 183 apiInfo, 184 ) 185 if err != nil { 186 return errors.Trace(err) 187 } 188 if isController { 189 instanceConfig.Controller = &instancecfg.ControllerConfig{ 190 Config: testing.FakeControllerConfig(), 191 MongoInfo: &mongo.MongoInfo{ 192 Info: mongo.Info{ 193 Addrs: []string{"127.0.0.1:1234"}, 194 CACert: "CA CERT\n" + testing.CACert, 195 }, 196 Password: "mongosecret", 197 Tag: names.NewMachineTag(machineId), 198 }, 199 } 200 instanceConfig.Jobs = []multiwatcher.MachineJob{multiwatcher.JobHostUnits, multiwatcher.JobManageModel} 201 } 202 cfg := env.Config() 203 instanceConfig.Tags = instancecfg.InstanceTags(env.Config().UUID(), params.ControllerUUID, cfg, nil) 204 params.Tools = possibleTools 205 params.InstanceConfig = instanceConfig 206 return nil 207 } 208 209 func SetImageMetadata(env environs.Environ, series, arches []string, out *[]*imagemetadata.ImageMetadata) error { 210 hasRegion, ok := env.(simplestreams.HasRegion) 211 if !ok { 212 return nil 213 } 214 sources, err := environs.ImageMetadataSources(env) 215 if err != nil { 216 return errors.Trace(err) 217 } 218 region, err := hasRegion.Region() 219 if err != nil { 220 return errors.Trace(err) 221 } 222 imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ 223 CloudSpec: region, 224 Series: series, 225 Arches: arches, 226 Stream: env.Config().ImageStream(), 227 }) 228 imageMetadata, _, err := imagemetadata.Fetch(sources, imageConstraint) 229 if err != nil { 230 return errors.Trace(err) 231 } 232 *out = imageMetadata 233 return nil 234 }