Skip to content

Commit 1ba3833

Browse files
authored
chore: adds cloudformation for publish (#2586)
Adds CloudFormation partial file for publish. Adds CloudFormation for publish environment variable. Adds publish to various service/job CloudFormation files. Adds publish yml file to workload. Addresses #2550 By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
1 parent b099ca8 commit 1ba3833

File tree

23 files changed

+245
-107
lines changed

23 files changed

+245
-107
lines changed

internal/pkg/addon/storage_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func TestS3_MarshalBinary(t *testing.T) {
110110

111111
func TestRDS_MarshalBinary(t *testing.T) {
112112
testCases := map[string]struct {
113-
engine string
113+
engine string
114114
mockDependencies func(ctrl *gomock.Controller, r *RDS)
115115

116116
wantedBinary []byte

internal/pkg/aws/s3/s3.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323

2424
const (
2525
artifactDirName = "manual"
26-
notFound = "NotFound"
26+
notFound = "NotFound"
2727
)
2828

2929
type s3ManagerAPI interface {
@@ -33,7 +33,7 @@ type s3ManagerAPI interface {
3333
type s3API interface {
3434
ListObjectVersions(input *s3.ListObjectVersionsInput) (*s3.ListObjectVersionsOutput, error)
3535
DeleteObjects(input *s3.DeleteObjectsInput) (*s3.DeleteObjectsOutput, error)
36-
HeadBucket (input *s3.HeadBucketInput) (*s3.HeadBucketOutput, error)
36+
HeadBucket(input *s3.HeadBucketInput) (*s3.HeadBucketOutput, error)
3737
}
3838

3939
// NamedBinary is a named binary to be uploaded.
@@ -110,8 +110,8 @@ func (s *S3) EmptyBucket(bucket string) error {
110110
var err error
111111

112112
// Bucket is exists check to make sure the bucket exists before proceeding in emptying it
113-
isExists, err:= s.isBucketExists(bucket)
114-
if err!= nil {
113+
isExists, err := s.isBucketExists(bucket)
114+
if err != nil {
115115
return fmt.Errorf("unable to determine the existance of bucket %s: %w", bucket, err)
116116
}
117117

internal/pkg/cli/task_delete_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func TestDeleteTaskOpts_Validate(t *testing.T) {
5757
"with all flags": {
5858
inAppName: "phonetool",
5959
inEnvName: "test",
60-
inName: "oneoff",
60+
inName: "oneoff",
6161
setupMocks: func(m validateMocks) {
6262
m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil)
6363
m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil)
@@ -69,8 +69,8 @@ func TestDeleteTaskOpts_Validate(t *testing.T) {
6969
"task does not exist": {
7070
inAppName: "phonetool",
7171
inEnvName: "test",
72-
inName: "oneoff",
73-
want: errors.New("get task: some error"),
72+
inName: "oneoff",
73+
want: errors.New("get task: some error"),
7474
setupMocks: func(m validateMocks) {
7575
m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil)
7676
m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil)
@@ -81,10 +81,10 @@ func TestDeleteTaskOpts_Validate(t *testing.T) {
8181
"with default cluster flag set": {
8282
inDefaultCluster: true,
8383
inName: "oneoff",
84-
setupMocks: func(m validateMocks) {
84+
setupMocks: func(m validateMocks) {
8585
m.cfn.EXPECT().GetTaskStack("oneoff")
8686
},
87-
want: nil,
87+
want: nil,
8888
},
8989
"with default cluster and env flag": {
9090
inDefaultCluster: true,
@@ -112,7 +112,7 @@ func TestDeleteTaskOpts_Validate(t *testing.T) {
112112

113113
mocks := validateMocks{
114114
store: mockstore,
115-
cfn: mocktaskStackManager,
115+
cfn: mocktaskStackManager,
116116
}
117117

118118
tc.setupMocks(mocks)

internal/pkg/deploy/cloudformation/stack/backend_svc.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -118,26 +118,26 @@ func (s *BackendService) Template() (string, error) {
118118
return "", err
119119
}
120120
content, err := s.parser.ParseBackendService(template.WorkloadOpts{
121-
Variables: s.manifest.BackendServiceConfig.Variables,
122-
Secrets: s.manifest.BackendServiceConfig.Secrets,
123-
NestedStack: outputs,
124-
Sidecars: sidecars,
125-
Autoscaling: autoscaling,
126-
CapacityProviders: capacityProviders,
127-
DesiredCountOnSpot: desiredCountOnSpot,
128-
ExecuteCommand: convertExecuteCommand(&s.manifest.ExecuteCommand),
129-
WorkloadType: manifest.BackendServiceType,
130-
HealthCheck: s.manifest.BackendServiceConfig.ImageConfig.HealthCheckOpts(),
131-
LogConfig: convertLogging(s.manifest.Logging),
132-
DockerLabels: s.manifest.ImageConfig.DockerLabels,
133-
DesiredCountLambda: desiredCountLambda.String(),
134-
EnvControllerLambda: envControllerLambda.String(),
135-
Storage: storage,
136-
Network: convertNetworkConfig(s.manifest.Network),
137-
EntryPoint: entrypoint,
138-
Command: command,
139-
DependsOn: dependencies,
140-
CredentialsParameter: aws.StringValue(s.manifest.ImageConfig.Credentials),
121+
Variables: s.manifest.BackendServiceConfig.Variables,
122+
Secrets: s.manifest.BackendServiceConfig.Secrets,
123+
NestedStack: outputs,
124+
Sidecars: sidecars,
125+
Autoscaling: autoscaling,
126+
CapacityProviders: capacityProviders,
127+
DesiredCountOnSpot: desiredCountOnSpot,
128+
ExecuteCommand: convertExecuteCommand(&s.manifest.ExecuteCommand),
129+
WorkloadType: manifest.BackendServiceType,
130+
HealthCheck: s.manifest.BackendServiceConfig.ImageConfig.HealthCheckOpts(),
131+
LogConfig: convertLogging(s.manifest.Logging),
132+
DockerLabels: s.manifest.ImageConfig.DockerLabels,
133+
DesiredCountLambda: desiredCountLambda.String(),
134+
EnvControllerLambda: envControllerLambda.String(),
135+
Storage: storage,
136+
Network: convertNetworkConfig(s.manifest.Network),
137+
EntryPoint: entrypoint,
138+
Command: command,
139+
DependsOn: dependencies,
140+
CredentialsParameter: aws.StringValue(s.manifest.ImageConfig.Credentials),
141141
ServiceDiscoveryEndpoint: s.rc.ServiceDiscoveryEndpoint,
142142
})
143143
if err != nil {

internal/pkg/deploy/cloudformation/stack/scheduled_job.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -163,21 +163,21 @@ func (j *ScheduledJob) Template() (string, error) {
163163
}
164164

165165
content, err := j.parser.ParseScheduledJob(template.WorkloadOpts{
166-
Variables: j.manifest.Variables,
167-
Secrets: j.manifest.Secrets,
168-
NestedStack: outputs,
169-
Sidecars: sidecars,
170-
ScheduleExpression: schedule,
171-
StateMachine: stateMachine,
172-
HealthCheck: j.manifest.ImageConfig.HealthCheckOpts(),
173-
LogConfig: convertLogging(j.manifest.Logging),
174-
DockerLabels: j.manifest.ImageConfig.DockerLabels,
175-
Storage: storage,
176-
Network: convertNetworkConfig(j.manifest.Network),
177-
EntryPoint: entrypoint,
178-
Command: command,
179-
DependsOn: dependencies,
180-
CredentialsParameter: aws.StringValue(j.manifest.ImageConfig.Credentials),
166+
Variables: j.manifest.Variables,
167+
Secrets: j.manifest.Secrets,
168+
NestedStack: outputs,
169+
Sidecars: sidecars,
170+
ScheduleExpression: schedule,
171+
StateMachine: stateMachine,
172+
HealthCheck: j.manifest.ImageConfig.HealthCheckOpts(),
173+
LogConfig: convertLogging(j.manifest.Logging),
174+
DockerLabels: j.manifest.ImageConfig.DockerLabels,
175+
Storage: storage,
176+
Network: convertNetworkConfig(j.manifest.Network),
177+
EntryPoint: entrypoint,
178+
Command: command,
179+
DependsOn: dependencies,
180+
CredentialsParameter: aws.StringValue(j.manifest.ImageConfig.Credentials),
181181
ServiceDiscoveryEndpoint: j.rc.ServiceDiscoveryEndpoint,
182182

183183
EnvControllerLambda: envControllerLambda.String(),

internal/pkg/deploy/cloudformation/stack/transformers.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"time"
1212

1313
"github.com/aws/aws-sdk-go/aws"
14+
"github.com/aws/aws-sdk-go/aws/endpoints"
1415
"github.com/aws/copilot-cli/internal/pkg/manifest"
1516
"github.com/aws/copilot-cli/internal/pkg/template"
1617
)
@@ -586,14 +587,18 @@ func convertCommand(command *manifest.CommandOverride) ([]string, error) {
586587
return out, nil
587588
}
588589

589-
func convertPublish(p *manifest.PublishConfig) (*template.PublishOpts, error) {
590+
func convertPublish(p *manifest.PublishConfig, accountID, region, app, env, svc string) (*template.PublishOpts, error) {
590591
if p == nil || len(p.Topics) == 0 {
591592
return nil, nil
592593
}
594+
partition, ok := endpoints.PartitionForRegion(endpoints.DefaultPartitions(), region)
595+
if !ok {
596+
return nil, fmt.Errorf("find the partition for region %s", region)
597+
}
593598
publishers := template.PublishOpts{}
594599
// convert the topics to template Topics
595600
for _, topic := range p.Topics {
596-
t, err := convertTopic(topic)
601+
t, err := convertTopic(topic, accountID, partition.ID(), region, app, env, svc)
597602
if err != nil {
598603
return nil, err
599604
}
@@ -604,19 +609,23 @@ func convertPublish(p *manifest.PublishConfig) (*template.PublishOpts, error) {
604609
return &publishers, nil
605610
}
606611

607-
func convertTopic(t manifest.Topic) (*template.Topics, error) {
608-
err := validatePubSubName(t.Name)
609-
if err != nil {
612+
func convertTopic(t manifest.Topic, accountID, partition, region, app, env, svc string) (*template.Topic, error) {
613+
// topic should have a valid name and valid service worker names
614+
if err := validatePubSubName(t.Name); err != nil {
610615
return nil, err
611616
}
612-
613-
workerErr := validateWorkerNames(t.AllowedWorkers)
614-
if workerErr != nil {
615-
return nil, workerErr
617+
if err := validateWorkerNames(t.AllowedWorkers); err != nil {
618+
return nil, err
616619
}
617620

618-
return &template.Topics{
621+
return &template.Topic{
619622
Name: t.Name,
620623
AllowedWorkers: t.AllowedWorkers,
624+
AccountID: accountID,
625+
Partition: partition,
626+
Region: region,
627+
App: app,
628+
Env: env,
629+
Svc: svc,
621630
}, nil
622631
}

internal/pkg/deploy/cloudformation/stack/transformers_test.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,12 @@ func Test_convertImageDependsOn(t *testing.T) {
14591459
}
14601460

14611461
func Test_convertPublish(t *testing.T) {
1462+
accountId := "123456789123"
1463+
partition := "aws"
1464+
region := "us-west-2"
1465+
app := "testapp"
1466+
env := "testenv"
1467+
svc := "hello"
14621468
testCases := map[string]struct {
14631469
inPublish *manifest.PublishConfig
14641470

@@ -1486,9 +1492,15 @@ func Test_convertPublish(t *testing.T) {
14861492
},
14871493
},
14881494
wanted: &template.PublishOpts{
1489-
Topics: []*template.Topics{
1495+
Topics: []*template.Topic{
14901496
{
1491-
Name: aws.String("topic1"),
1497+
Name: aws.String("topic1"),
1498+
AccountID: accountId,
1499+
Partition: partition,
1500+
Region: region,
1501+
App: app,
1502+
Env: env,
1503+
Svc: svc,
14921504
},
14931505
},
14941506
},
@@ -1503,10 +1515,16 @@ func Test_convertPublish(t *testing.T) {
15031515
},
15041516
},
15051517
wanted: &template.PublishOpts{
1506-
Topics: []*template.Topics{
1518+
Topics: []*template.Topic{
15071519
{
15081520
Name: aws.String("topic1"),
15091521
AllowedWorkers: []string{"worker1"},
1522+
AccountID: accountId,
1523+
Partition: partition,
1524+
Region: region,
1525+
App: app,
1526+
Env: env,
1527+
Svc: svc,
15101528
},
15111529
},
15121530
},
@@ -1536,7 +1554,7 @@ func Test_convertPublish(t *testing.T) {
15361554
}
15371555
for name, tc := range testCases {
15381556
t.Run(name, func(t *testing.T) {
1539-
got, err := convertPublish(tc.inPublish)
1557+
got, err := convertPublish(tc.inPublish, accountId, region, app, env, svc)
15401558
if tc.wantedError != nil {
15411559
require.EqualError(t, err, tc.wantedError.Error())
15421560
} else {

internal/pkg/deploy/cloudformation/stack/validate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ var (
2626
errNoContainerPath = errors.New("`path` cannot be empty")
2727
errNoSourceVolume = errors.New("`source_volume` cannot be empty")
2828
errEmptyEFSConfig = errors.New("bad EFS configuration: `efs` cannot be empty")
29-
errMissingPublishTopicField = errors.New("topic `name` cannot be empty")
29+
errMissingPublishTopicField = errors.New("field `publish.topics[].name` cannot be empty")
3030
)
3131

3232
// Conditional errors.

internal/pkg/deploy/pipeline_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ func TestPipelineBuildFromManifest(t *testing.T) {
152152
const defaultImage = "aws/codebuild/amazonlinux2-x86_64-standard:3.0"
153153

154154
testCases := map[string]struct {
155-
mfBuild *manifest.Build
156-
expectedBuild *Build
155+
mfBuild *manifest.Build
156+
expectedBuild *Build
157157
}{
158158
"set default image if not be specified in manifest": {
159159
mfBuild: nil,

internal/pkg/manifest/svc_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ environments:
8080
LoadBalancedWebServiceConfig: LoadBalancedWebServiceConfig{
8181
ImageConfig: ImageWithPortAndHealthcheck{
8282
ImageWithPort: ImageWithPort{Image: Image{Build: BuildArgsOrString{},
83-
Location: aws.String("foo/bar"),
83+
Location: aws.String("foo/bar"),
8484
Credentials: aws.String("some arn"),
8585
}, Port: aws.Uint16(80)},
8686
},

internal/pkg/manifest/workload.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -429,15 +429,15 @@ func (lc *Logging) GetEnableMetadata() *string {
429429

430430
// SidecarConfig represents the configurable options for setting up a sidecar container.
431431
type SidecarConfig struct {
432-
Port *string `yaml:"port"`
433-
Image *string `yaml:"image"`
434-
Essential *bool `yaml:"essential"`
435-
CredsParam *string `yaml:"credentialsParameter"`
436-
Variables map[string]string `yaml:"variables"`
437-
Secrets map[string]string `yaml:"secrets"`
438-
MountPoints []SidecarMountPoint `yaml:"mount_points"`
439-
DockerLabels map[string]string `yaml:"labels"`
440-
DependsOn map[string]string `yaml:"depends_on"`
432+
Port *string `yaml:"port"`
433+
Image *string `yaml:"image"`
434+
Essential *bool `yaml:"essential"`
435+
CredsParam *string `yaml:"credentialsParameter"`
436+
Variables map[string]string `yaml:"variables"`
437+
Secrets map[string]string `yaml:"secrets"`
438+
MountPoints []SidecarMountPoint `yaml:"mount_points"`
439+
DockerLabels map[string]string `yaml:"labels"`
440+
DependsOn map[string]string `yaml:"depends_on"`
441441
ImageOverride `yaml:",inline"`
442442
}
443443

internal/pkg/template/template_functions.go

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -119,45 +119,42 @@ func generateMountPointJSON(mountPoints []*MountPoint) string {
119119
}
120120
volumeMap[aws.StringValue(mp.SourceVolume)] = aws.StringValue(mp.ContainerPath)
121121
}
122-
// Check for empty maps
123-
if len(volumeMap) == 0 {
124-
return "{}"
125-
}
126122

127-
out, err := json.Marshal(volumeMap)
128-
if err != nil {
123+
out, ok := getJSONMap(volumeMap)
124+
if !ok {
129125
return "{}"
130126
}
127+
131128
return string(out)
132129

133130
}
134131

135132
// generatePublisherJSON turns a list of Topics objects into a JSON string:
136-
// `{"myTopic": ["hello"], "mySecondTopic": ["hello","goodbye"]}`
133+
// `{"myTopic": "topicArn", "mySecondTopic": "secondTopicArn"}`
137134
// This function must be called on an array of correctly constructed Topic objects.
138-
func generatePublishJSON(topics []*Topics) string {
139-
publisherMap := make(map[string][]string)
135+
func generateSNSJSON(topics []*Topic) string {
136+
if topics == nil {
137+
return ""
138+
}
139+
topicMap := make(map[string]string)
140140

141-
for _, pb := range topics {
142-
if aws.StringValue(pb.Name) == "" {
141+
for _, topic := range topics {
142+
// Topics with no name will not be included in the json
143+
if topic.Name == nil {
143144
continue
144145
}
145-
if pb.AllowedWorkers == nil {
146-
publisherMap[aws.StringValue(pb.Name)] = []string{}
147-
} else {
148-
publisherMap[aws.StringValue(pb.Name)] = pb.AllowedWorkers
149-
}
146+
topicMap[aws.StringValue(topic.Name)] = topic.ARN()
150147
}
151148

152-
out, ok := getJSONMap(publisherMap)
149+
out, ok := getJSONMap(topicMap)
153150
if !ok {
154151
return "{}"
155152
}
156153

157154
return string(out)
158155
}
159156

160-
func getJSONMap(inMap map[string][]string) ([]byte, bool) {
157+
func getJSONMap(inMap map[string]string) ([]byte, bool) {
161158
// Check for empty maps
162159
if len(inMap) == 0 {
163160
return nil, false

0 commit comments

Comments
 (0)