seira 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|