diff --git a/internal/pkg/deploy/cloudformation/stack/backend_svc.go b/internal/pkg/deploy/cloudformation/stack/backend_svc.go index 9325b9ed14b..fd67ef40405 100644 --- a/internal/pkg/deploy/cloudformation/stack/backend_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/backend_svc.go @@ -83,6 +83,10 @@ func (s *BackendService) Template() (string, error) { if err != nil { return "", fmt.Errorf("convert the Auto Scaling configuration for service %s: %w", s.name, err) } + storage, err := convertStorageOpts(s.manifest.Storage) + if err != nil { + return "", fmt.Errorf("convert storage options for service %s: %w", s.name, err) + } content, err := s.parser.ParseBackendService(template.WorkloadOpts{ Variables: s.manifest.BackendServiceConfig.Variables, Secrets: s.manifest.BackendServiceConfig.Secrets, @@ -92,6 +96,7 @@ func (s *BackendService) Template() (string, error) { HealthCheck: s.manifest.BackendServiceConfig.ImageConfig.HealthCheckOpts(), LogConfig: convertLogging(s.manifest.Logging), DesiredCountLambda: desiredCountLambda.String(), + Storage: storage, }) if err != nil { return "", fmt.Errorf("parse backend service template: %w", err) diff --git a/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go b/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go index 1c57feb673d..bd149066d02 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go @@ -112,6 +112,12 @@ func (s *LoadBalancedWebService) Template() (string, error) { if err != nil { return "", fmt.Errorf("convert the Auto Scaling configuration for service %s: %w", s.name, err) } + + storage, err := convertStorageOpts(s.manifest.Storage) + if err != nil { + return "", fmt.Errorf("convert storage options for service %s: %w", s.name, err) + } + content, err := s.parser.ParseLoadBalancedWebService(template.WorkloadOpts{ Variables: s.manifest.Variables, Secrets: s.manifest.Secrets, @@ -124,6 +130,7 @@ func (s *LoadBalancedWebService) Template() (string, error) { RulePriorityLambda: rulePriorityLambda.String(), DesiredCountLambda: desiredCountLambda.String(), EnvControllerLambda: envControllerLambda.String(), + Storage: storage, }) if err != nil { return "", err diff --git a/internal/pkg/deploy/cloudformation/stack/scheduled_job.go b/internal/pkg/deploy/cloudformation/stack/scheduled_job.go index 727b9268c97..21c995b2457 100644 --- a/internal/pkg/deploy/cloudformation/stack/scheduled_job.go +++ b/internal/pkg/deploy/cloudformation/stack/scheduled_job.go @@ -137,6 +137,11 @@ func (j *ScheduledJob) Template() (string, error) { return "", fmt.Errorf("convert retry/timeout config for job %s: %w", j.name, err) } + storage, err := convertStorageOpts(j.manifest.Storage) + if err != nil { + return "", fmt.Errorf("convert storage options for job %s: %w", j.name, err) + } + content, err := j.parser.ParseScheduledJob(template.WorkloadOpts{ Variables: j.manifest.Variables, Secrets: j.manifest.Secrets, @@ -145,6 +150,7 @@ func (j *ScheduledJob) Template() (string, error) { ScheduleExpression: schedule, StateMachine: stateMachine, LogConfig: convertLogging(j.manifest.Logging), + Storage: storage, }) if err != nil { return "", fmt.Errorf("parse scheduled job template: %w", err) diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-manifest.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-manifest.yml index 2b245da196d..ef73b679220 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-manifest.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-manifest.yml @@ -24,6 +24,23 @@ retries: 3 # Optional. The timeout after which to stop the job if it's still running. You can use the units (h, m, s). timeout: 1h +storage: + volumes: + myEFSVolume: + path: '/etc/mount1' + read_only: true + efs: + id: fs-12345 + +sidecars: + nginx: + image: public.ecr.aws/nginx/nginx + port: 8080 + mount_points: + - source_volume: myEFSVolume + path: '/var/www' + variables: + NGINX_PORT: 8080 # Optional fields for more advanced use-cases. # #variables: # Pass environment variables as key value pairs. diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-test.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-test.stack.yml index 42cd9d5ee5c..53f70432947 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-test.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-test.stack.yml @@ -66,6 +66,8 @@ Resources: Value: !Sub '${EnvName}' - Name: COPILOT_SERVICE_NAME Value: !Sub '${WorkloadName}' + - Name: COPILOT_MOUNT_POINTS + Value: '{"myEFSVolume":"/etc/mount1"}' LogConfiguration: LogDriver: awslogs @@ -73,6 +75,39 @@ Resources: awslogs-region: !Ref AWS::Region awslogs-group: !Ref LogGroup awslogs-stream-prefix: copilot + + MountPoints: + - ContainerPath: /etc/mount1 + ReadOnly: true + SourceVolume: myEFSVolume + - Name: nginx + Image: 'public.ecr.aws/nginx/nginx' + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: !Ref LogGroup + awslogs-region: !Ref AWS::Region + awslogs-stream-prefix: copilot + MountPoints: + - ContainerPath: '/var/www' + ReadOnly: true + SourceVolume: myEFSVolume + PortMappings: + - ContainerPort: 8080 + Environment: + - Name: NGINX_PORT + Value: '8080' + - Name: COPILOT_MOUNT_POINTS + Value: '{"myEFSVolume":"/var/www"}' + + Volumes: + - Name: myEFSVolume + EFSVolumeConfiguration: + FilesystemId: fs-12345 + RootDirectory: / + TransitEncryption: ENABLED + AuthorizationConfig: + IAM: DISABLED ExecutionRole: @@ -145,7 +180,15 @@ Resources: StringEquals: 'iam:ResourceTag/copilot-application': !Sub '${AppName}' 'iam:ResourceTag/copilot-environment': !Sub '${EnvName}' - + - PolicyName: 'GrantEFSAccessfs-12345' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Action: + - 'elasticfilesystem:ClientMount' + Resource: + - !Sub 'arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/fs-12345' Rule: Metadata: diff --git a/internal/pkg/deploy/cloudformation/stack/transformers.go b/internal/pkg/deploy/cloudformation/stack/transformers.go index fe76f4280db..df406e4d7b1 100644 --- a/internal/pkg/deploy/cloudformation/stack/transformers.go +++ b/internal/pkg/deploy/cloudformation/stack/transformers.go @@ -53,14 +53,19 @@ func convertSidecar(s map[string]*manifest.SidecarConfig) ([]*template.SidecarOp if err != nil { return nil, err } + mp, err := renderSidecarMountPoints(config.MountPoints) + if err != nil { + return nil, err + } sidecars = append(sidecars, &template.SidecarOpts{ - Name: aws.String(name), - Image: config.Image, - Port: port, - Protocol: protocol, - CredsParam: config.CredsParam, - Secrets: config.Secrets, - Variables: config.Variables, + Name: aws.String(name), + Image: config.Image, + Port: port, + Protocol: protocol, + CredsParam: config.CredsParam, + Secrets: config.Secrets, + Variables: config.Variables, + MountPoints: mp, }) } return sidecars, nil @@ -153,6 +158,9 @@ func logConfigOpts(lc *manifest.Logging) *template.LogConfigOpts { // convertStorageOpts converts a manifest Storage field into template data structures which can be used // to execute CFN templates func convertStorageOpts(in *manifest.Storage) (*template.StorageOpts, error) { + if in == nil { + return nil, nil + } v, err := renderVolumes(in.Volumes) if err != nil { return nil, err diff --git a/internal/pkg/manifest/lb_web_svc_test.go b/internal/pkg/manifest/lb_web_svc_test.go index 4dc019612f7..74de8d3a3e1 100644 --- a/internal/pkg/manifest/lb_web_svc_test.go +++ b/internal/pkg/manifest/lb_web_svc_test.go @@ -159,7 +159,7 @@ func TestLoadBalancedWebService_ApplyEnv(t *testing.T) { Count: Count{ Value: aws.Int(1), }, - Storage: Storage{ + Storage: &Storage{ Volumes: map[string]Volume{ "myEFSVolume": { MountPointOpts: MountPointOpts{ @@ -205,7 +205,7 @@ func TestLoadBalancedWebService_ApplyEnv(t *testing.T) { Count: Count{ Value: aws.Int(1), }, - Storage: Storage{ + Storage: &Storage{ Volumes: map[string]Volume{ "myEFSVolume": { MountPointOpts: MountPointOpts{ @@ -259,7 +259,7 @@ func TestLoadBalancedWebService_ApplyEnv(t *testing.T) { "GITHUB_TOKEN": "1111", "TWILIO_TOKEN": "1111", }, - Storage: Storage{ + Storage: &Storage{ Volumes: map[string]Volume{ "myEFSVolume": { MountPointOpts: MountPointOpts{ @@ -311,7 +311,7 @@ func TestLoadBalancedWebService_ApplyEnv(t *testing.T) { Variables: map[string]string{ "DDB_TABLE_NAME": "awards-prod", }, - Storage: Storage{ + Storage: &Storage{ Volumes: map[string]Volume{ "myEFSVolume": { EFS: EFSVolumeConfiguration{ @@ -385,7 +385,7 @@ func TestLoadBalancedWebService_ApplyEnv(t *testing.T) { "GITHUB_TOKEN": "1111", "TWILIO_TOKEN": "1111", }, - Storage: Storage{ + Storage: &Storage{ Volumes: map[string]Volume{ "myEFSVolume": { MountPointOpts: MountPointOpts{ diff --git a/internal/pkg/manifest/workload.go b/internal/pkg/manifest/workload.go index 2ba9b14c20c..8fc9719ae8d 100644 --- a/internal/pkg/manifest/workload.go +++ b/internal/pkg/manifest/workload.go @@ -215,7 +215,7 @@ type TaskConfig struct { Count Count `yaml:"count"` Variables map[string]string `yaml:"variables"` Secrets map[string]string `yaml:"secrets"` - Storage Storage `yaml:"storage"` + Storage *Storage `yaml:"storage"` } // WorkloadProps contains properties for creating a new workload manifest. diff --git a/templates/workloads/jobs/scheduled-job/cf.yml b/templates/workloads/jobs/scheduled-job/cf.yml index 0d3c118b4b2..a1da49adf68 100644 --- a/templates/workloads/jobs/scheduled-job/cf.yml +++ b/templates/workloads/jobs/scheduled-job/cf.yml @@ -44,11 +44,11 @@ Resources: {{include "envvars" . | indent 10}} {{include "secrets" . | indent 10}} {{include "logconfig" . | indent 10}} -{{- if .Storage}} +{{- if .Storage -}} {{include "mount-points" . | indent 10}} -{{- end}} +{{- end -}} {{include "sidecars" . | indent 8}} -{{- if .Storage}} +{{- if .Storage -}} {{include "volumes" . | indent 6}} {{- end}} {{include "executionrole" . | indent 2}} diff --git a/templates/workloads/partials/cf/mount-points.yml b/templates/workloads/partials/cf/mount-points.yml index b6699b58852..fba74870902 100644 --- a/templates/workloads/partials/cf/mount-points.yml +++ b/templates/workloads/partials/cf/mount-points.yml @@ -1,7 +1,7 @@ {{- if .Storage.MountPoints}} MountPoints: {{- range $mp := .Storage.MountPoints}} - - ContainerPath: {{$mp.ContainerPath}} + - ContainerPath: '{{$mp.ContainerPath}}' ReadOnly: {{$mp.ReadOnly}} SourceVolume: {{$mp.SourceVolume}} {{- end -}} diff --git a/templates/workloads/partials/cf/sidecars.yml b/templates/workloads/partials/cf/sidecars.yml index c0cab21eb9e..f7f0424f9af 100644 --- a/templates/workloads/partials/cf/sidecars.yml +++ b/templates/workloads/partials/cf/sidecars.yml @@ -50,7 +50,7 @@ {{- range $mp := $sidecar.MountPoints}} - SourceVolume: {{$mp.SourceVolume}} ReadOnly: {{$mp.ReadOnly}} - ContainerPath: {{$mp.ContainerPath}} + ContainerPath: '{{$mp.ContainerPath}}' {{- end}} {{- end}} {{- end}} \ No newline at end of file diff --git a/templates/workloads/partials/cf/volumes.yml b/templates/workloads/partials/cf/volumes.yml index 11ffcbc415f..55b844c3cb9 100644 --- a/templates/workloads/partials/cf/volumes.yml +++ b/templates/workloads/partials/cf/volumes.yml @@ -4,7 +4,7 @@ Volumes: - Name: {{$vol.Name}} EFSVolumeConfiguration: FilesystemId: {{$vol.Filesystem}} - RootDirectory: {{$vol.RootDirectory}} + RootDirectory: '{{$vol.RootDirectory}}' TransitEncryption: ENABLED {{- if or $vol.AccessPointID $vol.IAM}} AuthorizationConfig: @@ -15,5 +15,5 @@ Volumes: IAM: {{$vol.IAM}} {{- end}} {{- end}} -{{- end}} -{{- end}} +{{- end -}} +{{- end -}} diff --git a/templates/workloads/services/backend/cf.yml b/templates/workloads/services/backend/cf.yml index 2c7a4294805..df3047af240 100644 --- a/templates/workloads/services/backend/cf.yml +++ b/templates/workloads/services/backend/cf.yml @@ -56,11 +56,11 @@ Resources: StartPeriod: {{.HealthCheck.StartPeriod}} Timeout: {{.HealthCheck.Timeout}} {{- end}} -{{- if .Storage}} +{{- if .Storage -}} {{include "mount-points" . | indent 10}} -{{- end}} +{{- end -}} {{include "sidecars" . | indent 8}} -{{- if .Storage}} +{{- if .Storage -}} {{include "volumes" . | indent 6}} {{- end}} {{include "executionrole" . | indent 2}} diff --git a/templates/workloads/services/lb-web/cf.yml b/templates/workloads/services/lb-web/cf.yml index 76596944161..2241d5578d3 100644 --- a/templates/workloads/services/lb-web/cf.yml +++ b/templates/workloads/services/lb-web/cf.yml @@ -67,11 +67,11 @@ Resources: Value: !GetAtt EnvControllerAction.PublicLoadBalancerDNSName {{include "secrets" . | indent 10}} {{include "logconfig" . | indent 10}} -{{- if .Storage}} +{{- if .Storage -}} {{include "mount-points" . | indent 10}} -{{- end}} +{{- end -}} {{include "sidecars" . | indent 8}} -{{if .Storage}} +{{if .Storage -}} {{include "volumes" . | indent 6}} {{- end}} {{include "executionrole" . | indent 2}}