-
Notifications
You must be signed in to change notification settings - Fork 398
/
app.go
152 lines (130 loc) · 5.24 KB
/
app.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package config
import (
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ssm"
)
// Application is a named collection of environments and services.
type Application struct {
Name string `json:"name"` // Name of an Application. Must be unique amongst other apps in the same account.
AccountID string `json:"account"` // AccountID this app is mastered in.
PermissionsBoundary string `json:"permissionsBoundary,omitempty"` // Existing IAM permissions boundary.
Domain string `json:"domain"` // Existing domain name in Route53. An empty domain name means the user does not have one.
DomainHostedZoneID string `json:"domainHostedZoneID"` // Existing domain hosted zone in Route53. An empty domain name means the user does not have one.
Version string `json:"version"` // The version of the app layout in the underlying datastore (e.g. SSM).
Tags map[string]string `json:"tags,omitempty"` // Labels to apply to resources created within the app.
}
// CreateApplication instantiates a new application, validates its uniqueness and stores it in SSM.
func (s *Store) CreateApplication(application *Application) error {
applicationPath := fmt.Sprintf(fmtApplicationPath, application.Name)
application.Version = schemaVersion
data, err := marshal(application)
if err != nil {
return fmt.Errorf("serializing application %s: %w", application.Name, err)
}
_, err = s.ssm.PutParameter(&ssm.PutParameterInput{
Name: aws.String(applicationPath),
Description: aws.String("Copilot Application"),
Type: aws.String(ssm.ParameterTypeString),
Value: aws.String(data),
Tags: []*ssm.Tag{
{
Key: aws.String("copilot-application"),
Value: aws.String(application.Name),
},
},
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case ssm.ErrCodeParameterAlreadyExists:
return nil
}
}
return fmt.Errorf("create application %s: %w", application.Name, err)
}
return nil
}
// UpdateApplication updates the data in SSM about an application.
func (s *Store) UpdateApplication(application *Application) error {
applicationPath := fmt.Sprintf(fmtApplicationPath, application.Name)
application.Version = schemaVersion
data, err := marshal(application)
if err != nil {
return fmt.Errorf("serializing application %s: %w", application.Name, err)
}
if _, err = s.ssm.PutParameter(&ssm.PutParameterInput{
Name: aws.String(applicationPath),
Description: aws.String("Copilot Application"),
Type: aws.String(ssm.ParameterTypeString),
Value: aws.String(data),
Overwrite: aws.Bool(true),
}); err != nil {
return fmt.Errorf("update application %s: %w", application.Name, err)
}
return nil
}
// GetApplication fetches an application by name. If it can't be found, return a ErrNoSuchApplication
func (s *Store) GetApplication(applicationName string) (*Application, error) {
applicationPath := fmt.Sprintf(fmtApplicationPath, applicationName)
applicationParam, err := s.ssm.GetParameter(&ssm.GetParameterInput{
Name: aws.String(applicationPath),
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case ssm.ErrCodeParameterNotFound:
account, region := s.getCallerAccountAndRegion()
return nil, &ErrNoSuchApplication{
ApplicationName: applicationName,
AccountID: account,
Region: region,
}
}
}
return nil, fmt.Errorf("get application %s: %w", applicationName, err)
}
var application Application
if err := json.Unmarshal([]byte(*applicationParam.Parameter.Value), &application); err != nil {
return nil, fmt.Errorf("read configuration for application %s: %w", applicationName, err)
}
return &application, nil
}
// ListApplications returns the list of existing applications in the customer's account and region.
func (s *Store) ListApplications() ([]*Application, error) {
var applications []*Application
serializedApplications, err := s.listParams(rootApplicationPath)
if err != nil {
return nil, fmt.Errorf("list applications: %w", err)
}
for _, serializedApplication := range serializedApplications {
var application Application
if err := json.Unmarshal([]byte(*serializedApplication), &application); err != nil {
return nil, fmt.Errorf("read application configuration: %w", err)
}
applications = append(applications, &application)
}
return applications, nil
}
// DeleteApplication deletes the SSM parameter related to the application.
func (s *Store) DeleteApplication(name string) error {
paramName := fmt.Sprintf(fmtApplicationPath, name)
_, err := s.ssm.DeleteParameter(&ssm.DeleteParameterInput{
Name: aws.String(paramName),
})
if err != nil {
awserr, ok := err.(awserr.Error)
if !ok {
return err
}
if awserr.Code() == ssm.ErrCodeParameterNotFound {
return nil
}
return fmt.Errorf("delete SSM param %s: %w", paramName, awserr)
}
return nil
}