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