~juju-qa/ubuntu/yakkety/juju/2.0-rc3-again

« back to all changes in this revision

Viewing changes to src/launchpad.net/juju-core/environs/ec2/local_test.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-04-24 22:34:47 UTC
  • Revision ID: package-import@ubuntu.com-20130424223447-f0qdji7ubnyo0s71
Tags: upstream-1.10.0.1
ImportĀ upstreamĀ versionĀ 1.10.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package ec2_test
 
2
 
 
3
import (
 
4
        "bytes"
 
5
        "launchpad.net/goamz/aws"
 
6
        amzec2 "launchpad.net/goamz/ec2"
 
7
        "launchpad.net/goamz/ec2/ec2test"
 
8
        "launchpad.net/goamz/s3"
 
9
        "launchpad.net/goamz/s3/s3test"
 
10
        . "launchpad.net/gocheck"
 
11
        "launchpad.net/goyaml"
 
12
        "launchpad.net/juju-core/constraints"
 
13
        "launchpad.net/juju-core/environs"
 
14
        "launchpad.net/juju-core/environs/ec2"
 
15
        "launchpad.net/juju-core/environs/jujutest"
 
16
        envtesting "launchpad.net/juju-core/environs/testing"
 
17
        "launchpad.net/juju-core/state"
 
18
        "launchpad.net/juju-core/testing"
 
19
        "launchpad.net/juju-core/utils"
 
20
        "regexp"
 
21
)
 
22
 
 
23
type ProviderSuite struct{}
 
24
 
 
25
var _ = Suite(&ProviderSuite{})
 
26
 
 
27
var testImagesContent = []jujutest.FileContent{{
 
28
        Name: "/query/precise/server/released.current.txt",
 
29
        Content: "" +
 
30
                "precise\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-20800c10\taki-98e26fa8\t\tparavirtual\n" +
 
31
                "precise\tserver\trelease\t20121017\tebs\ti386\ttest\tami-00000034\tparavirtual\n",
 
32
}, {
 
33
        Name: "/query/quantal/server/released.current.txt",
 
34
        Content: "" +
 
35
                "quantal\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-40f97070\taki-98e26fa8\t\tparavirtual\n" +
 
36
                "quantal\tserver\trelease\t20121017\tebs\ti386\ttest\tami-01000034\taki-98e26fa8\t\tparavirtual\n",
 
37
}, {
 
38
        Name: "/query/raring/server/released.current.txt",
 
39
        Content: "" +
 
40
                "raring\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-40f97070\taki-98e26fa8\t\tparavirtual\n" +
 
41
                "raring\tserver\trelease\t20121017\tebs\ti386\ttest\tami-40f97070\taki-98e26fa8\t\tparavirtual\n",
 
42
}}
 
43
 
 
44
// testInstanceTypeContent holds the cost in USDe-3/hour for each of the
 
45
// few available instance types in  the convenient fictional "test" region.
 
46
var testInstanceTypeContent = map[string]uint64{
 
47
        "m1.small":  60,
 
48
        "m1.medium": 120,
 
49
        "m1.large":  240,
 
50
        "m1.xlarge": 480,
 
51
        "t1.micro":  020,
 
52
}
 
53
 
 
54
func (s *ProviderSuite) TestMetadata(c *C) {
 
55
        metadataContent := []jujutest.FileContent{
 
56
                {"/2011-01-01/meta-data/instance-id", "dummy.instance.id"},
 
57
                {"/2011-01-01/meta-data/public-hostname", "public.dummy.address.invalid"},
 
58
                {"/2011-01-01/meta-data/local-hostname", "private.dummy.address.invalid"},
 
59
        }
 
60
        ec2.UseTestMetadata(metadataContent)
 
61
        defer ec2.UseTestMetadata(nil)
 
62
 
 
63
        p, err := environs.Provider("ec2")
 
64
        c.Assert(err, IsNil)
 
65
 
 
66
        addr, err := p.PublicAddress()
 
67
        c.Assert(err, IsNil)
 
68
        c.Assert(addr, Equals, "public.dummy.address.invalid")
 
69
 
 
70
        addr, err = p.PrivateAddress()
 
71
        c.Assert(err, IsNil)
 
72
        c.Assert(addr, Equals, "private.dummy.address.invalid")
 
73
 
 
74
        id, err := p.InstanceId()
 
75
        c.Assert(err, IsNil)
 
76
        c.Assert(id, Equals, state.InstanceId("dummy.instance.id"))
 
77
}
 
78
 
 
79
func registerLocalTests() {
 
80
        // N.B. Make sure the region we use here
 
81
        // has entries in the images/query txt files.
 
82
        aws.Regions["test"] = aws.Region{
 
83
                Name: "test",
 
84
        }
 
85
        attrs := map[string]interface{}{
 
86
                "name":                 "sample",
 
87
                "type":                 "ec2",
 
88
                "region":               "test",
 
89
                "control-bucket":       "test-bucket",
 
90
                "public-bucket":        "public-tools",
 
91
                "public-bucket-region": "test",
 
92
                "admin-secret":         "local-secret",
 
93
                "access-key":           "x",
 
94
                "secret-key":           "x",
 
95
                "authorized-keys":      "foo",
 
96
                "ca-cert":              testing.CACert,
 
97
                "ca-private-key":       testing.CAKey,
 
98
        }
 
99
 
 
100
        Suite(&localServerSuite{
 
101
                Tests: jujutest.Tests{
 
102
                        TestConfig: jujutest.TestConfig{attrs},
 
103
                },
 
104
        })
 
105
        Suite(&localLiveSuite{
 
106
                LiveTests: LiveTests{
 
107
                        LiveTests: jujutest.LiveTests{
 
108
                                TestConfig: jujutest.TestConfig{attrs},
 
109
                        },
 
110
                },
 
111
        })
 
112
        Suite(&localNonUSEastSuite{
 
113
                tests: jujutest.Tests{
 
114
                        TestConfig: jujutest.TestConfig{attrs},
 
115
                },
 
116
                srv: localServer{
 
117
                        config: &s3test.Config{
 
118
                                Send409Conflict: true,
 
119
                        },
 
120
                },
 
121
        })
 
122
}
 
123
 
 
124
// localLiveSuite runs tests from LiveTests using a fake
 
125
// EC2 server that runs within the test process itself.
 
126
type localLiveSuite struct {
 
127
        testing.LoggingSuite
 
128
        LiveTests
 
129
        srv localServer
 
130
        env environs.Environ
 
131
}
 
132
 
 
133
func (t *localLiveSuite) SetUpSuite(c *C) {
 
134
        t.LoggingSuite.SetUpSuite(c)
 
135
        ec2.UseTestImageData(testImagesContent)
 
136
        ec2.UseTestInstanceTypeData(testInstanceTypeContent)
 
137
        t.srv.startServer(c)
 
138
        t.LiveTests.SetUpSuite(c)
 
139
        t.env = t.LiveTests.Env
 
140
        ec2.ShortTimeouts(true)
 
141
}
 
142
 
 
143
func (t *localLiveSuite) TearDownSuite(c *C) {
 
144
        t.LiveTests.TearDownSuite(c)
 
145
        t.srv.stopServer(c)
 
146
        t.env = nil
 
147
        ec2.ShortTimeouts(false)
 
148
        ec2.UseTestImageData(nil)
 
149
        ec2.UseTestInstanceTypeData(nil)
 
150
        t.LoggingSuite.TearDownSuite(c)
 
151
}
 
152
 
 
153
func (t *localLiveSuite) SetUpTest(c *C) {
 
154
        t.LoggingSuite.SetUpTest(c)
 
155
        t.LiveTests.SetUpTest(c)
 
156
}
 
157
 
 
158
func (t *localLiveSuite) TearDownTest(c *C) {
 
159
        t.LiveTests.TearDownTest(c)
 
160
        t.LoggingSuite.TearDownTest(c)
 
161
}
 
162
 
 
163
// localServer represents a fake EC2 server running within
 
164
// the test process itself.
 
165
type localServer struct {
 
166
        ec2srv *ec2test.Server
 
167
        s3srv  *s3test.Server
 
168
        config *s3test.Config
 
169
}
 
170
 
 
171
func (srv *localServer) startServer(c *C) {
 
172
        var err error
 
173
        srv.ec2srv, err = ec2test.NewServer()
 
174
        if err != nil {
 
175
                c.Fatalf("cannot start ec2 test server: %v", err)
 
176
        }
 
177
        srv.s3srv, err = s3test.NewServer(srv.config)
 
178
        if err != nil {
 
179
                c.Fatalf("cannot start s3 test server: %v", err)
 
180
        }
 
181
        aws.Regions["test"] = aws.Region{
 
182
                Name:                 "test",
 
183
                EC2Endpoint:          srv.ec2srv.URL(),
 
184
                S3Endpoint:           srv.s3srv.URL(),
 
185
                S3LocationConstraint: true,
 
186
        }
 
187
        s3inst := s3.New(aws.Auth{}, aws.Regions["test"])
 
188
        writeablePublicStorage := ec2.BucketStorage(s3inst.Bucket("public-tools"))
 
189
        envtesting.UploadFakeTools(c, writeablePublicStorage)
 
190
        srv.addSpice(c)
 
191
}
 
192
 
 
193
// addSpice adds some "spice" to the local server
 
194
// by adding state that may cause tests to fail.
 
195
func (srv *localServer) addSpice(c *C) {
 
196
        states := []amzec2.InstanceState{
 
197
                ec2test.ShuttingDown,
 
198
                ec2test.Terminated,
 
199
                ec2test.Stopped,
 
200
        }
 
201
        for _, state := range states {
 
202
                srv.ec2srv.NewInstances(1, "m1.small", "ami-a7f539ce", state, nil)
 
203
        }
 
204
}
 
205
 
 
206
func (srv *localServer) stopServer(c *C) {
 
207
        srv.ec2srv.Quit()
 
208
        srv.s3srv.Quit()
 
209
        // Clear out the region because the server address is
 
210
        // no longer valid.
 
211
        delete(aws.Regions, "test")
 
212
}
 
213
 
 
214
// localServerSuite contains tests that run against a fake EC2 server
 
215
// running within the test process itself.  These tests can test things that
 
216
// would be unreasonably slow or expensive to test on a live Amazon server.
 
217
// It starts a new local ec2test server for each test.  The server is
 
218
// accessed by using the "test" region, which is changed to point to the
 
219
// network address of the local server.
 
220
type localServerSuite struct {
 
221
        testing.LoggingSuite
 
222
        jujutest.Tests
 
223
        srv localServer
 
224
        env environs.Environ
 
225
}
 
226
 
 
227
func (t *localServerSuite) SetUpSuite(c *C) {
 
228
        t.LoggingSuite.SetUpSuite(c)
 
229
        ec2.UseTestImageData(testImagesContent)
 
230
        ec2.UseTestInstanceTypeData(testInstanceTypeContent)
 
231
        t.Tests.SetUpSuite(c)
 
232
        ec2.ShortTimeouts(true)
 
233
}
 
234
 
 
235
func (t *localServerSuite) TearDownSuite(c *C) {
 
236
        t.Tests.TearDownSuite(c)
 
237
        ec2.ShortTimeouts(false)
 
238
        ec2.UseTestImageData(nil)
 
239
        ec2.UseTestInstanceTypeData(nil)
 
240
        t.LoggingSuite.TearDownSuite(c)
 
241
}
 
242
 
 
243
func (t *localServerSuite) SetUpTest(c *C) {
 
244
        t.LoggingSuite.SetUpTest(c)
 
245
        t.srv.startServer(c)
 
246
        t.Tests.SetUpTest(c)
 
247
        t.env = t.Tests.Env
 
248
}
 
249
 
 
250
func (t *localServerSuite) TearDownTest(c *C) {
 
251
        t.Tests.TearDownTest(c)
 
252
        t.srv.stopServer(c)
 
253
        t.LoggingSuite.TearDownTest(c)
 
254
}
 
255
 
 
256
func (t *localServerSuite) TestBootstrapInstanceUserDataAndState(c *C) {
 
257
        policy := t.env.AssignmentPolicy()
 
258
        c.Assert(policy, Equals, state.AssignNew)
 
259
 
 
260
        envtesting.UploadFakeTools(c, t.env.Storage())
 
261
        err := environs.Bootstrap(t.env, constraints.Value{})
 
262
        c.Assert(err, IsNil)
 
263
 
 
264
        // check that the state holds the id of the bootstrap machine.
 
265
        bootstrapState, err := ec2.LoadState(t.env)
 
266
        c.Assert(err, IsNil)
 
267
        c.Assert(bootstrapState.StateInstances, HasLen, 1)
 
268
 
 
269
        insts, err := t.env.Instances(bootstrapState.StateInstances)
 
270
        c.Assert(err, IsNil)
 
271
        c.Assert(insts, HasLen, 1)
 
272
        c.Check(insts[0].Id(), Equals, bootstrapState.StateInstances[0])
 
273
 
 
274
        info, apiInfo, err := t.env.StateInfo()
 
275
        c.Assert(err, IsNil)
 
276
        c.Assert(info, NotNil)
 
277
 
 
278
        // check that the user data is configured to start zookeeper
 
279
        // and the machine and provisioning agents.
 
280
        inst := t.srv.ec2srv.Instance(string(insts[0].Id()))
 
281
        c.Assert(inst, NotNil)
 
282
        bootstrapDNS, err := insts[0].DNSName()
 
283
        c.Assert(err, IsNil)
 
284
        c.Assert(bootstrapDNS, Not(Equals), "")
 
285
 
 
286
        userData, err := utils.Gunzip(inst.UserData)
 
287
        c.Assert(err, IsNil)
 
288
        c.Logf("first instance: UserData: %q", userData)
 
289
        var x map[interface{}]interface{}
 
290
        err = goyaml.Unmarshal(userData, &x)
 
291
        c.Assert(err, IsNil)
 
292
        CheckPackage(c, x, "git", true)
 
293
        CheckScripts(c, x, "jujud bootstrap-state", true)
 
294
        // TODO check for provisioning agent
 
295
        // TODO check for machine agent
 
296
 
 
297
        // check that a new instance will be started without
 
298
        // zookeeper, with a machine agent, and without a
 
299
        // provisioning agent.
 
300
        series := t.env.Config().DefaultSeries()
 
301
        info.Tag = "machine-1"
 
302
        apiInfo.Tag = "machine-1"
 
303
        inst1, err := t.env.StartInstance("1", "fake_nonce", series, constraints.Value{}, info, apiInfo)
 
304
        c.Assert(err, IsNil)
 
305
        inst = t.srv.ec2srv.Instance(string(inst1.Id()))
 
306
        c.Assert(inst, NotNil)
 
307
        userData, err = utils.Gunzip(inst.UserData)
 
308
        c.Assert(err, IsNil)
 
309
        c.Logf("second instance: UserData: %q", userData)
 
310
        x = nil
 
311
        err = goyaml.Unmarshal(userData, &x)
 
312
        c.Assert(err, IsNil)
 
313
        CheckPackage(c, x, "zookeeperd", false)
 
314
        // TODO check for provisioning agent
 
315
        // TODO check for machine agent
 
316
 
 
317
        err = t.env.Destroy(append(insts, inst1))
 
318
        c.Assert(err, IsNil)
 
319
 
 
320
        _, err = ec2.LoadState(t.env)
 
321
        c.Assert(err, NotNil)
 
322
}
 
323
 
 
324
// If match is true, CheckScripts checks that at least one script started
 
325
// by the cloudinit data matches the given regexp pattern, otherwise it
 
326
// checks that no script matches.  It's exported so it can be used by tests
 
327
// defined in ec2_test.
 
328
func CheckScripts(c *C, x map[interface{}]interface{}, pattern string, match bool) {
 
329
        scripts0 := x["runcmd"]
 
330
        if scripts0 == nil {
 
331
                c.Errorf("cloudinit has no entry for runcmd")
 
332
                return
 
333
        }
 
334
        scripts := scripts0.([]interface{})
 
335
        re := regexp.MustCompile(pattern)
 
336
        found := false
 
337
        for _, s0 := range scripts {
 
338
                s := s0.(string)
 
339
                if re.MatchString(s) {
 
340
                        found = true
 
341
                }
 
342
        }
 
343
        switch {
 
344
        case match && !found:
 
345
                c.Errorf("script %q not found in %q", pattern, scripts)
 
346
        case !match && found:
 
347
                c.Errorf("script %q found but not expected in %q", pattern, scripts)
 
348
        }
 
349
}
 
350
 
 
351
// CheckPackage checks that the cloudinit will or won't install the given
 
352
// package, depending on the value of match.  It's exported so it can be
 
353
// used by tests defined outside the ec2 package.
 
354
func CheckPackage(c *C, x map[interface{}]interface{}, pkg string, match bool) {
 
355
        pkgs0 := x["packages"]
 
356
        if pkgs0 == nil {
 
357
                if match {
 
358
                        c.Errorf("cloudinit has no entry for packages")
 
359
                }
 
360
                return
 
361
        }
 
362
 
 
363
        pkgs := pkgs0.([]interface{})
 
364
 
 
365
        found := false
 
366
        for _, p0 := range pkgs {
 
367
                p := p0.(string)
 
368
                if p == pkg {
 
369
                        found = true
 
370
                }
 
371
        }
 
372
        switch {
 
373
        case match && !found:
 
374
                c.Errorf("package %q not found in %v", pkg, pkgs)
 
375
        case !match && found:
 
376
                c.Errorf("%q found but not expected in %v", pkg, pkgs)
 
377
        }
 
378
}
 
379
 
 
380
// localNonUSEastSuite is similar to localServerSuite but the S3 mock server
 
381
// behaves as if
 
382
type localNonUSEastSuite struct {
 
383
        testing.LoggingSuite
 
384
        tests jujutest.Tests
 
385
        srv   localServer
 
386
        env   environs.Environ
 
387
}
 
388
 
 
389
func (t *localNonUSEastSuite) SetUpSuite(c *C) {
 
390
        t.LoggingSuite.SetUpSuite(c)
 
391
        ec2.UseTestImageData(testImagesContent)
 
392
        ec2.UseTestInstanceTypeData(testInstanceTypeContent)
 
393
        t.tests.SetUpSuite(c)
 
394
        ec2.ShortTimeouts(true)
 
395
}
 
396
 
 
397
func (t *localNonUSEastSuite) TearDownSuite(c *C) {
 
398
        ec2.ShortTimeouts(false)
 
399
        ec2.UseTestImageData(nil)
 
400
        ec2.UseTestInstanceTypeData(nil)
 
401
        t.LoggingSuite.TearDownSuite(c)
 
402
}
 
403
 
 
404
func (t *localNonUSEastSuite) SetUpTest(c *C) {
 
405
        t.LoggingSuite.SetUpTest(c)
 
406
        t.srv.startServer(c)
 
407
        t.tests.SetUpTest(c)
 
408
        t.env = t.tests.Env
 
409
}
 
410
 
 
411
func (t *localNonUSEastSuite) TearDownTest(c *C) {
 
412
        t.tests.TearDownTest(c)
 
413
        t.srv.stopServer(c)
 
414
        t.LoggingSuite.TearDownTest(c)
 
415
}
 
416
 
 
417
func (t *localNonUSEastSuite) TestPutBucket(c *C) {
 
418
        p := ec2.WritablePublicStorage(t.env).(ec2.Storage)
 
419
        for i := 0; i < 5; i++ {
 
420
                p.ResetMadeBucket()
 
421
                var buf bytes.Buffer
 
422
                err := p.Put("test-file", &buf, 0)
 
423
                c.Assert(err, IsNil)
 
424
        }
 
425
}