seira 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/helpers.rb +5 -0
- data/lib/seira.rb +11 -2
- data/lib/seira/db.rb +93 -1
- data/lib/seira/db/create.rb +3 -4
- data/lib/seira/pods.rb +2 -7
- data/lib/seira/setup.rb +4 -16
- data/lib/seira/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d89537c56c0c2a5fc49a16238d2b063e55806d7
|
4
|
+
data.tar.gz: 3f4231dd7aa7ea3717d146f49c751068992a957f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2068e219e27356551e61d964806ab43ec229dc5b6f6b2aee665495c5d27a3006664e08dc0f4640c0058d0d21a134e7c08f24d64e45a95fa95f9b70d3a8cb3bb3
|
7
|
+
data.tar.gz: 95678bb5225c5065bf3a9cfcf67a81950e835aa9d95f2c2cd8cc7ba537d4624466cb28534d476b679d9a4e00665e4991c053a7076eb75dbb4e55a9d8447f8e7c
|
data/lib/helpers.rb
CHANGED
@@ -8,6 +8,11 @@ module Seira
|
|
8
8
|
context[:cluster]
|
9
9
|
end
|
10
10
|
end
|
11
|
+
|
12
|
+
def fetch_pods(filters:, app:)
|
13
|
+
filter_string = { app: app }.merge(filters).map { |k, v| "#{k}=#{v}" }.join(',')
|
14
|
+
JSON.parse(`kubectl get pods --namespace=#{app} -o json --selector=#{filter_string}`)['items']
|
15
|
+
end
|
11
16
|
end
|
12
17
|
end
|
13
18
|
end
|
data/lib/seira.rb
CHANGED
@@ -4,6 +4,7 @@ require 'colorize'
|
|
4
4
|
require 'tmpdir'
|
5
5
|
|
6
6
|
require "seira/version"
|
7
|
+
require 'helpers'
|
7
8
|
require 'seira/app'
|
8
9
|
require 'seira/cluster'
|
9
10
|
require 'seira/memcached'
|
@@ -67,8 +68,16 @@ module Seira
|
|
67
68
|
@args = reversed_args.reverse
|
68
69
|
end
|
69
70
|
|
70
|
-
@cluster =
|
71
|
-
|
71
|
+
@cluster =
|
72
|
+
if category == 'setup' && cluster == 'all'
|
73
|
+
cluster
|
74
|
+
else
|
75
|
+
@settings.full_cluster_name_for_shorthand(cluster)
|
76
|
+
end
|
77
|
+
|
78
|
+
unless category == 'setup' && cluster == 'all'
|
79
|
+
@project = @settings.project_for_cluster(@cluster)
|
80
|
+
end
|
72
81
|
end
|
73
82
|
|
74
83
|
def run
|
data/lib/seira/db.rb
CHANGED
@@ -4,7 +4,7 @@ require_relative 'db/create'
|
|
4
4
|
|
5
5
|
module Seira
|
6
6
|
class Db
|
7
|
-
VALID_ACTIONS = %w[help create delete list restart connect].freeze
|
7
|
+
VALID_ACTIONS = %w[help create delete list restart connect ps kill analyze].freeze
|
8
8
|
SUMMARY = "Manage your Cloud SQL Postgres databases.".freeze
|
9
9
|
|
10
10
|
attr_reader :app, :action, :args, :context
|
@@ -30,6 +30,12 @@ module Seira
|
|
30
30
|
run_restart
|
31
31
|
when 'connect'
|
32
32
|
run_connect
|
33
|
+
when 'ps'
|
34
|
+
run_ps
|
35
|
+
when 'kill'
|
36
|
+
run_kill
|
37
|
+
when 'analyze'
|
38
|
+
run_analyze
|
33
39
|
else
|
34
40
|
fail "Unknown command encountered"
|
35
41
|
end
|
@@ -57,6 +63,9 @@ module Seira
|
|
57
63
|
puts "list: List all postgres instances."
|
58
64
|
puts "restart: Fully restart the database."
|
59
65
|
puts "connect: Open a psql command prompt. You will be shown the password needed before the prompt opens."
|
66
|
+
puts "ps: List running queries"
|
67
|
+
puts "kill: Kill a query"
|
68
|
+
puts "analyze: Display database performance information"
|
60
69
|
end
|
61
70
|
|
62
71
|
def run_create
|
@@ -96,6 +105,89 @@ module Seira
|
|
96
105
|
system("gcloud sql connect #{name}")
|
97
106
|
end
|
98
107
|
|
108
|
+
def run_ps
|
109
|
+
verbose = false
|
110
|
+
args.each do |arg|
|
111
|
+
if %w[--verbose -v].include? arg
|
112
|
+
verbose = true
|
113
|
+
else
|
114
|
+
puts "Warning: unrecognized argument #{arg}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
execute_db_command(<<~SQL
|
119
|
+
SELECT
|
120
|
+
pid,
|
121
|
+
state,
|
122
|
+
application_name AS source,
|
123
|
+
age(now(),query_start) AS running_for,
|
124
|
+
query_start,
|
125
|
+
wait_event IS NOT NULL AS waiting,
|
126
|
+
query
|
127
|
+
FROM pg_stat_activity
|
128
|
+
WHERE
|
129
|
+
query <> '<insufficient privilege>'
|
130
|
+
#{verbose ? '' : "AND state <> 'idle'"}
|
131
|
+
AND pid <> pg_backend_pid()
|
132
|
+
ORDER BY query_start DESC
|
133
|
+
SQL
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
def run_kill
|
138
|
+
force = false
|
139
|
+
pid = nil
|
140
|
+
|
141
|
+
args.each do |arg|
|
142
|
+
if %w[--force -f].include? arg
|
143
|
+
force = true
|
144
|
+
elsif /^\d+$/.match? arg
|
145
|
+
if pid.nil?
|
146
|
+
pid = arg
|
147
|
+
else
|
148
|
+
puts 'Must specify only one PID'
|
149
|
+
exit 1
|
150
|
+
end
|
151
|
+
else
|
152
|
+
puts "Warning: unrecognized argument #{arg}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
execute_db_command("SELECT #{force ? 'pg_terminate_backend' : 'pg_cancel_backend'}(#{pid})")
|
157
|
+
end
|
158
|
+
|
159
|
+
def run_analyze
|
160
|
+
puts 'Cache Hit Rates'.bold
|
161
|
+
execute_db_command(
|
162
|
+
<<~SQL
|
163
|
+
SELECT sum(heap_blks_read) as heap_read, sum(heap_blks_hit) as heap_hit, (sum(heap_blks_hit) - sum(heap_blks_read)) / sum(heap_blks_hit) as ratio
|
164
|
+
FROM pg_statio_user_tables;
|
165
|
+
SQL
|
166
|
+
)
|
167
|
+
|
168
|
+
puts 'Index Usage Rates'.bold
|
169
|
+
execute_db_command(
|
170
|
+
<<~SQL
|
171
|
+
SELECT relname, 100 * idx_scan / (seq_scan + idx_scan) percent_of_times_index_used, n_live_tup rows_in_table
|
172
|
+
FROM pg_stat_user_tables
|
173
|
+
WHERE (seq_scan + idx_scan) > 0
|
174
|
+
ORDER BY n_live_tup DESC;
|
175
|
+
SQL
|
176
|
+
)
|
177
|
+
end
|
178
|
+
|
179
|
+
def execute_db_command(sql_command)
|
180
|
+
# TODO(josh): move pgbouncer naming logic here and in Create to a common location
|
181
|
+
tier = primary_instance.gsub("#{app}-", '')
|
182
|
+
matching_pods = Helpers.fetch_pods(app: app, filters: { tier: tier })
|
183
|
+
if matching_pods.empty?
|
184
|
+
puts 'Could not find pgbouncer pod to connect to'
|
185
|
+
exit 1
|
186
|
+
end
|
187
|
+
pod_name = matching_pods.first['metadata']['name']
|
188
|
+
exit 1 unless system("kubectl exec #{pod_name} --namespace #{app} -- psql -c \"#{sql_command}\"")
|
189
|
+
end
|
190
|
+
|
99
191
|
def existing_instances
|
100
192
|
`gcloud sql instances list --uri`.split("\n").map { |uri| uri.split('/').last }.select { |name| name.start_with? "#{app}-" }.map { |name| name.gsub(/^#{app}-/, '') }
|
101
193
|
end
|
data/lib/seira/db/create.rb
CHANGED
@@ -194,7 +194,7 @@ module Seira
|
|
194
194
|
end
|
195
195
|
|
196
196
|
def pgbouncer_tier
|
197
|
-
name.gsub("
|
197
|
+
name.gsub("#{app}-", "")
|
198
198
|
end
|
199
199
|
|
200
200
|
def default_database_name
|
@@ -203,6 +203,8 @@ module Seira
|
|
203
203
|
|
204
204
|
def write_pgbouncer_yaml
|
205
205
|
# TODO: Clean this up by moving into a proper templated yaml file
|
206
|
+
# TODO: Fix warning from cloudsql-proxy. We use context[:default_zone] for the DB Instance name
|
207
|
+
# which causes this error: got region "us-central1-c", want "us-central1".
|
206
208
|
pgbouncer_yaml = <<-FOO
|
207
209
|
---
|
208
210
|
apiVersion: v1
|
@@ -289,9 +291,6 @@ spec:
|
|
289
291
|
ports:
|
290
292
|
- containerPort: 5432
|
291
293
|
protocol: TCP
|
292
|
-
envFrom:
|
293
|
-
- configMapRef:
|
294
|
-
name: cloudsql-configs
|
295
294
|
volumeMounts:
|
296
295
|
- name: cloudsql-credentials
|
297
296
|
mountPath: /secrets/cloudsql
|
data/lib/seira/pods.rb
CHANGED
@@ -62,7 +62,7 @@ module Seira
|
|
62
62
|
|
63
63
|
def run_connect
|
64
64
|
# If a pod name is specified, connect to that pod; otherwise pick a random web pod
|
65
|
-
target_pod_name = pod_name || fetch_pods(app: app, tier: 'web').sample&.dig('metadata', 'name')
|
65
|
+
target_pod_name = pod_name || Helpers.fetch_pods(app: app, filters: { tier: 'web' }).sample&.dig('metadata', 'name')
|
66
66
|
|
67
67
|
if target_pod_name
|
68
68
|
connect_to_pod(target_pod_name)
|
@@ -104,7 +104,7 @@ module Seira
|
|
104
104
|
command = args.join(' ')
|
105
105
|
|
106
106
|
# Find a 'template' pod from the proper tier
|
107
|
-
template_pod = fetch_pods(app: app, tier: tier).first
|
107
|
+
template_pod = Helpers.fetch_pods(app: app, filters: { tier: tier }).first
|
108
108
|
if template_pod.nil?
|
109
109
|
puts "Unable to find #{tier} tier pod to copy config from"
|
110
110
|
exit(1)
|
@@ -164,11 +164,6 @@ module Seira
|
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
167
|
-
def fetch_pods(filters)
|
168
|
-
filter_string = filters.map { |k, v| "#{k}=#{v}" }.join(',')
|
169
|
-
JSON.parse(`kubectl get pods --namespace=#{app} -o json --selector=#{filter_string}`)['items']
|
170
|
-
end
|
171
|
-
|
172
167
|
def connect_to_pod(name, command = 'bash')
|
173
168
|
puts "Connecting to #{name}..."
|
174
169
|
system("kubectl exec -ti #{name} --namespace=#{app} -- #{command}")
|
data/lib/seira/setup.rb
CHANGED
@@ -18,7 +18,7 @@ module Seira
|
|
18
18
|
ensure_software_installed
|
19
19
|
|
20
20
|
if arg == 'all'
|
21
|
-
puts "We will now set up gcloud and kubectl for each project. We use a distinct GCP Project for each environment
|
21
|
+
puts "We will now set up gcloud and kubectl for each project. We use a distinct GCP Project for each environment, which are specified in .seira.yml."
|
22
22
|
settings.valid_cluster_names.each do |cluster|
|
23
23
|
setup_cluster(cluster)
|
24
24
|
end
|
@@ -26,7 +26,7 @@ module Seira
|
|
26
26
|
puts "We will now set up gcloud and kubectl for #{arg}"
|
27
27
|
setup_cluster(arg)
|
28
28
|
else
|
29
|
-
puts "Please specify a valid cluster name or 'all'."
|
29
|
+
puts "Please specify a valid cluster name or 'all'. Got #{arg}"
|
30
30
|
exit(1)
|
31
31
|
end
|
32
32
|
|
@@ -51,20 +51,8 @@ module Seira
|
|
51
51
|
end
|
52
52
|
|
53
53
|
system("gcloud config configurations activate #{cluster_name}")
|
54
|
-
|
55
|
-
|
56
|
-
# system("gcloud iam service-accounts create #{iam_user} --display-name=#{iam_user}")
|
57
|
-
# puts "Created service account:"
|
58
|
-
# system("gcloud iam service-accounts describe #{iam_user}@#{cluster_metadata['project']}.iam.gserviceaccount.com")
|
59
|
-
puts "First,"
|
60
|
-
puts "First, set up a service account in the #{cluster_metadata['project']} project and download the credentials for it. You may do so by accessing the below link. Save the file in a safe location."
|
61
|
-
puts "https://console.cloud.google.com/iam-admin/serviceaccounts/project?project=#{cluster_metadata['project']}&organizationId=#{settings.organization_id}"
|
62
|
-
puts "Then, set up an IAM user that it will inherit the permissions for."
|
63
|
-
|
64
|
-
puts "Please enter the path of your JSON key:"
|
65
|
-
filename = STDIN.gets
|
66
|
-
puts "Activating service account..."
|
67
|
-
system("gcloud auth activate-service-account --key-file #{filename}")
|
54
|
+
puts "Authenticating in order to set the auth for project #{cluster_name}. You will be directed to a google login page."
|
55
|
+
system("gcloud auth login")
|
68
56
|
system("gcloud config set project #{cluster_metadata['project']}")
|
69
57
|
system("gcloud config set compute/zone #{settings.default_zone}")
|
70
58
|
puts "Your new gcloud setup for #{cluster_name}:"
|
data/lib/seira/version.rb
CHANGED
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Ringwelski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|