cloudformation_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package backend
  2. import (
  3. "fmt"
  4. "reflect"
  5. "testing"
  6. "github.com/aws/aws-sdk-go/service/elbv2"
  7. "github.com/awslabs/goformation/v4/cloudformation"
  8. "github.com/awslabs/goformation/v4/cloudformation/ec2"
  9. "github.com/awslabs/goformation/v4/cloudformation/ecs"
  10. "github.com/awslabs/goformation/v4/cloudformation/elasticloadbalancingv2"
  11. "github.com/awslabs/goformation/v4/cloudformation/iam"
  12. "github.com/compose-spec/compose-go/cli"
  13. "github.com/compose-spec/compose-go/loader"
  14. "github.com/compose-spec/compose-go/types"
  15. "github.com/docker/ecs-plugin/pkg/compose"
  16. "gotest.tools/v3/assert"
  17. "gotest.tools/v3/golden"
  18. )
  19. func TestSimpleConvert(t *testing.T) {
  20. project := load(t, "testdata/input/simple-single-service.yaml")
  21. result := convertResultAsString(t, project)
  22. expected := "simple/simple-cloudformation-conversion.golden"
  23. golden.Assert(t, result, expected)
  24. }
  25. func TestRolePolicy(t *testing.T) {
  26. template := convertYaml(t, "test", `
  27. version: "3"
  28. services:
  29. foo:
  30. image: hello_world
  31. x-aws-pull_credentials: "secret"
  32. `)
  33. role := template.Resources["FooTaskExecutionRole"].(*iam.Role)
  34. assert.Check(t, role != nil)
  35. assert.Check(t, role.ManagedPolicyArns[0] == ECSTaskExecutionPolicy)
  36. assert.Check(t, role.ManagedPolicyArns[1] == ECRReadOnlyPolicy)
  37. // We expect an extra policy has been created for x-aws-pull_credentials
  38. assert.Check(t, len(role.Policies) == 1)
  39. policy := role.Policies[0].PolicyDocument.(*PolicyDocument)
  40. expected := []string{"secretsmanager:GetSecretValue", "ssm:GetParameters", "kms:Decrypt"}
  41. assert.DeepEqual(t, expected, policy.Statement[0].Action)
  42. assert.DeepEqual(t, []string{"secret"}, policy.Statement[0].Resource)
  43. }
  44. func TestMapNetworksToSecurityGroups(t *testing.T) {
  45. template := convertYaml(t, "test", `
  46. version: "3"
  47. services:
  48. test:
  49. image: hello_world
  50. networks:
  51. - front-tier
  52. - back-tier
  53. networks:
  54. front-tier:
  55. name: public
  56. back-tier:
  57. internal: true
  58. `)
  59. assert.Check(t, template.Resources["TestPublicNetwork"] != nil)
  60. assert.Check(t, template.Resources["TestBacktierNetwork"] != nil)
  61. assert.Check(t, template.Resources["TestBacktierNetworkIngress"] != nil)
  62. ingress := template.Resources["TestPublicNetworkIngress"].(*ec2.SecurityGroupIngress)
  63. assert.Check(t, ingress != nil)
  64. assert.Check(t, ingress.SourceSecurityGroupId == cloudformation.Ref("TestPublicNetwork"))
  65. }
  66. func TestLoadBalancerTypeApplication(t *testing.T) {
  67. template := convertYaml(t, "test123456789009876543211234567890", `
  68. version: "3"
  69. services:
  70. test:
  71. image: nginx
  72. ports:
  73. - 80:80
  74. `)
  75. lb := template.Resources["TestLoadBalancer"].(*elasticloadbalancingv2.LoadBalancer)
  76. assert.Check(t, lb != nil)
  77. assert.Check(t, len(lb.Name) <= 32)
  78. assert.Check(t, lb.Type == elbv2.LoadBalancerTypeEnumApplication)
  79. assert.Check(t, len(lb.SecurityGroups) > 0)
  80. }
  81. func TestNoLoadBalancerIfNoPortExposed(t *testing.T) {
  82. template := convertYaml(t, "test", `
  83. version: "3"
  84. services:
  85. test:
  86. image: nginx
  87. foo:
  88. image: bar
  89. `)
  90. for _, r := range template.Resources {
  91. assert.Check(t, r.AWSCloudFormationType() != "AWS::ElasticLoadBalancingV2::TargetGroup")
  92. assert.Check(t, r.AWSCloudFormationType() != "AWS::ElasticLoadBalancingV2::Listener")
  93. assert.Check(t, r.AWSCloudFormationType() != "AWS::ElasticLoadBalancingV2::LoadBalancer")
  94. }
  95. }
  96. func TestServiceReplicas(t *testing.T) {
  97. template := convertYaml(t, "test", `
  98. version: "3"
  99. services:
  100. test:
  101. image: nginx
  102. deploy:
  103. replicas: 10
  104. `)
  105. s := template.Resources["TestService"].(*ecs.Service)
  106. assert.Check(t, s != nil)
  107. assert.Check(t, s.DesiredCount == 10)
  108. }
  109. func TestLoadBalancerTypeNetwork(t *testing.T) {
  110. template := convertYaml(t, "test", `
  111. version: "3"
  112. services:
  113. test:
  114. image: nginx
  115. ports:
  116. - 80:80
  117. - 88:88
  118. `)
  119. lb := template.Resources["TestLoadBalancer"].(*elasticloadbalancingv2.LoadBalancer)
  120. assert.Check(t, lb != nil)
  121. assert.Check(t, lb.Type == elbv2.LoadBalancerTypeEnumNetwork)
  122. }
  123. func TestServiceMapping(t *testing.T) {
  124. template := convertYaml(t, "test", `
  125. version: "3"
  126. services:
  127. test:
  128. image: "image"
  129. command: "command"
  130. entrypoint: "entrypoint"
  131. environment:
  132. - "FOO=BAR"
  133. cap_add:
  134. - SYS_PTRACE
  135. cap_drop:
  136. - SYSLOG
  137. init: true
  138. user: "user"
  139. working_dir: "working_dir"
  140. `)
  141. def := template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
  142. container := def.ContainerDefinitions[0]
  143. assert.Equal(t, container.Image, "image")
  144. assert.Equal(t, container.Command[0], "command")
  145. assert.Equal(t, container.EntryPoint[0], "entrypoint")
  146. assert.Equal(t, get(container.Environment, "FOO"), "BAR")
  147. assert.Check(t, container.LinuxParameters.InitProcessEnabled)
  148. assert.Equal(t, container.LinuxParameters.Capabilities.Add[0], "SYS_PTRACE")
  149. assert.Equal(t, container.LinuxParameters.Capabilities.Drop[0], "SYSLOG")
  150. assert.Equal(t, container.User, "user")
  151. assert.Equal(t, container.WorkingDirectory, "working_dir")
  152. }
  153. func get(l []ecs.TaskDefinition_KeyValuePair, name string) string {
  154. for _, e := range l {
  155. if e.Name == name {
  156. return e.Value
  157. }
  158. }
  159. return ""
  160. }
  161. func TestResourcesHaveProjectTagSet(t *testing.T) {
  162. template := convertYaml(t, "test", `
  163. version: "3"
  164. services:
  165. test:
  166. image: nginx
  167. ports:
  168. - 80:80
  169. - 88:88
  170. `)
  171. for _, r := range template.Resources {
  172. tags := reflect.Indirect(reflect.ValueOf(r)).FieldByName("Tags")
  173. if !tags.IsValid() {
  174. continue
  175. }
  176. for i := 0; i < tags.Len(); i++ {
  177. k := tags.Index(i).FieldByName("Key").String()
  178. v := tags.Index(i).FieldByName("Value").String()
  179. if k == compose.ProjectTag {
  180. assert.Equal(t, v, "Test")
  181. }
  182. }
  183. }
  184. }
  185. func convertResultAsString(t *testing.T, project *types.Project) string {
  186. backend, err := NewBackend("", "")
  187. assert.NilError(t, err)
  188. result, err := backend.Convert(project)
  189. assert.NilError(t, err)
  190. resultAsJSON, err := result.JSON()
  191. assert.NilError(t, err)
  192. return fmt.Sprintf("%s\n", string(resultAsJSON))
  193. }
  194. func load(t *testing.T, paths ...string) *types.Project {
  195. options := cli.ProjectOptions{
  196. Name: t.Name(),
  197. ConfigPaths: paths,
  198. }
  199. project, err := cli.ProjectFromOptions(&options)
  200. assert.NilError(t, err)
  201. return project
  202. }
  203. func convertYaml(t *testing.T, name string, yaml string) *cloudformation.Template {
  204. dict, err := loader.ParseYAML([]byte(yaml))
  205. assert.NilError(t, err)
  206. model, err := loader.Load(types.ConfigDetails{
  207. ConfigFiles: []types.ConfigFile{
  208. {Config: dict},
  209. },
  210. }, func(options *loader.Options) {
  211. options.Name = "Test"
  212. })
  213. assert.NilError(t, err)
  214. template, err := Backend{}.Convert(model)
  215. assert.NilError(t, err)
  216. return template
  217. }