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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db287b6e4753b077e1b2340e263137e739ac94a8
4
- data.tar.gz: 69b980247f1809ec81f478bf402a14eb6e0e1358
3
+ metadata.gz: 8d89537c56c0c2a5fc49a16238d2b063e55806d7
4
+ data.tar.gz: 3f4231dd7aa7ea3717d146f49c751068992a957f
5
5
  SHA512:
6
- metadata.gz: ac64bd6b4fc973a71c4bc97666ec4b52878cddff5d432ea2af47ef37b6f83a9fdf7a85483b0a78013b8ba9e6f7002c02d0d850496c89061b789585fa0f86dbf9
7
- data.tar.gz: 2422fd823be52e7e6294b9e76564c147ee73a3c043d713c5d0b4943f38c3758f8be8da0957df327a8a9cd7a6f1f015b93d6d0eee841065e30f4c431f07069f6a
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 = @settings.full_cluster_name_for_shorthand(cluster)
71
- @project = @settings.project_for_cluster(@cluster)
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
@@ -194,7 +194,7 @@ module Seira
194
194
  end
195
195
 
196
196
  def pgbouncer_tier
197
- name.gsub("handshake-", "")
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: #{ENVIRONMENTS.join(', ')}"
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
- # TODO: Is this possible to automate?
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
@@ -1,3 +1,3 @@
1
1
  module Seira
2
- VERSION = "0.2.2".freeze
2
+ VERSION = "0.3.0".freeze
3
3
  end
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.2.2
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-02 00:00:00.000000000 Z
11
+ date: 2018-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline