cloudformation_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. /*
  2. Copyright 2020 Docker Compose CLI authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package ecs
  14. import (
  15. "context"
  16. "fmt"
  17. "io/ioutil"
  18. "reflect"
  19. "testing"
  20. "github.com/docker/compose-cli/api/compose"
  21. "github.com/aws/aws-sdk-go/service/elbv2"
  22. "github.com/awslabs/goformation/v4/cloudformation"
  23. "github.com/awslabs/goformation/v4/cloudformation/ec2"
  24. "github.com/awslabs/goformation/v4/cloudformation/ecs"
  25. "github.com/awslabs/goformation/v4/cloudformation/efs"
  26. "github.com/awslabs/goformation/v4/cloudformation/elasticloadbalancingv2"
  27. "github.com/awslabs/goformation/v4/cloudformation/iam"
  28. "github.com/awslabs/goformation/v4/cloudformation/logs"
  29. "github.com/compose-spec/compose-go/loader"
  30. "github.com/compose-spec/compose-go/types"
  31. "github.com/golang/mock/gomock"
  32. "gotest.tools/v3/assert"
  33. "gotest.tools/v3/golden"
  34. )
  35. func TestSimpleConvert(t *testing.T) {
  36. bytes, err := ioutil.ReadFile("testdata/input/simple-single-service.yaml")
  37. assert.NilError(t, err)
  38. template := convertYaml(t, string(bytes), useDefaultVPC)
  39. resultAsJSON, err := marshall(template, "yaml")
  40. assert.NilError(t, err)
  41. result := fmt.Sprintf("%s\n", string(resultAsJSON))
  42. expected := "simple-cloudformation-conversion.golden"
  43. golden.Assert(t, result, expected)
  44. }
  45. func TestLogging(t *testing.T) {
  46. template := convertYaml(t, `
  47. services:
  48. foo:
  49. image: hello_world
  50. logging:
  51. options:
  52. awslogs-datetime-pattern: "FOO"
  53. x-aws-logs_retention: 10
  54. `, useDefaultVPC)
  55. def := template.Resources["FooTaskDefinition"].(*ecs.TaskDefinition)
  56. logging := getMainContainer(def, t).LogConfiguration
  57. if logging != nil {
  58. assert.Equal(t, logging.Options["awslogs-datetime-pattern"], "FOO")
  59. } else {
  60. t.Fatal("Logging not configured")
  61. }
  62. logGroup := template.Resources["LogGroup"].(*logs.LogGroup)
  63. assert.Equal(t, logGroup.RetentionInDays, 10)
  64. }
  65. func TestEnvFile(t *testing.T) {
  66. template := convertYaml(t, `
  67. services:
  68. foo:
  69. image: hello_world
  70. env_file:
  71. - testdata/input/envfile
  72. `, useDefaultVPC)
  73. def := template.Resources["FooTaskDefinition"].(*ecs.TaskDefinition)
  74. env := getMainContainer(def, t).Environment
  75. var found bool
  76. for _, pair := range env {
  77. if pair.Name == "FOO" {
  78. assert.Equal(t, pair.Value, "BAR")
  79. found = true
  80. }
  81. }
  82. assert.Check(t, found, "environment variable FOO not set")
  83. }
  84. func TestEnvFileAndEnv(t *testing.T) {
  85. template := convertYaml(t, `
  86. services:
  87. foo:
  88. image: hello_world
  89. env_file:
  90. - testdata/input/envfile
  91. environment:
  92. - "FOO=ZOT"
  93. `, useDefaultVPC)
  94. def := template.Resources["FooTaskDefinition"].(*ecs.TaskDefinition)
  95. env := getMainContainer(def, t).Environment
  96. var found bool
  97. for _, pair := range env {
  98. if pair.Name == "FOO" {
  99. assert.Equal(t, pair.Value, "ZOT")
  100. found = true
  101. }
  102. }
  103. assert.Check(t, found, "environment variable FOO not set")
  104. }
  105. func TestRollingUpdateLimits(t *testing.T) {
  106. template := convertYaml(t, `
  107. services:
  108. foo:
  109. image: hello_world
  110. deploy:
  111. replicas: 4
  112. update_config:
  113. parallelism: 2
  114. `, useDefaultVPC)
  115. service := template.Resources["FooService"].(*ecs.Service)
  116. assert.Check(t, service.DeploymentConfiguration.MaximumPercent == 150)
  117. assert.Check(t, service.DeploymentConfiguration.MinimumHealthyPercent == 50)
  118. }
  119. func TestRollingUpdateExtension(t *testing.T) {
  120. template := convertYaml(t, `
  121. services:
  122. foo:
  123. image: hello_world
  124. deploy:
  125. update_config:
  126. x-aws-min_percent: 25
  127. x-aws-max_percent: 125
  128. `, useDefaultVPC)
  129. service := template.Resources["FooService"].(*ecs.Service)
  130. assert.Check(t, service.DeploymentConfiguration.MaximumPercent == 125)
  131. assert.Check(t, service.DeploymentConfiguration.MinimumHealthyPercent == 25)
  132. }
  133. func TestRolePolicy(t *testing.T) {
  134. template := convertYaml(t, `
  135. services:
  136. foo:
  137. image: hello_world
  138. x-aws-pull_credentials: "secret"
  139. `, useDefaultVPC)
  140. x := template.Resources["FooTaskExecutionRole"]
  141. assert.Check(t, x != nil)
  142. role := *(x.(*iam.Role))
  143. assert.Check(t, role.ManagedPolicyArns[0] == ecsTaskExecutionPolicy)
  144. assert.Check(t, role.ManagedPolicyArns[1] == ecrReadOnlyPolicy)
  145. // We expect an extra policy has been created for x-aws-pull_credentials
  146. assert.Check(t, len(role.Policies) == 1)
  147. policy := role.Policies[0].PolicyDocument.(*PolicyDocument)
  148. expected := []string{"secretsmanager:GetSecretValue", "ssm:GetParameters", "kms:Decrypt"}
  149. assert.DeepEqual(t, expected, policy.Statement[0].Action)
  150. assert.DeepEqual(t, []string{"secret"}, policy.Statement[0].Resource)
  151. }
  152. func TestMapNetworksToSecurityGroups(t *testing.T) {
  153. template := convertYaml(t, `
  154. services:
  155. test:
  156. image: hello_world
  157. networks:
  158. - front-tier
  159. - back-tier
  160. networks:
  161. front-tier:
  162. name: public
  163. back-tier:
  164. internal: true
  165. `, useDefaultVPC)
  166. assert.Check(t, template.Resources["FronttierNetwork"] != nil)
  167. assert.Check(t, template.Resources["BacktierNetwork"] != nil)
  168. assert.Check(t, template.Resources["BacktierNetworkIngress"] != nil)
  169. i := template.Resources["FronttierNetworkIngress"]
  170. assert.Check(t, i != nil)
  171. ingress := *i.(*ec2.SecurityGroupIngress)
  172. assert.Check(t, ingress.SourceSecurityGroupId == cloudformation.Ref("FronttierNetwork"))
  173. }
  174. func TestLoadBalancerTypeApplication(t *testing.T) {
  175. cases := []string{
  176. `services:
  177. test:
  178. image: nginx
  179. ports:
  180. - 80:80
  181. `,
  182. `services:
  183. test:
  184. image: nginx
  185. ports:
  186. - target: 8080
  187. x-aws-protocol: http
  188. `,
  189. }
  190. for _, y := range cases {
  191. template := convertYaml(t, y, useDefaultVPC)
  192. lb := template.Resources["LoadBalancer"]
  193. assert.Check(t, lb != nil)
  194. loadBalancer := *lb.(*elasticloadbalancingv2.LoadBalancer)
  195. assert.Check(t, len(loadBalancer.Name) <= 32)
  196. assert.Check(t, loadBalancer.Type == elbv2.LoadBalancerTypeEnumApplication)
  197. assert.Check(t, len(loadBalancer.SecurityGroups) > 0)
  198. }
  199. }
  200. func TestNoLoadBalancerIfNoPortExposed(t *testing.T) {
  201. template := convertYaml(t, `
  202. services:
  203. test:
  204. image: nginx
  205. foo:
  206. image: bar
  207. `, useDefaultVPC)
  208. for _, r := range template.Resources {
  209. assert.Check(t, r.AWSCloudFormationType() != "AWS::ElasticLoadBalancingV2::TargetGroup")
  210. assert.Check(t, r.AWSCloudFormationType() != "AWS::ElasticLoadBalancingV2::Listener")
  211. assert.Check(t, r.AWSCloudFormationType() != "AWS::ElasticLoadBalancingV2::PortPublisher")
  212. }
  213. }
  214. func TestServiceReplicas(t *testing.T) {
  215. template := convertYaml(t, `
  216. services:
  217. test:
  218. image: nginx
  219. deploy:
  220. replicas: 10
  221. `, useDefaultVPC)
  222. s := template.Resources["TestService"]
  223. assert.Check(t, s != nil)
  224. service := *s.(*ecs.Service)
  225. assert.Check(t, service.DesiredCount == 10)
  226. }
  227. func TestTaskSizeConvert(t *testing.T) {
  228. template := convertYaml(t, `
  229. services:
  230. test:
  231. image: nginx
  232. `, useDefaultVPC)
  233. def := template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
  234. assert.Equal(t, def.Cpu, "256")
  235. assert.Equal(t, def.Memory, "512")
  236. template = convertYaml(t, `
  237. services:
  238. test:
  239. image: nginx
  240. deploy:
  241. resources:
  242. limits:
  243. cpus: '0.5'
  244. memory: 2048M
  245. `, useDefaultVPC)
  246. def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
  247. assert.Equal(t, def.Cpu, "512")
  248. assert.Equal(t, def.Memory, "2048")
  249. template = convertYaml(t, `
  250. services:
  251. test:
  252. image: nginx
  253. deploy:
  254. resources:
  255. limits:
  256. cpus: '4'
  257. memory: 8192M
  258. `, useDefaultVPC)
  259. def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
  260. assert.Equal(t, def.Cpu, "4096")
  261. assert.Equal(t, def.Memory, "8192")
  262. template = convertYaml(t, `
  263. services:
  264. test:
  265. image: nginx
  266. deploy:
  267. resources:
  268. limits:
  269. cpus: '4'
  270. memory: 792Mb
  271. reservations:
  272. generic_resources:
  273. - discrete_resource_spec:
  274. kind: gpus
  275. value: 2
  276. `, useDefaultVPC, useGPU)
  277. def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
  278. assert.Equal(t, def.Cpu, "4000")
  279. assert.Equal(t, def.Memory, "792")
  280. template = convertYaml(t, `
  281. services:
  282. test:
  283. image: nginx
  284. deploy:
  285. resources:
  286. reservations:
  287. generic_resources:
  288. - discrete_resource_spec:
  289. kind: gpus
  290. value: 2
  291. `, useDefaultVPC, useGPU)
  292. def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
  293. assert.Equal(t, def.Cpu, "")
  294. assert.Equal(t, def.Memory, "")
  295. template = convertYaml(t, `
  296. services:
  297. test:
  298. image: nginx
  299. deploy:
  300. resources:
  301. reservations:
  302. devices:
  303. - capabilities: [gpu]
  304. count: 2
  305. `, useDefaultVPC, useGPU)
  306. def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
  307. assert.Equal(t, def.Cpu, "")
  308. assert.Equal(t, def.Memory, "")
  309. }
  310. func TestLoadBalancerTypeNetwork(t *testing.T) {
  311. template := convertYaml(t, `
  312. services:
  313. test:
  314. image: nginx
  315. ports:
  316. - 80:80
  317. - 88:88
  318. `, useDefaultVPC)
  319. lb := template.Resources["LoadBalancer"]
  320. assert.Check(t, lb != nil)
  321. loadBalancer := *lb.(*elasticloadbalancingv2.LoadBalancer)
  322. assert.Check(t, loadBalancer.Type == elbv2.LoadBalancerTypeEnumNetwork)
  323. }
  324. func TestUseExternalNetwork(t *testing.T) {
  325. template := convertYaml(t, `
  326. services:
  327. test:
  328. image: nginx
  329. networks:
  330. default:
  331. external: true
  332. name: sg-123abc
  333. `, useDefaultVPC, func(m *MockAPIMockRecorder) {
  334. m.SecurityGroupExists(gomock.Any(), "sg-123abc").Return(true, nil)
  335. })
  336. assert.Check(t, template.Resources["DefaultNetwork"] == nil)
  337. assert.Check(t, template.Resources["DefaultNetworkIngress"] == nil)
  338. s := template.Resources["TestService"].(*ecs.Service)
  339. assert.Check(t, s != nil) //nolint:staticcheck
  340. assert.Check(t, s.NetworkConfiguration.AwsvpcConfiguration.SecurityGroups[0] == "sg-123abc") //nolint:staticcheck
  341. }
  342. func TestUseExternalVolume(t *testing.T) {
  343. template := convertYaml(t, `
  344. services:
  345. test:
  346. image: nginx
  347. volumes:
  348. db-data:
  349. external: true
  350. name: fs-123abc
  351. `, useDefaultVPC, func(m *MockAPIMockRecorder) {
  352. m.ResolveFileSystem(gomock.Any(), "fs-123abc").Return(existingAWSResource{id: "fs-123abc"}, nil)
  353. })
  354. s := template.Resources["DbdataNFSMountTargetOnSubnet1"].(*efs.MountTarget)
  355. assert.Check(t, s != nil) //nolint:staticcheck
  356. assert.Equal(t, s.FileSystemId, "fs-123abc") //nolint:staticcheck
  357. s = template.Resources["DbdataNFSMountTargetOnSubnet2"].(*efs.MountTarget)
  358. assert.Check(t, s != nil) //nolint:staticcheck
  359. assert.Equal(t, s.FileSystemId, "fs-123abc") //nolint:staticcheck
  360. }
  361. func TestCreateVolume(t *testing.T) {
  362. template := convertYaml(t, `
  363. services:
  364. test:
  365. image: nginx
  366. volumes:
  367. db-data:
  368. driver_opts:
  369. backup_policy: ENABLED
  370. lifecycle_policy: AFTER_30_DAYS
  371. performance_mode: maxIO
  372. throughput_mode: provisioned
  373. provisioned_throughput: 1024
  374. `, useDefaultVPC, func(m *MockAPIMockRecorder) {
  375. m.ListFileSystems(gomock.Any(), map[string]string{
  376. compose.ProjectTag: t.Name(),
  377. compose.VolumeTag: "db-data",
  378. }).Return(nil, nil)
  379. })
  380. n := volumeResourceName("db-data")
  381. f := template.Resources[n].(*efs.FileSystem)
  382. assert.Check(t, f != nil) //nolint:staticcheck
  383. assert.Equal(t, f.BackupPolicy.Status, "ENABLED") //nolint:staticcheck
  384. assert.Equal(t, f.LifecyclePolicies[0].TransitionToIA, "AFTER_30_DAYS") //nolint:staticcheck
  385. assert.Equal(t, f.PerformanceMode, "maxIO") //nolint:staticcheck
  386. assert.Equal(t, f.ThroughputMode, "provisioned") //nolint:staticcheck
  387. assert.Equal(t, f.ProvisionedThroughputInMibps, float64(1024)) //nolint:staticcheck
  388. s := template.Resources["DbdataNFSMountTargetOnSubnet1"].(*efs.MountTarget)
  389. assert.Check(t, s != nil) //nolint:staticcheck
  390. assert.Equal(t, s.FileSystemId, cloudformation.Ref(n)) //nolint:staticcheck
  391. }
  392. func TestCreateAccessPoint(t *testing.T) {
  393. template := convertYaml(t, `
  394. services:
  395. test:
  396. image: nginx
  397. volumes:
  398. db-data:
  399. driver_opts:
  400. uid: 1002
  401. gid: 1002
  402. `, useDefaultVPC, func(m *MockAPIMockRecorder) {
  403. m.ListFileSystems(gomock.Any(), gomock.Any()).Return(nil, nil)
  404. })
  405. a := template.Resources["DbdataAccessPoint"].(*efs.AccessPoint)
  406. assert.Check(t, a != nil) //nolint:staticcheck
  407. assert.Equal(t, a.PosixUser.Uid, "1002") //nolint:staticcheck
  408. assert.Equal(t, a.PosixUser.Gid, "1002") //nolint:staticcheck
  409. }
  410. func TestReusePreviousVolume(t *testing.T) {
  411. template := convertYaml(t, `
  412. services:
  413. test:
  414. image: nginx
  415. volumes:
  416. db-data: {}
  417. `, useDefaultVPC, func(m *MockAPIMockRecorder) {
  418. m.ListFileSystems(gomock.Any(), map[string]string{
  419. compose.ProjectTag: t.Name(),
  420. compose.VolumeTag: "db-data",
  421. }).Return([]awsResource{
  422. existingAWSResource{
  423. id: "fs-123abc",
  424. },
  425. }, nil)
  426. })
  427. s := template.Resources["DbdataNFSMountTargetOnSubnet1"].(*efs.MountTarget)
  428. assert.Check(t, s != nil) //nolint:staticcheck
  429. assert.Equal(t, s.FileSystemId, "fs-123abc") //nolint:staticcheck
  430. }
  431. func TestServiceMapping(t *testing.T) {
  432. template := convertYaml(t, `
  433. services:
  434. test:
  435. image: "image"
  436. command: "command"
  437. entrypoint: "entrypoint"
  438. environment:
  439. - "FOO=BAR"
  440. cap_add:
  441. - SYS_PTRACE
  442. cap_drop:
  443. - SYSLOG
  444. init: true
  445. user: "user"
  446. working_dir: "working_dir"
  447. `, useDefaultVPC)
  448. def := template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
  449. container := getMainContainer(def, t)
  450. assert.Equal(t, container.Image, "image")
  451. assert.Equal(t, container.Command[0], "command")
  452. assert.Equal(t, container.EntryPoint[0], "entrypoint")
  453. assert.Equal(t, get(container.Environment, "FOO"), "BAR")
  454. assert.Check(t, container.LinuxParameters.InitProcessEnabled)
  455. assert.Equal(t, container.LinuxParameters.Capabilities.Add[0], "SYS_PTRACE")
  456. assert.Equal(t, container.LinuxParameters.Capabilities.Drop[0], "SYSLOG")
  457. assert.Equal(t, container.User, "user")
  458. assert.Equal(t, container.WorkingDirectory, "working_dir")
  459. }
  460. func get(l []ecs.TaskDefinition_KeyValuePair, name string) string {
  461. for _, e := range l {
  462. if e.Name == name {
  463. return e.Value
  464. }
  465. }
  466. return ""
  467. }
  468. func TestResourcesHaveProjectTagSet(t *testing.T) {
  469. template := convertYaml(t, `
  470. services:
  471. test:
  472. image: nginx
  473. ports:
  474. - 80:80
  475. - 88:88
  476. `, useDefaultVPC)
  477. for _, r := range template.Resources {
  478. tags := reflect.Indirect(reflect.ValueOf(r)).FieldByName("Tags")
  479. if !tags.IsValid() {
  480. continue
  481. }
  482. for i := 0; i < tags.Len(); i++ {
  483. k := tags.Index(i).FieldByName("Key").String()
  484. v := tags.Index(i).FieldByName("Value").String()
  485. if k == compose.ProjectTag {
  486. assert.Equal(t, v, t.Name())
  487. }
  488. }
  489. }
  490. }
  491. func TestTemplateMetadata(t *testing.T) {
  492. template := convertYaml(t, `
  493. x-aws-cluster: "arn:aws:ecs:region:account:cluster/name"
  494. services:
  495. test:
  496. image: nginx
  497. `, useDefaultVPC, func(m *MockAPIMockRecorder) {
  498. m.ResolveCluster(gomock.Any(), "arn:aws:ecs:region:account:cluster/name").Return(existingAWSResource{
  499. arn: "arn:aws:ecs:region:account:cluster/name",
  500. id: "name",
  501. }, nil)
  502. })
  503. assert.Equal(t, template.Metadata["Cluster"], "arn:aws:ecs:region:account:cluster/name")
  504. }
  505. func TestARNUsedAsVpcID(t *testing.T) {
  506. convertYaml(t, `
  507. x-aws-vpc: "arn:aws:ec2:us-west-1:EXAMPLE:vpc/vpc-1234acbd"
  508. services:
  509. test:
  510. image: nginx
  511. `, func(m *MockAPIMockRecorder) {
  512. m.CheckVPC(gomock.Any(), "vpc-1234acbd").Return(nil)
  513. m.GetSubNets(gomock.Any(), "vpc-1234acbd").Return([]awsResource{
  514. existingAWSResource{id: "subnet1"},
  515. existingAWSResource{id: "subnet2"},
  516. }, nil)
  517. m.IsPublicSubnet(gomock.Any(), "subnet1").Return(true, nil)
  518. m.IsPublicSubnet(gomock.Any(), "subnet2").Return(true, nil)
  519. })
  520. }
  521. func convertYaml(t *testing.T, yaml string, fn ...func(m *MockAPIMockRecorder)) *cloudformation.Template {
  522. project := loadConfig(t, yaml)
  523. ctrl := gomock.NewController(t)
  524. defer ctrl.Finish()
  525. m := NewMockAPI(ctrl)
  526. for _, f := range fn {
  527. f(m.EXPECT())
  528. }
  529. backend := &ecsAPIService{
  530. aws: m,
  531. }
  532. template, err := backend.convert(context.TODO(), project)
  533. assert.NilError(t, err)
  534. return template
  535. }
  536. func loadConfig(t *testing.T, yaml string) *types.Project {
  537. dict, err := loader.ParseYAML([]byte(yaml))
  538. assert.NilError(t, err)
  539. model, err := loader.Load(types.ConfigDetails{
  540. ConfigFiles: []types.ConfigFile{
  541. {Config: dict},
  542. },
  543. }, func(options *loader.Options) {
  544. options.Name = t.Name()
  545. })
  546. assert.NilError(t, err)
  547. return model
  548. }
  549. func getMainContainer(def *ecs.TaskDefinition, t *testing.T) ecs.TaskDefinition_ContainerDefinition {
  550. for _, c := range def.ContainerDefinitions {
  551. if c.Essential {
  552. return c
  553. }
  554. }
  555. t.Fail()
  556. return def.ContainerDefinitions[0]
  557. }
  558. func useDefaultVPC(m *MockAPIMockRecorder) {
  559. m.GetDefaultVPC(gomock.Any()).Return("vpc-123", nil)
  560. m.GetSubNets(gomock.Any(), "vpc-123").Return([]awsResource{
  561. existingAWSResource{id: "subnet1"},
  562. existingAWSResource{id: "subnet2"},
  563. }, nil)
  564. m.IsPublicSubnet(gomock.Any(), "subnet1").Return(true, nil)
  565. m.IsPublicSubnet(gomock.Any(), "subnet2").Return(true, nil)
  566. }
  567. func useGPU(m *MockAPIMockRecorder) {
  568. m.GetParameter(gomock.Any(), gomock.Any()).Return("", nil)
  569. }