Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): display secrets as subcategory in svc_show #1704

Merged
merged 17 commits into from
Nov 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions internal/pkg/aws/ecs/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,50 @@ func (t TaskStatus) HumanString() string {
// TaskDefinition wraps up ECS TaskDefinition struct.
type TaskDefinition ecs.TaskDefinition

// ContainerEnvVar holds basic info of an environment variable.
type ContainerEnvVar struct {
Name string
Container string
Value string
}

// EnvironmentVariables returns environment variables of the task definition.
func (t *TaskDefinition) EnvironmentVariables() map[string]string {
envs := make(map[string]string)
for _, env := range t.ContainerDefinitions[0].Environment {
envs[aws.StringValue(env.Name)] = aws.StringValue(env.Value)
func (t *TaskDefinition) EnvironmentVariables() []*ContainerEnvVar {
var envs []*ContainerEnvVar
for _, container := range t.ContainerDefinitions {
for _, env := range container.Environment {
envs = append(envs, &ContainerEnvVar{
aws.StringValue(env.Name),
aws.StringValue(container.Name),
aws.StringValue(env.Value),
})
}
}
return envs
}

// ContainerSecret holds basic info of a secret.
type ContainerSecret struct {
Name string
Container string
ValueFrom string
}

// Secrets returns secrets of the task definition.
func (t *TaskDefinition) Secrets() []*ContainerSecret {
var secrets []*ContainerSecret
for _, container := range t.ContainerDefinitions {
for _, secret := range container.Secrets {
secrets = append(secrets, &ContainerSecret{
aws.StringValue(secret.Name),
aws.StringValue(container.Name),
aws.StringValue(secret.ValueFrom),
})
}
}
return secrets
}

// TaskID parses the task ARN and returns the task ID.
// For example: arn:aws:ecs:us-west-2:123456789:task/my-project-test-Cluster-9F7Y0RLP60R7/4082490ee6c245e09d2145010aa1ba8d,
// arn:aws:ecs:us-west-2:123456789:task/4082490ee6c245e09d2145010aa1ba8d
Expand Down
75 changes: 70 additions & 5 deletions internal/pkg/aws/ecs/task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,9 @@ func TestTaskDefinition_EnvVars(t *testing.T) {
testCases := map[string]struct {
inContainers []*ecs.ContainerDefinition

wantEnvVars map[string]string
wantEnvVars []*ContainerEnvVar
}{
"should return wrapped error given error": {
"should return wrapped error given error; otherwise should return list of ContainerEnvVar objects": {
inContainers: []*ecs.ContainerDefinition{
{
Environment: []*ecs.KeyValuePair{
Expand All @@ -258,12 +258,21 @@ func TestTaskDefinition_EnvVars(t *testing.T) {
Value: aws.String("prod"),
},
},
Name: aws.String("container"),
},
},

wantEnvVars: map[string]string{
"COPILOT_SERVICE_NAME": "my-svc",
"COPILOT_ENVIRONMENT_NAME": "prod",
wantEnvVars: []*ContainerEnvVar{
{
Name: "COPILOT_SERVICE_NAME",
Container: "container",
Value: "my-svc",
},
{
Name: "COPILOT_ENVIRONMENT_NAME",
Container: "container",
Value: "prod",
},
},
},
}
Expand All @@ -285,3 +294,59 @@ func TestTaskDefinition_EnvVars(t *testing.T) {

}
}

func TestTaskDefinition_Secrets(t *testing.T) {
testCases := map[string]struct {
inContainers []*ecs.ContainerDefinition

wantedSecrets []*ContainerSecret
}{
"should return secrets of the task definition as a list of ContainerSecret objects": {
inContainers: []*ecs.ContainerDefinition{
{
Name: aws.String("container"),
Secrets: []*ecs.Secret{
{
Name: aws.String("GITHUB_WEBHOOK_SECRET"),
ValueFrom: aws.String("GH_WEBHOOK_SECRET"),
},
{
Name: aws.String("SOME_OTHER_SECRET"),
ValueFrom: aws.String("SHHHHHHHH"),
},
},
},
},

wantedSecrets: []*ContainerSecret{
{
Name: "GITHUB_WEBHOOK_SECRET",
Container: "container",
ValueFrom: "GH_WEBHOOK_SECRET",
},
{
Name: "SOME_OTHER_SECRET",
Container: "container",
ValueFrom: "SHHHHHHHH",
},
},
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
// GIVEN
ctrl := gomock.NewController(t)
defer ctrl.Finish()

taskDefinition := TaskDefinition{
ContainerDefinitions: tc.inContainers,
}

gotSecrets := taskDefinition.Secrets()

require.Equal(t, tc.wantedSecrets, gotSecrets)
})

}
}
18 changes: 14 additions & 4 deletions internal/pkg/describe/backend_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"sort"
"text/tabwriter"

"github.com/aws/copilot-cli/internal/pkg/deploy/cloudformation/stack"
Expand Down Expand Up @@ -99,7 +98,8 @@ func (d *BackendServiceDescriber) Describe() (HumanJSONStringer, error) {

var configs []*ServiceConfig
var services []*ServiceDiscovery
var envVars []*EnvVars
var envVars []*envVar
var secrets []*secret
for _, env := range environments {
err := d.initServiceDescriber(env)
if err != nil {
Expand Down Expand Up @@ -130,9 +130,12 @@ func (d *BackendServiceDescriber) Describe() (HumanJSONStringer, error) {
return nil, fmt.Errorf("retrieve environment variables: %w", err)
}
envVars = append(envVars, flattenEnvVars(env, backendSvcEnvVars)...)
webSvcSecrets, err := d.svcDescriber[env].Secrets()
if err != nil {
return nil, fmt.Errorf("retrieve secrets: %w", err)
}
secrets = append(secrets, flattenSecrets(env, webSvcSecrets)...)
}
sort.SliceStable(envVars, func(i, j int) bool { return envVars[i].Environment < envVars[j].Environment })
sort.SliceStable(envVars, func(i, j int) bool { return envVars[i].Name < envVars[j].Name })

resources := make(map[string][]*CfnResource)
if d.enableResources {
Expand All @@ -156,6 +159,7 @@ func (d *BackendServiceDescriber) Describe() (HumanJSONStringer, error) {
Configurations: configs,
ServiceDiscovery: services,
Variables: envVars,
Secrets: secrets,
Resources: resources,
}, nil
}
Expand All @@ -168,6 +172,7 @@ type backendSvcDesc struct {
Configurations configurations `json:"configurations"`
ServiceDiscovery serviceDiscoveries `json:"serviceDiscovery"`
Variables envVars `json:"variables"`
Secrets secrets `json:"secrets,omitempty"`
Resources cfnResources `json:"resources,omitempty"`
}

Expand Down Expand Up @@ -198,6 +203,11 @@ func (w *backendSvcDesc) HumanString() string {
fmt.Fprint(writer, color.Bold.Sprint("\nVariables\n\n"))
writer.Flush()
w.Variables.humanString(writer)
if len(w.Secrets) != 0 {
fmt.Fprint(writer, color.Bold.Sprint("\nSecrets\n\n"))
writer.Flush()
w.Secrets.humanString(writer)
}
if len(w.Resources) != 0 {
fmt.Fprint(writer, color.Bold.Sprint("\nResources\n"))
writer.Flush()
Expand Down
Loading