This repository has been archived by the owner on Jan 30, 2019. It is now read-only.
/
configuration.go
181 lines (150 loc) · 5.23 KB
/
configuration.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package soapboxd
import (
"database/sql"
"time"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/adhocteam/soapbox/proto"
gpb "github.com/golang/protobuf/ptypes/timestamp"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
func (s *Server) ListConfigurations(ctx context.Context, req *proto.ListConfigurationRequest) (*proto.ListConfigurationResponse, error) {
// TODO(paulsmith): maybe embed actual config vars in response payload
query := `SELECT version, created_at FROM configurations WHERE environment_id = $1`
var configs []*proto.Configuration
envID := req.GetEnvironmentId()
rows, err := s.db.Query(query, envID)
if err != nil {
return nil, errors.Wrap(err, "querying configurations table")
}
for rows.Next() {
c := &proto.Configuration{
EnvironmentId: envID,
}
var createdAt time.Time
if err := rows.Scan(&c.Version, &createdAt); err != nil {
return nil, errors.Wrap(err, "scanning db row")
}
setPbTimestamp(c.CreatedAt, createdAt)
configs = append(configs, c)
}
if err := rows.Err(); err != nil {
return nil, errors.Wrap(err, "db iteration")
}
resp := &proto.ListConfigurationResponse{
Configs: configs,
}
return resp, nil
}
func (s *Server) GetLatestConfiguration(ctx context.Context, req *proto.GetLatestConfigurationRequest) (*proto.Configuration, error) {
// TODO(paulsmith): FIXME return error or message with error
// semantics if we get nothing back from the db, instead of
// returning a zero-value configuration (in the case where an
// environment doesn't have any configurations)
query := `
SELECT version, created_at
FROM configurations
WHERE environment_id = $1
ORDER BY version DESC
LIMIT 1
`
config := &proto.Configuration{
CreatedAt: new(gpb.Timestamp),
}
envID := req.GetEnvironmentId()
var createdAt time.Time
if err := s.db.QueryRow(query, envID).Scan(&config.Version, &createdAt); err != nil {
if err == sql.ErrNoRows {
return nil, status.Error(codes.NotFound, "no configuration found for environment")
}
return nil, errors.Wrap(err, "querying configurations table")
}
setPbTimestamp(config.CreatedAt, createdAt)
appSlug, envSlug, err := s.getSlugs(ctx, envID)
if err != nil {
return nil, errors.Wrap(err, "getting env and app slugs")
}
config.ConfigVars, err = s.configurationStore.GetConfigVars(appSlug, envSlug, config.Version)
if err != nil {
return nil, errors.Wrap(err, "getting config variables")
}
return config, nil
}
func (s *Server) CreateConfiguration(ctx context.Context, req *proto.CreateConfigurationRequest) (*proto.Configuration, error) {
envID := req.GetEnvironmentId()
tx, err := s.db.Begin()
if err != nil {
return nil, errors.Wrap(err, "beginning transaction")
}
defer tx.Rollback()
config := &proto.Configuration{
EnvironmentId: envID,
ConfigVars: req.ConfigVars,
CreatedAt: new(gpb.Timestamp),
}
configQuery := `
INSERT INTO configurations (environment_id)
VALUES ($1)
RETURNING created_at, version`
var createdAt time.Time
if err := tx.QueryRow(configQuery, envID).Scan(&createdAt, &config.Version); err != nil {
return nil, errors.Wrap(err, "inserting into configurations table")
}
setPbTimestamp(config.CreatedAt, createdAt)
env, err := s.GetEnvironment(ctx, &proto.GetEnvironmentRequest{Id: envID})
if err != nil {
return nil, errors.Wrap(err, "getting environment")
}
app, err := s.GetApplication(ctx, &proto.GetApplicationRequest{Id: env.GetApplicationId()})
if err != nil {
return nil, errors.Wrap(err, "getting application")
}
kmsKeyARN := app.GetAwsEncryptionKeyArn()
appSlug := app.GetSlug()
envSlug := env.GetSlug()
err = s.configurationStore.SaveConfigVars(appSlug, envSlug, config.Version, config.ConfigVars, kmsKeyARN)
if err != nil {
return nil, errors.Wrap(err, "saving config variables")
}
if err := tx.Commit(); err != nil {
return nil, errors.Wrap(err, "committing transaction")
}
return config, nil
}
func (s *Server) DeleteConfiguration(ctx context.Context, req *proto.DeleteConfigurationRequest) (*proto.Empty, error) {
envID := req.GetEnvironmentId()
version := req.GetVersion()
tx, err := s.db.Begin()
if err != nil {
return nil, errors.Wrap(err, "beginning transaction")
}
defer tx.Rollback()
query := `DELETE FROM configurations WHERE environment_id = $1 AND version = $2`
if _, err := tx.Exec(query, envID, version); err != nil {
return nil, errors.Wrap(err, "deleting configuration from local database")
}
appSlug, envSlug, err := s.getSlugs(ctx, envID)
if err != nil {
return nil, errors.Wrap(err, "getting env and app slugs")
}
err = s.configurationStore.DeleteConfigVars(appSlug, envSlug, version)
if err != nil {
return nil, errors.Wrap(err, "deleting config variables")
}
if err := tx.Commit(); err != nil {
return nil, errors.Wrap(err, "committing transaction")
}
return &proto.Empty{}, nil
}
func (s *Server) getSlugs(ctx context.Context, envID int32) (string, string, error) {
env, err := s.GetEnvironment(ctx, &proto.GetEnvironmentRequest{Id: envID})
if err != nil {
return "", "", errors.Wrap(err, "getting environment")
}
app, err := s.GetApplication(ctx, &proto.GetApplicationRequest{Id: env.GetApplicationId()})
if err != nil {
return "", "", errors.Wrap(err, "getting application")
}
return app.GetSlug(), env.GetSlug(), nil
}