You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

582 lines
16 KiB

  1. package ec2_test
  2. import (
  3. "fmt"
  4. "regexp"
  5. "sort"
  6. "github.com/goamz/goamz/aws"
  7. "github.com/goamz/goamz/ec2"
  8. "github.com/goamz/goamz/ec2/ec2test"
  9. "github.com/goamz/goamz/testutil"
  10. . "gopkg.in/check.v1"
  11. )
  12. // LocalServer represents a local ec2test fake server.
  13. type LocalServer struct {
  14. auth aws.Auth
  15. region aws.Region
  16. srv *ec2test.Server
  17. }
  18. func (s *LocalServer) SetUp(c *C) {
  19. srv, err := ec2test.NewServer()
  20. c.Assert(err, IsNil)
  21. c.Assert(srv, NotNil)
  22. s.srv = srv
  23. s.region = aws.Region{EC2Endpoint: srv.URL()}
  24. }
  25. // LocalServerSuite defines tests that will run
  26. // against the local ec2test server. It includes
  27. // selected tests from ClientTests;
  28. // when the ec2test functionality is sufficient, it should
  29. // include all of them, and ClientTests can be simply embedded.
  30. type LocalServerSuite struct {
  31. srv LocalServer
  32. ServerTests
  33. clientTests ClientTests
  34. }
  35. var _ = Suite(&LocalServerSuite{})
  36. func (s *LocalServerSuite) SetUpSuite(c *C) {
  37. s.srv.SetUp(c)
  38. s.ServerTests.ec2 = ec2.NewWithClient(s.srv.auth, s.srv.region, testutil.DefaultClient)
  39. s.clientTests.ec2 = ec2.NewWithClient(s.srv.auth, s.srv.region, testutil.DefaultClient)
  40. }
  41. func (s *LocalServerSuite) TestRunAndTerminate(c *C) {
  42. s.clientTests.TestRunAndTerminate(c)
  43. }
  44. func (s *LocalServerSuite) TestSecurityGroups(c *C) {
  45. s.clientTests.TestSecurityGroups(c)
  46. }
  47. // TestUserData is not defined on ServerTests because it
  48. // requires the ec2test server to function.
  49. func (s *LocalServerSuite) TestUserData(c *C) {
  50. data := make([]byte, 256)
  51. for i := range data {
  52. data[i] = byte(i)
  53. }
  54. inst, err := s.ec2.RunInstances(&ec2.RunInstancesOptions{
  55. ImageId: imageId,
  56. InstanceType: "t1.micro",
  57. UserData: data,
  58. })
  59. c.Assert(err, IsNil)
  60. c.Assert(inst, NotNil)
  61. c.Assert(inst.Instances[0].DNSName, Equals, inst.Instances[0].InstanceId+".example.com")
  62. id := inst.Instances[0].InstanceId
  63. defer s.ec2.TerminateInstances([]string{id})
  64. tinst := s.srv.srv.Instance(id)
  65. c.Assert(tinst, NotNil)
  66. c.Assert(tinst.UserData, DeepEquals, data)
  67. }
  68. // AmazonServerSuite runs the ec2test server tests against a live EC2 server.
  69. // It will only be activated if the -all flag is specified.
  70. type AmazonServerSuite struct {
  71. srv AmazonServer
  72. ServerTests
  73. }
  74. var _ = Suite(&AmazonServerSuite{})
  75. func (s *AmazonServerSuite) SetUpSuite(c *C) {
  76. if !testutil.Amazon {
  77. c.Skip("AmazonServerSuite tests not enabled")
  78. }
  79. s.srv.SetUp(c)
  80. s.ServerTests.ec2 = ec2.NewWithClient(s.srv.auth, aws.USEast, testutil.DefaultClient)
  81. }
  82. // ServerTests defines a set of tests designed to test
  83. // the ec2test local fake ec2 server.
  84. // It is not used as a test suite in itself, but embedded within
  85. // another type.
  86. type ServerTests struct {
  87. ec2 *ec2.EC2
  88. }
  89. func terminateInstances(c *C, e *ec2.EC2, insts []*ec2.Instance) {
  90. var ids []string
  91. for _, inst := range insts {
  92. if inst != nil {
  93. ids = append(ids, inst.InstanceId)
  94. }
  95. }
  96. _, err := e.TerminateInstances(ids)
  97. c.Check(err, IsNil, Commentf("%d INSTANCES LEFT RUNNING!!!", len(ids)))
  98. }
  99. func (s *ServerTests) makeTestGroup(c *C, name, descr string) ec2.SecurityGroup {
  100. // Clean it up if a previous test left it around.
  101. _, err := s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
  102. if err != nil && err.(*ec2.Error).Code != "InvalidGroup.NotFound" {
  103. c.Fatalf("delete security group: %v", err)
  104. }
  105. resp, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: name, Description: descr})
  106. c.Assert(err, IsNil)
  107. c.Assert(resp.Name, Equals, name)
  108. return resp.SecurityGroup
  109. }
  110. func (s *ServerTests) TestIPPerms(c *C) {
  111. g0 := s.makeTestGroup(c, "goamz-test0", "ec2test group 0")
  112. defer s.ec2.DeleteSecurityGroup(g0)
  113. g1 := s.makeTestGroup(c, "goamz-test1", "ec2test group 1")
  114. defer s.ec2.DeleteSecurityGroup(g1)
  115. resp, err := s.ec2.SecurityGroups([]ec2.SecurityGroup{g0, g1}, nil)
  116. c.Assert(err, IsNil)
  117. c.Assert(resp.Groups, HasLen, 2)
  118. c.Assert(resp.Groups[0].IPPerms, HasLen, 0)
  119. c.Assert(resp.Groups[1].IPPerms, HasLen, 0)
  120. ownerId := resp.Groups[0].OwnerId
  121. // test some invalid parameters
  122. // TODO more
  123. _, err = s.ec2.AuthorizeSecurityGroup(g0, []ec2.IPPerm{{
  124. Protocol: "tcp",
  125. FromPort: 0,
  126. ToPort: 1024,
  127. SourceIPs: []string{"z127.0.0.1/24"},
  128. }})
  129. c.Assert(err, NotNil)
  130. c.Check(err.(*ec2.Error).Code, Equals, "InvalidPermission.Malformed")
  131. // Check that AuthorizeSecurityGroup adds the correct authorizations.
  132. _, err = s.ec2.AuthorizeSecurityGroup(g0, []ec2.IPPerm{{
  133. Protocol: "tcp",
  134. FromPort: 2000,
  135. ToPort: 2001,
  136. SourceIPs: []string{"127.0.0.0/24"},
  137. SourceGroups: []ec2.UserSecurityGroup{{
  138. Name: g1.Name,
  139. }, {
  140. Id: g0.Id,
  141. }},
  142. }, {
  143. Protocol: "tcp",
  144. FromPort: 2000,
  145. ToPort: 2001,
  146. SourceIPs: []string{"200.1.1.34/32"},
  147. }})
  148. c.Assert(err, IsNil)
  149. resp, err = s.ec2.SecurityGroups([]ec2.SecurityGroup{g0}, nil)
  150. c.Assert(err, IsNil)
  151. c.Assert(resp.Groups, HasLen, 1)
  152. c.Assert(resp.Groups[0].IPPerms, HasLen, 1)
  153. perm := resp.Groups[0].IPPerms[0]
  154. srcg := perm.SourceGroups
  155. c.Assert(srcg, HasLen, 2)
  156. // Normalize so we don't care about returned order.
  157. if srcg[0].Name == g1.Name {
  158. srcg[0], srcg[1] = srcg[1], srcg[0]
  159. }
  160. c.Check(srcg[0].Name, Equals, g0.Name)
  161. c.Check(srcg[0].Id, Equals, g0.Id)
  162. c.Check(srcg[0].OwnerId, Equals, ownerId)
  163. c.Check(srcg[1].Name, Equals, g1.Name)
  164. c.Check(srcg[1].Id, Equals, g1.Id)
  165. c.Check(srcg[1].OwnerId, Equals, ownerId)
  166. sort.Strings(perm.SourceIPs)
  167. c.Check(perm.SourceIPs, DeepEquals, []string{"127.0.0.0/24", "200.1.1.34/32"})
  168. // Check that we can't delete g1 (because g0 is using it)
  169. _, err = s.ec2.DeleteSecurityGroup(g1)
  170. c.Assert(err, NotNil)
  171. c.Check(err.(*ec2.Error).Code, Equals, "InvalidGroup.InUse")
  172. _, err = s.ec2.RevokeSecurityGroup(g0, []ec2.IPPerm{{
  173. Protocol: "tcp",
  174. FromPort: 2000,
  175. ToPort: 2001,
  176. SourceGroups: []ec2.UserSecurityGroup{{Id: g1.Id}},
  177. }, {
  178. Protocol: "tcp",
  179. FromPort: 2000,
  180. ToPort: 2001,
  181. SourceIPs: []string{"200.1.1.34/32"},
  182. }})
  183. c.Assert(err, IsNil)
  184. resp, err = s.ec2.SecurityGroups([]ec2.SecurityGroup{g0}, nil)
  185. c.Assert(err, IsNil)
  186. c.Assert(resp.Groups, HasLen, 1)
  187. c.Assert(resp.Groups[0].IPPerms, HasLen, 1)
  188. perm = resp.Groups[0].IPPerms[0]
  189. srcg = perm.SourceGroups
  190. c.Assert(srcg, HasLen, 1)
  191. c.Check(srcg[0].Name, Equals, g0.Name)
  192. c.Check(srcg[0].Id, Equals, g0.Id)
  193. c.Check(srcg[0].OwnerId, Equals, ownerId)
  194. c.Check(perm.SourceIPs, DeepEquals, []string{"127.0.0.0/24"})
  195. // We should be able to delete g1 now because we've removed its only use.
  196. _, err = s.ec2.DeleteSecurityGroup(g1)
  197. c.Assert(err, IsNil)
  198. _, err = s.ec2.DeleteSecurityGroup(g0)
  199. c.Assert(err, IsNil)
  200. f := ec2.NewFilter()
  201. f.Add("group-id", g0.Id, g1.Id)
  202. resp, err = s.ec2.SecurityGroups(nil, f)
  203. c.Assert(err, IsNil)
  204. c.Assert(resp.Groups, HasLen, 0)
  205. }
  206. func (s *ServerTests) TestDuplicateIPPerm(c *C) {
  207. name := "goamz-test"
  208. descr := "goamz security group for tests"
  209. // Clean it up, if a previous test left it around and avoid leaving it around.
  210. s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
  211. defer s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
  212. resp1, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: name, Description: descr})
  213. c.Assert(err, IsNil)
  214. c.Assert(resp1.Name, Equals, name)
  215. perms := []ec2.IPPerm{{
  216. Protocol: "tcp",
  217. FromPort: 200,
  218. ToPort: 1024,
  219. SourceIPs: []string{"127.0.0.1/24"},
  220. }, {
  221. Protocol: "tcp",
  222. FromPort: 0,
  223. ToPort: 100,
  224. SourceIPs: []string{"127.0.0.1/24"},
  225. }}
  226. _, err = s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: name}, perms[0:1])
  227. c.Assert(err, IsNil)
  228. _, err = s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: name}, perms[0:2])
  229. c.Assert(err, ErrorMatches, `.*\(InvalidPermission.Duplicate\)`)
  230. }
  231. type filterSpec struct {
  232. name string
  233. values []string
  234. }
  235. func (s *ServerTests) TestInstanceFiltering(c *C) {
  236. groupResp, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: sessionName("testgroup1"), Description: "testgroup one description"})
  237. c.Assert(err, IsNil)
  238. group1 := groupResp.SecurityGroup
  239. defer s.ec2.DeleteSecurityGroup(group1)
  240. groupResp, err = s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: sessionName("testgroup2"), Description: "testgroup two description"})
  241. c.Assert(err, IsNil)
  242. group2 := groupResp.SecurityGroup
  243. defer s.ec2.DeleteSecurityGroup(group2)
  244. insts := make([]*ec2.Instance, 3)
  245. inst, err := s.ec2.RunInstances(&ec2.RunInstancesOptions{
  246. MinCount: 2,
  247. ImageId: imageId,
  248. InstanceType: "t1.micro",
  249. SecurityGroups: []ec2.SecurityGroup{group1},
  250. })
  251. c.Assert(err, IsNil)
  252. insts[0] = &inst.Instances[0]
  253. insts[1] = &inst.Instances[1]
  254. defer terminateInstances(c, s.ec2, insts)
  255. imageId2 := "ami-e358958a" // Natty server, i386, EBS store
  256. inst, err = s.ec2.RunInstances(&ec2.RunInstancesOptions{
  257. ImageId: imageId2,
  258. InstanceType: "t1.micro",
  259. SecurityGroups: []ec2.SecurityGroup{group2},
  260. })
  261. c.Assert(err, IsNil)
  262. insts[2] = &inst.Instances[0]
  263. ids := func(indices ...int) (instIds []string) {
  264. for _, index := range indices {
  265. instIds = append(instIds, insts[index].InstanceId)
  266. }
  267. return
  268. }
  269. tests := []struct {
  270. about string
  271. instanceIds []string // instanceIds argument to Instances method.
  272. filters []filterSpec // filters argument to Instances method.
  273. resultIds []string // set of instance ids of expected results.
  274. allowExtra bool // resultIds may be incomplete.
  275. err string // expected error.
  276. }{
  277. {
  278. about: "check that Instances returns all instances",
  279. resultIds: ids(0, 1, 2),
  280. allowExtra: true,
  281. }, {
  282. about: "check that specifying two instance ids returns them",
  283. instanceIds: ids(0, 2),
  284. resultIds: ids(0, 2),
  285. }, {
  286. about: "check that specifying a non-existent instance id gives an error",
  287. instanceIds: append(ids(0), "i-deadbeef"),
  288. err: `.*\(InvalidInstanceID\.NotFound\)`,
  289. }, {
  290. about: "check that a filter allowed both instances returns both of them",
  291. filters: []filterSpec{
  292. {"instance-id", ids(0, 2)},
  293. },
  294. resultIds: ids(0, 2),
  295. }, {
  296. about: "check that a filter allowing only one instance returns it",
  297. filters: []filterSpec{
  298. {"instance-id", ids(1)},
  299. },
  300. resultIds: ids(1),
  301. }, {
  302. about: "check that a filter allowing no instances returns none",
  303. filters: []filterSpec{
  304. {"instance-id", []string{"i-deadbeef12345"}},
  305. },
  306. }, {
  307. about: "check that filtering on group id works",
  308. filters: []filterSpec{
  309. {"group-id", []string{group1.Id}},
  310. },
  311. resultIds: ids(0, 1),
  312. }, {
  313. about: "check that filtering on group name works",
  314. filters: []filterSpec{
  315. {"group-name", []string{group1.Name}},
  316. },
  317. resultIds: ids(0, 1),
  318. }, {
  319. about: "check that filtering on image id works",
  320. filters: []filterSpec{
  321. {"image-id", []string{imageId}},
  322. },
  323. resultIds: ids(0, 1),
  324. allowExtra: true,
  325. }, {
  326. about: "combination filters 1",
  327. filters: []filterSpec{
  328. {"image-id", []string{imageId, imageId2}},
  329. {"group-name", []string{group1.Name}},
  330. },
  331. resultIds: ids(0, 1),
  332. }, {
  333. about: "combination filters 2",
  334. filters: []filterSpec{
  335. {"image-id", []string{imageId2}},
  336. {"group-name", []string{group1.Name}},
  337. },
  338. },
  339. }
  340. for i, t := range tests {
  341. c.Logf("%d. %s", i, t.about)
  342. var f *ec2.Filter
  343. if t.filters != nil {
  344. f = ec2.NewFilter()
  345. for _, spec := range t.filters {
  346. f.Add(spec.name, spec.values...)
  347. }
  348. }
  349. resp, err := s.ec2.DescribeInstances(t.instanceIds, f)
  350. if t.err != "" {
  351. c.Check(err, ErrorMatches, t.err)
  352. continue
  353. }
  354. c.Assert(err, IsNil)
  355. insts := make(map[string]*ec2.Instance)
  356. for _, r := range resp.Reservations {
  357. for j := range r.Instances {
  358. inst := &r.Instances[j]
  359. c.Check(insts[inst.InstanceId], IsNil, Commentf("duplicate instance id: %q", inst.InstanceId))
  360. insts[inst.InstanceId] = inst
  361. }
  362. }
  363. if !t.allowExtra {
  364. c.Check(insts, HasLen, len(t.resultIds), Commentf("expected %d instances got %#v", len(t.resultIds), insts))
  365. }
  366. for j, id := range t.resultIds {
  367. c.Check(insts[id], NotNil, Commentf("instance id %d (%q) not found; got %#v", j, id, insts))
  368. }
  369. }
  370. }
  371. func idsOnly(gs []ec2.SecurityGroup) []ec2.SecurityGroup {
  372. for i := range gs {
  373. gs[i].Name = ""
  374. }
  375. return gs
  376. }
  377. func namesOnly(gs []ec2.SecurityGroup) []ec2.SecurityGroup {
  378. for i := range gs {
  379. gs[i].Id = ""
  380. }
  381. return gs
  382. }
  383. func (s *ServerTests) TestGroupFiltering(c *C) {
  384. g := make([]ec2.SecurityGroup, 4)
  385. for i := range g {
  386. resp, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: sessionName(fmt.Sprintf("testgroup%d", i)), Description: fmt.Sprintf("testdescription%d", i)})
  387. c.Assert(err, IsNil)
  388. g[i] = resp.SecurityGroup
  389. c.Logf("group %d: %v", i, g[i])
  390. defer s.ec2.DeleteSecurityGroup(g[i])
  391. }
  392. perms := [][]ec2.IPPerm{
  393. {{
  394. Protocol: "tcp",
  395. FromPort: 100,
  396. ToPort: 200,
  397. SourceIPs: []string{"1.2.3.4/32"},
  398. }},
  399. {{
  400. Protocol: "tcp",
  401. FromPort: 200,
  402. ToPort: 300,
  403. SourceGroups: []ec2.UserSecurityGroup{{Id: g[1].Id}},
  404. }},
  405. {{
  406. Protocol: "udp",
  407. FromPort: 200,
  408. ToPort: 400,
  409. SourceGroups: []ec2.UserSecurityGroup{{Id: g[1].Id}},
  410. }},
  411. }
  412. for i, ps := range perms {
  413. _, err := s.ec2.AuthorizeSecurityGroup(g[i], ps)
  414. c.Assert(err, IsNil)
  415. }
  416. groups := func(indices ...int) (gs []ec2.SecurityGroup) {
  417. for _, index := range indices {
  418. gs = append(gs, g[index])
  419. }
  420. return
  421. }
  422. type groupTest struct {
  423. about string
  424. groups []ec2.SecurityGroup // groupIds argument to SecurityGroups method.
  425. filters []filterSpec // filters argument to SecurityGroups method.
  426. results []ec2.SecurityGroup // set of expected result groups.
  427. allowExtra bool // specified results may be incomplete.
  428. err string // expected error.
  429. }
  430. filterCheck := func(name, val string, gs []ec2.SecurityGroup) groupTest {
  431. return groupTest{
  432. about: "filter check " + name,
  433. filters: []filterSpec{{name, []string{val}}},
  434. results: gs,
  435. allowExtra: true,
  436. }
  437. }
  438. tests := []groupTest{
  439. {
  440. about: "check that SecurityGroups returns all groups",
  441. results: groups(0, 1, 2, 3),
  442. allowExtra: true,
  443. }, {
  444. about: "check that specifying two group ids returns them",
  445. groups: idsOnly(groups(0, 2)),
  446. results: groups(0, 2),
  447. }, {
  448. about: "check that specifying names only works",
  449. groups: namesOnly(groups(0, 2)),
  450. results: groups(0, 2),
  451. }, {
  452. about: "check that specifying a non-existent group id gives an error",
  453. groups: append(groups(0), ec2.SecurityGroup{Id: "sg-eeeeeeeee"}),
  454. err: `.*\(InvalidGroup\.NotFound\)`,
  455. }, {
  456. about: "check that a filter allowed two groups returns both of them",
  457. filters: []filterSpec{
  458. {"group-id", []string{g[0].Id, g[2].Id}},
  459. },
  460. results: groups(0, 2),
  461. },
  462. {
  463. about: "check that the previous filter works when specifying a list of ids",
  464. groups: groups(1, 2),
  465. filters: []filterSpec{
  466. {"group-id", []string{g[0].Id, g[2].Id}},
  467. },
  468. results: groups(2),
  469. }, {
  470. about: "check that a filter allowing no groups returns none",
  471. filters: []filterSpec{
  472. {"group-id", []string{"sg-eeeeeeeee"}},
  473. },
  474. },
  475. filterCheck("description", "testdescription1", groups(1)),
  476. filterCheck("group-name", g[2].Name, groups(2)),
  477. filterCheck("ip-permission.cidr", "1.2.3.4/32", groups(0)),
  478. filterCheck("ip-permission.group-name", g[1].Name, groups(1, 2)),
  479. filterCheck("ip-permission.protocol", "udp", groups(2)),
  480. filterCheck("ip-permission.from-port", "200", groups(1, 2)),
  481. filterCheck("ip-permission.to-port", "200", groups(0)),
  482. // TODO owner-id
  483. }
  484. for i, t := range tests {
  485. c.Logf("%d. %s", i, t.about)
  486. var f *ec2.Filter
  487. if t.filters != nil {
  488. f = ec2.NewFilter()
  489. for _, spec := range t.filters {
  490. f.Add(spec.name, spec.values...)
  491. }
  492. }
  493. resp, err := s.ec2.SecurityGroups(t.groups, f)
  494. if t.err != "" {
  495. c.Check(err, ErrorMatches, t.err)
  496. continue
  497. }
  498. c.Assert(err, IsNil)
  499. groups := make(map[string]*ec2.SecurityGroup)
  500. for j := range resp.Groups {
  501. group := &resp.Groups[j].SecurityGroup
  502. c.Check(groups[group.Id], IsNil, Commentf("duplicate group id: %q", group.Id))
  503. groups[group.Id] = group
  504. }
  505. // If extra groups may be returned, eliminate all groups that
  506. // we did not create in this session apart from the default group.
  507. if t.allowExtra {
  508. namePat := regexp.MustCompile(sessionName("testgroup[0-9]"))
  509. for id, g := range groups {
  510. if !namePat.MatchString(g.Name) {
  511. delete(groups, id)
  512. }
  513. }
  514. }
  515. c.Check(groups, HasLen, len(t.results))
  516. for j, g := range t.results {
  517. rg := groups[g.Id]
  518. c.Assert(rg, NotNil, Commentf("group %d (%v) not found; got %#v", j, g, groups))
  519. c.Check(rg.Name, Equals, g.Name, Commentf("group %d (%v)", j, g))
  520. }
  521. }
  522. }