seira 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/seira/app.rb +9 -4
- data/lib/seira/db/create.rb +327 -0
- data/lib/seira/db.rb +10 -89
- data/lib/seira/secrets.rb +6 -10
- data/lib/seira/settings.rb +4 -0
- data/lib/seira/version.rb +1 -1
- data/lib/seira.rb +5 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 137cf8ac1506f10dac88ef667c49c5f6a30b515b
|
4
|
+
data.tar.gz: f55493c0ddfc6615f0954d9672d78a2399e41bdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d179c9b561dafcf2ecc0162e4c493b488a28e18e62195d8913c2aa2d211f5af805301cc5f8d6dd9f2ec59feae023d36409ce7d0e51b71a7852d140afe636a31
|
7
|
+
data.tar.gz: c31974b1f7b50272779f76f1628ed5aade976fe5c36035314b7774d4e3e3092ad1ba38b750ab8ebb6f1e83ecca6c86eec6f066927770c29e7371f5fbc2a16244
|
data/lib/seira/app.rb
CHANGED
@@ -41,12 +41,12 @@ module Seira
|
|
41
41
|
puts "Possible actions:\n\n"
|
42
42
|
puts "bootstrap: Create new app with main secret, cloudsql secret, and gcr secret in the new namespace."
|
43
43
|
puts "apply: Apply the configuration in kubernetes/<cluster-name>/<app-name> using REVISION environment variable to find/replace REVISION in the YAML."
|
44
|
-
puts "restart:
|
44
|
+
puts "restart: Forces a rolling deploy for any deployment making use of RESTARTED_AT_VALUE in the deployment."
|
45
45
|
puts "scale: Scales the given tier deployment to the specified number of instances."
|
46
46
|
end
|
47
47
|
|
48
48
|
def run_restart
|
49
|
-
|
49
|
+
run_apply(restart: true)
|
50
50
|
end
|
51
51
|
|
52
52
|
private
|
@@ -60,7 +60,7 @@ module Seira
|
|
60
60
|
end
|
61
61
|
|
62
62
|
# Kube vanilla based upgrade
|
63
|
-
def run_apply
|
63
|
+
def run_apply(restart: false)
|
64
64
|
destination = "tmp/#{context[:cluster]}/#{app}"
|
65
65
|
revision = ENV['REVISION']
|
66
66
|
|
@@ -73,6 +73,10 @@ module Seira
|
|
73
73
|
|
74
74
|
replacement_hash = { 'REVISION' => revision }
|
75
75
|
|
76
|
+
if restart
|
77
|
+
replacement_hash['RESTARTED_AT_VALUE'] = Time.now.to_s
|
78
|
+
end
|
79
|
+
|
76
80
|
replacement_hash.each do |k, v|
|
77
81
|
next unless v.nil? || v == ''
|
78
82
|
puts "Found nil or blank value for replacement hash key #{k}. Aborting!"
|
@@ -144,7 +148,8 @@ module Seira
|
|
144
148
|
|
145
149
|
def find_and_replace_revision(source:, destination:, replacement_hash:)
|
146
150
|
puts "Copying source yaml from #{source} to #{destination}"
|
147
|
-
FileUtils
|
151
|
+
FileUtils.mkdir_p destination # Create the nested directory
|
152
|
+
FileUtils.rm_rf("#{destination}/.", secure: true) # Clean out old files from the tmp folder
|
148
153
|
FileUtils.copy_entry source, destination
|
149
154
|
|
150
155
|
# Iterate through each yaml file and find/replace and save
|
@@ -0,0 +1,327 @@
|
|
1
|
+
module Seira
|
2
|
+
class Db
|
3
|
+
class Create
|
4
|
+
attr_reader :app, :action, :args, :context
|
5
|
+
|
6
|
+
attr_reader :name, :version, :cpu, :memory, :storage, :replica_for, :make_highly_available
|
7
|
+
attr_reader :root_password, :proxyuser_password
|
8
|
+
|
9
|
+
def initialize(app:, action:, args:, context:)
|
10
|
+
@app = app
|
11
|
+
@action = action
|
12
|
+
@args = args
|
13
|
+
@context = context
|
14
|
+
|
15
|
+
# We allow overriding the version, so you could specify a mysql version but much of the
|
16
|
+
# below assumes postgres for now
|
17
|
+
@version = 'POSTGRES_9_6'
|
18
|
+
@cpu = 1 # Number of CPUs
|
19
|
+
@memory = 4 # GB
|
20
|
+
@storage = 10 # GB
|
21
|
+
@replica_for = nil
|
22
|
+
@make_highly_available = false
|
23
|
+
|
24
|
+
@root_password = nil
|
25
|
+
@proxyuser_password = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def run(existing_instances)
|
29
|
+
@name = "#{app}-#{Seira::Random.unique_name(existing_instances)}"
|
30
|
+
|
31
|
+
run_create_command
|
32
|
+
|
33
|
+
if replica_for.nil?
|
34
|
+
update_root_password
|
35
|
+
create_proxy_user
|
36
|
+
end
|
37
|
+
|
38
|
+
set_secrets
|
39
|
+
write_pgbouncer_yaml
|
40
|
+
|
41
|
+
puts "To use this database, deploy the pgbouncer config file that was created and use the ENV that was set."
|
42
|
+
puts "To make this database the primary, promote it using the CLI and update the DATABASE_URL."
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def run_create_command
|
48
|
+
# The 'beta' is needed for HA and other beta features
|
49
|
+
create_command = "gcloud beta sql instances create #{name}"
|
50
|
+
|
51
|
+
args.each do |arg|
|
52
|
+
if arg.start_with? '--version='
|
53
|
+
@version = arg.split('=')[1]
|
54
|
+
elsif arg.start_with? '--cpu='
|
55
|
+
@cpu = arg.split('=')[1]
|
56
|
+
elsif arg.start_with? '--memory='
|
57
|
+
@memory = arg.split('=')[1]
|
58
|
+
elsif arg.start_with? '--storage='
|
59
|
+
@storage = arg.split('=')[1]
|
60
|
+
elsif arg.start_with? '--primary='
|
61
|
+
@replica_for = arg.split('=')[1] # TODO: Read secret to get it automatically
|
62
|
+
elsif arg.start_with? '--highly-available'
|
63
|
+
@make_highly_available = true
|
64
|
+
elsif /^--[\w\-]+=.+$/.match? arg
|
65
|
+
create_command += " #{arg}"
|
66
|
+
else
|
67
|
+
puts "Warning: Unrecognized argument '#{arg}'"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if make_highly_available && !replica_for.nil?
|
72
|
+
puts "Cannot create an HA read-replica."
|
73
|
+
exit(1)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Basic configs
|
77
|
+
create_command += " --database-version=#{version}"
|
78
|
+
|
79
|
+
# A read replica cannot have HA, inherits the cpu, mem and storage of its primary
|
80
|
+
if replica_for.nil?
|
81
|
+
# Make sure to do automated daily backups by default, unless it's a replica
|
82
|
+
create_command += " --backup"
|
83
|
+
create_command += " --cpu=#{cpu}"
|
84
|
+
create_command += " --memory=#{memory}"
|
85
|
+
create_command += " --storage-size=#{storage}"
|
86
|
+
|
87
|
+
# Make HA if asked for
|
88
|
+
create_command += " --availability-type=REGIONAL" if make_highly_available
|
89
|
+
else
|
90
|
+
create_command += " --master-instance-name=#{replica_for}"
|
91
|
+
# We don't need to wait for it to finish to move ahead if it's a replica, as we don't
|
92
|
+
# make any changes to the database itself
|
93
|
+
create_command += " --async"
|
94
|
+
end
|
95
|
+
|
96
|
+
puts "Running: #{create_command}"
|
97
|
+
|
98
|
+
# Create the sql instance with the specified/default parameters
|
99
|
+
if system(create_command)
|
100
|
+
async_additional =
|
101
|
+
unless replica_for.nil?
|
102
|
+
". Database is still being created and may take some time to be available."
|
103
|
+
end
|
104
|
+
|
105
|
+
puts "Successfully created sql instance #{name}#{async_additional}"
|
106
|
+
else
|
107
|
+
puts "Failed to create sql instance"
|
108
|
+
exit(1)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def update_root_password
|
113
|
+
# Set the root user's password to something secure
|
114
|
+
@root_password = SecureRandom.urlsafe_base64(32)
|
115
|
+
|
116
|
+
if system("gcloud sql users set-password postgres '' --instance=#{name} --password=#{root_password}")
|
117
|
+
puts "Set root password to #{root_password}"
|
118
|
+
else
|
119
|
+
puts "Failed to set root password"
|
120
|
+
exit(1)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_proxy_user
|
125
|
+
# Create proxyuser with secure password
|
126
|
+
@proxyuser_password = SecureRandom.urlsafe_base64(32)
|
127
|
+
|
128
|
+
if system("gcloud sql users create proxyuser '' --instance=#{name} --password=#{proxyuser_password}")
|
129
|
+
puts "Created proxyuser with password #{proxyuser_password}"
|
130
|
+
else
|
131
|
+
puts "Failed to create proxyuser"
|
132
|
+
exit(1)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Connect to the instance and remove some of the default group memberships and permissions
|
136
|
+
# from proxyuser, leaving it with only what it needs to be able to do
|
137
|
+
expect_script = <<~BASH
|
138
|
+
set timeout 90
|
139
|
+
spawn gcloud sql connect #{name}
|
140
|
+
expect "Password for user postgres:"
|
141
|
+
send "#{root_password}\\r"
|
142
|
+
expect "postgres=>"
|
143
|
+
send "ALTER ROLE proxyuser NOCREATEDB NOCREATEROLE;\\r"
|
144
|
+
expect "postgres=>"
|
145
|
+
BASH
|
146
|
+
if system("expect <<EOF\n#{expect_script}EOF")
|
147
|
+
puts "Successfully removed unnecessary permissions from proxyuser"
|
148
|
+
else
|
149
|
+
puts "Failed to remove unnecessary permissions from proxyuser"
|
150
|
+
exit(1)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def set_secrets
|
155
|
+
env_name = name.tr('-', '_').upcase
|
156
|
+
|
157
|
+
# If setting as primary, update relevant secrets. Only primaries have root passwords.
|
158
|
+
if replica_for.nil?
|
159
|
+
create_pgbouncer_secret(db_user: 'proxyuser', db_password: proxyuser_password)
|
160
|
+
Secrets.new(app: app, action: 'set', args: ["#{env_name}_ROOT_PASSWORD=#{root_password}"], context: context).run
|
161
|
+
write_database_env(key: "DATABASE_URL", db_user: 'proxyuser', db_password: proxyuser_password)
|
162
|
+
write_database_env(key: "#{env_name}_DB_URL", db_user: 'proxyuser', db_password: proxyuser_password)
|
163
|
+
else
|
164
|
+
# When creating a replica, we cannot manage users on the replica. We must manage the users on the primary, which the replica
|
165
|
+
# inherits. For now we will use the same credentials that the primary uses.
|
166
|
+
primary_uri = URI.parse(Secrets.new(app: app, action: 'get', args: [], context: context).get('DATABASE_URL'))
|
167
|
+
primary_user = primary_uri.user
|
168
|
+
primary_password = primary_uri.password
|
169
|
+
create_pgbouncer_secret(db_user: primary_user, db_password: primary_password)
|
170
|
+
write_database_env(key: "#{env_name}_DB_URL", db_user: primary_user, db_password: primary_password)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def create_pgbouncer_secret(db_user:, db_password:)
|
175
|
+
puts `kubectl create secret generic #{pgbouncer_secret_name} --namespace #{app} --from-literal=DB_USER=#{db_user} --from-literal=DB_PASSWORD=#{db_password}`
|
176
|
+
end
|
177
|
+
|
178
|
+
def write_database_env(key:, db_user:, db_password:)
|
179
|
+
Secrets.new(app: app, action: 'set', args: ["#{key}=postgres://#{db_user}:#{db_password}@#{pgbouncer_service_name}:6432"], context: context).run
|
180
|
+
end
|
181
|
+
|
182
|
+
def pgbouncer_secret_name
|
183
|
+
"#{name}-pgbouncer-secrets"
|
184
|
+
end
|
185
|
+
|
186
|
+
def pgbouncer_configs_name
|
187
|
+
"#{name}-pgbouncer-configs"
|
188
|
+
end
|
189
|
+
|
190
|
+
def pgbouncer_service_name
|
191
|
+
"#{name}-pgbouncer-service"
|
192
|
+
end
|
193
|
+
|
194
|
+
def pgbouncer_tier
|
195
|
+
name.gsub("handshake-", "")
|
196
|
+
end
|
197
|
+
|
198
|
+
def write_pgbouncer_yaml
|
199
|
+
# TODO: Clean this up by moving into a proper templated yaml file
|
200
|
+
pgbouncer_yaml = <<-FOO
|
201
|
+
---
|
202
|
+
apiVersion: v1
|
203
|
+
kind: ConfigMap
|
204
|
+
metadata:
|
205
|
+
name: #{pgbouncer_configs_name}
|
206
|
+
namespace: #{app}
|
207
|
+
data:
|
208
|
+
DB_HOST: "127.0.0.1"
|
209
|
+
DB_PORT: "5432"
|
210
|
+
LISTEN_PORT: "6432"
|
211
|
+
LISTEN_ADDRESS: "*"
|
212
|
+
TCP_KEEPALIVE: "1"
|
213
|
+
TCP_KEEPCNT: "5"
|
214
|
+
TCP_KEEPIDLE: "300" # see: https://git.io/vi0Aj
|
215
|
+
TCP_KEEPINTVL: "300"
|
216
|
+
LOG_DISCONNECTIONS: "0" # spammy, not needed
|
217
|
+
MAX_CLIENT_CONN: "500"
|
218
|
+
MAX_DB_CONNECTIONS: "90"
|
219
|
+
DEFAULT_POOL_SIZE: "90"
|
220
|
+
POOL_MODE: "transaction"
|
221
|
+
---
|
222
|
+
apiVersion: extensions/v1beta1
|
223
|
+
kind: Deployment
|
224
|
+
metadata:
|
225
|
+
name: #{name}-pgbouncer
|
226
|
+
namespace: #{app}
|
227
|
+
labels:
|
228
|
+
app: #{app}
|
229
|
+
tier: #{pgbouncer_tier}
|
230
|
+
database: #{name}
|
231
|
+
spec:
|
232
|
+
replicas: 1
|
233
|
+
minReadySeconds: 20
|
234
|
+
strategy:
|
235
|
+
type: RollingUpdate
|
236
|
+
rollingUpdate:
|
237
|
+
maxSurge: 1
|
238
|
+
maxUnavailable: 1
|
239
|
+
template:
|
240
|
+
metadata:
|
241
|
+
labels:
|
242
|
+
app: #{app}
|
243
|
+
tier: #{pgbouncer_tier}
|
244
|
+
database: #{name}
|
245
|
+
spec:
|
246
|
+
containers:
|
247
|
+
- image: handshake/pgbouncer:0.1.2
|
248
|
+
name: pgbouncer
|
249
|
+
ports:
|
250
|
+
- containerPort: 6432
|
251
|
+
protocol: TCP
|
252
|
+
envFrom:
|
253
|
+
- configMapRef:
|
254
|
+
name: #{pgbouncer_configs_name}
|
255
|
+
- secretRef:
|
256
|
+
name: #{pgbouncer_secret_name}
|
257
|
+
readinessProbe:
|
258
|
+
tcpSocket:
|
259
|
+
port: 6432
|
260
|
+
initialDelaySeconds: 5
|
261
|
+
periodSeconds: 10
|
262
|
+
livenessProbe:
|
263
|
+
tcpSocket:
|
264
|
+
port: 6432
|
265
|
+
initialDelaySeconds: 15
|
266
|
+
periodSeconds: 20
|
267
|
+
resources:
|
268
|
+
requests:
|
269
|
+
cpu: 100m
|
270
|
+
memory: 300m
|
271
|
+
- image: gcr.io/cloudsql-docker/gce-proxy:1.11 # Gcloud SQL Proxy
|
272
|
+
name: cloudsql-proxy
|
273
|
+
command:
|
274
|
+
- /cloud_sql_proxy
|
275
|
+
- --dir=/cloudsql
|
276
|
+
- -instances=#{context[:project]}:#{context[:default_zone]}:#{name}=tcp:5432
|
277
|
+
- -credential_file=/secrets/cloudsql/credentials.json
|
278
|
+
ports:
|
279
|
+
- containerPort: 5432
|
280
|
+
protocol: TCP
|
281
|
+
envFrom:
|
282
|
+
- configMapRef:
|
283
|
+
name: cloudsql-configs
|
284
|
+
volumeMounts:
|
285
|
+
- name: cloudsql-credentials
|
286
|
+
mountPath: /secrets/cloudsql
|
287
|
+
readOnly: true
|
288
|
+
- name: ssl-certs
|
289
|
+
mountPath: /etc/ssl/certs
|
290
|
+
- name: cloudsql
|
291
|
+
mountPath: /cloudsql
|
292
|
+
volumes:
|
293
|
+
- name: cloudsql-credentials
|
294
|
+
secret:
|
295
|
+
secretName: cloudsql-credentials
|
296
|
+
- name: cloudsql
|
297
|
+
emptyDir:
|
298
|
+
- name: ssl-certs
|
299
|
+
hostPath:
|
300
|
+
path: /etc/ssl/certs
|
301
|
+
---
|
302
|
+
apiVersion: v1
|
303
|
+
kind: Service
|
304
|
+
metadata:
|
305
|
+
name: #{pgbouncer_service_name}
|
306
|
+
namespace: #{app}
|
307
|
+
labels:
|
308
|
+
app: #{app}
|
309
|
+
tier: #{pgbouncer_tier}
|
310
|
+
spec:
|
311
|
+
type: NodePort
|
312
|
+
ports:
|
313
|
+
- protocol: TCP
|
314
|
+
port: 6432
|
315
|
+
targetPort: 6432
|
316
|
+
nodePort: 0
|
317
|
+
selector:
|
318
|
+
app: #{app}
|
319
|
+
tier: #{pgbouncer_tier}
|
320
|
+
database: #{name}
|
321
|
+
FOO
|
322
|
+
|
323
|
+
File.write("kubernetes/#{context[:cluster]}/#{app}/pgbouncer-#{name.gsub("#{app}-", '')}.yaml", pgbouncer_yaml)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
data/lib/seira/db.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'securerandom'
|
2
2
|
|
3
|
+
require_relative 'db/create.rb'
|
4
|
+
|
3
5
|
module Seira
|
4
6
|
class Db
|
5
7
|
VALID_ACTIONS = %w[help create delete list].freeze
|
@@ -33,104 +35,23 @@ module Seira
|
|
33
35
|
|
34
36
|
def run_help
|
35
37
|
puts SUMMARY
|
36
|
-
puts "\n
|
37
|
-
puts "
|
38
|
+
puts "\n"
|
39
|
+
puts "create: Create a new postgres instance in cloud sql. Supports creating replicas and other numerous flags."
|
40
|
+
puts "delete: Delete a postgres instance from cloud sql. Use with caution, and remove all kubernetes configs first."
|
41
|
+
puts "list: List all postgres instances."
|
38
42
|
end
|
39
43
|
|
40
44
|
def run_create
|
41
|
-
|
42
|
-
# below assumes postgres for now
|
43
|
-
version = 'POSTGRES_9_6'
|
44
|
-
cpu = 1 # Number of CPUs
|
45
|
-
memory = 4 # GB
|
46
|
-
storage = 10 # GB
|
47
|
-
set_as_primary = false
|
48
|
-
|
49
|
-
name = "#{app}-#{Seira::Random.unique_name(existing_instances)}"
|
50
|
-
|
51
|
-
create_command = "gcloud sql instances create #{name}"
|
52
|
-
|
53
|
-
args.each do |arg|
|
54
|
-
if arg.start_with? '--version='
|
55
|
-
version = arg.split('=')[1]
|
56
|
-
elsif arg.start_with? '--cpu='
|
57
|
-
cpu = arg.split('=')[1]
|
58
|
-
elsif arg.start_with? '--memory='
|
59
|
-
memory = arg.split('=')[1]
|
60
|
-
elsif arg.start_with? '--storage='
|
61
|
-
storage = arg.split('=')[1]
|
62
|
-
elsif arg.start_with? '--set-as-primary='
|
63
|
-
set_as_primary = %w[true yes t y].include?(arg.split('=')[1])
|
64
|
-
elsif /^--[\w\-]+=.+$/.match? arg
|
65
|
-
create_command += " #{arg}"
|
66
|
-
else
|
67
|
-
puts "Warning: Unrecognized argument '#{arg}'"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
create_command += " --database-version=#{version}"
|
72
|
-
create_command += " --cpu=#{cpu}"
|
73
|
-
create_command += " --memory=#{memory}"
|
74
|
-
create_command += " --storage-size=#{storage}"
|
75
|
-
|
76
|
-
# Create the sql instance with the specified/default parameters
|
77
|
-
if system(create_command)
|
78
|
-
puts "Successfully created sql instance #{name}"
|
79
|
-
else
|
80
|
-
puts "Failed to create sql instance"
|
81
|
-
exit(1)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Set the root user's password to something secure
|
85
|
-
root_password = SecureRandom.urlsafe_base64(32)
|
86
|
-
if system("gcloud sql users set-password postgres '' --instance=#{name} --password=#{root_password}")
|
87
|
-
puts "Set root password to #{root_password}"
|
88
|
-
else
|
89
|
-
puts "Failed to set root password"
|
90
|
-
exit(1)
|
91
|
-
end
|
92
|
-
|
93
|
-
# Create proxyuser with secure password
|
94
|
-
proxyuser_password = SecureRandom.urlsafe_base64(32)
|
95
|
-
if system("gcloud sql users create proxyuser '' --instance=#{name} --password=#{proxyuser_password}")
|
96
|
-
puts "Created proxyuser with password #{proxyuser_password}"
|
97
|
-
else
|
98
|
-
puts "Failed to create proxyuser"
|
99
|
-
exit(1)
|
100
|
-
end
|
101
|
-
|
102
|
-
# Connect to the instance and remove some of the default group memberships and permissions
|
103
|
-
# from proxyuser, leaving it with only what it needs to be able to do
|
104
|
-
expect_script = <<~BASH
|
105
|
-
set timeout 90
|
106
|
-
spawn gcloud sql connect #{name}
|
107
|
-
expect "Password for user postgres:"
|
108
|
-
send "#{root_password}\\r"
|
109
|
-
expect "postgres=>"
|
110
|
-
send "ALTER ROLE proxyuser NOCREATEDB NOCREATEROLE;\\r"
|
111
|
-
expect "postgres=>"
|
112
|
-
BASH
|
113
|
-
if system("expect <<EOF\n#{expect_script}EOF")
|
114
|
-
puts "Successfully removed unnecessary permissions from proxyuser"
|
115
|
-
else
|
116
|
-
puts "Failed to remove unnecessary permissions from proxyuser"
|
117
|
-
exit(1)
|
118
|
-
end
|
119
|
-
|
120
|
-
# If setting as primary, update relevant secrets
|
121
|
-
if set_as_primary
|
122
|
-
Secrets.new(app: app, action: 'create-pgbouncer-secret', args: ['proxyuser', proxyuser_password], context: context).run
|
123
|
-
Secrets.new(app: app, action: 'set', args: ["DATABASE_URL=postgres://proxyuser:#{proxyuser_password}@#{app}-pgbouncer-service:6432"], context: context).run
|
124
|
-
end
|
125
|
-
# Regardless of primary or not, store a URL for this db matching its unique name
|
126
|
-
env_name = name.tr('-', '_').upcase
|
127
|
-
Secrets.new(app: app, action: 'set', args: ["#{env_name}_DB_URL=postgres://proxyuser:#{proxyuser_password}@#{app}-pgbouncer-service:6432", "#{env_name}_ROOT_PASSWORD=#{root_password}"], context: context).run
|
45
|
+
Seira::Db::Create.new(app: app, action: action, args: args, context: context).run(existing_instances)
|
128
46
|
end
|
129
47
|
|
130
48
|
def run_delete
|
131
49
|
name = "#{app}-#{args[0]}"
|
132
50
|
if system("gcloud sql instances delete #{name}")
|
133
51
|
puts "Successfully deleted sql instance #{name}"
|
52
|
+
|
53
|
+
# TODO: Automate the below
|
54
|
+
puts "Don't forget to delete the deployment, configmap, secret, and service for the pgbouncer instance."
|
134
55
|
else
|
135
56
|
puts "Failed to delete sql instance #{name}"
|
136
57
|
end
|
data/lib/seira/secrets.rb
CHANGED
@@ -38,8 +38,6 @@ module Seira
|
|
38
38
|
run_list
|
39
39
|
when 'list-decoded'
|
40
40
|
run_list_decoded
|
41
|
-
when 'create-pgbouncer-secret'
|
42
|
-
run_create_pgbouncer_secret
|
43
41
|
else
|
44
42
|
fail "Unknown command encountered"
|
45
43
|
end
|
@@ -65,6 +63,11 @@ module Seira
|
|
65
63
|
"#{app}-secrets"
|
66
64
|
end
|
67
65
|
|
66
|
+
def get(key)
|
67
|
+
secrets = fetch_current_secrets
|
68
|
+
Base64.decode64(secrets['data'][key])
|
69
|
+
end
|
70
|
+
|
68
71
|
private
|
69
72
|
|
70
73
|
def run_help
|
@@ -88,8 +91,7 @@ module Seira
|
|
88
91
|
end
|
89
92
|
|
90
93
|
def run_get
|
91
|
-
|
92
|
-
puts "#{key}: #{Base64.decode64(secrets['data'][key])}"
|
94
|
+
puts "#{key}: #{get(key)}"
|
93
95
|
end
|
94
96
|
|
95
97
|
def run_set
|
@@ -120,12 +122,6 @@ module Seira
|
|
120
122
|
end
|
121
123
|
end
|
122
124
|
|
123
|
-
def run_create_pgbouncer_secret
|
124
|
-
db_user = args[0]
|
125
|
-
db_password = args[1]
|
126
|
-
puts `kubectl create secret generic #{PGBOUNCER_SECRETS_NAME} --namespace #{app} --from-literal=DB_USER=#{db_user} --from-literal=DB_PASSWORD=#{db_password}`
|
127
|
-
end
|
128
|
-
|
129
125
|
# In the normal case the secret we are updating is just main_secret_name,
|
130
126
|
# but in special cases we may be doing an operation on a different secret
|
131
127
|
def write_secrets(secrets:, secret_name: main_secret_name)
|
data/lib/seira/settings.rb
CHANGED
data/lib/seira/version.rb
CHANGED
data/lib/seira.rb
CHANGED
@@ -30,7 +30,7 @@ module Seira
|
|
30
30
|
'setup' => Seira::Setup
|
31
31
|
}.freeze
|
32
32
|
|
33
|
-
attr_reader :cluster, :app, :category, :action, :args
|
33
|
+
attr_reader :project, :cluster, :app, :category, :action, :args
|
34
34
|
attr_reader :settings
|
35
35
|
|
36
36
|
# Pop from beginning repeatedly for the first 4 main args, and then take the remaining back to original order for
|
@@ -64,6 +64,7 @@ module Seira
|
|
64
64
|
end
|
65
65
|
|
66
66
|
@cluster = @settings.full_cluster_name_for_shorthand(cluster)
|
67
|
+
@project = @settings.project_for_cluster(@cluster)
|
67
68
|
end
|
68
69
|
|
69
70
|
def run
|
@@ -100,7 +101,9 @@ module Seira
|
|
100
101
|
|
101
102
|
def passed_context
|
102
103
|
{
|
103
|
-
cluster: cluster
|
104
|
+
cluster: cluster,
|
105
|
+
project: project,
|
106
|
+
default_zone: settings.default_zone
|
104
107
|
}
|
105
108
|
end
|
106
109
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: seira
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Ringwelski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-12-
|
11
|
+
date: 2017-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- lib/seira/app.rb
|
107
107
|
- lib/seira/cluster.rb
|
108
108
|
- lib/seira/db.rb
|
109
|
+
- lib/seira/db/create.rb
|
109
110
|
- lib/seira/memcached.rb
|
110
111
|
- lib/seira/pods.rb
|
111
112
|
- lib/seira/proxy.rb
|