seira 0.7.5 → 0.8.1
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/cluster.rb +20 -2
- data/lib/seira/commands/teleport.rb +28 -0
- data/lib/seira/commands.rb +9 -0
- data/lib/seira/pods.rb +8 -3
- data/lib/seira/settings.rb +26 -0
- data/lib/seira/setup.rb +5 -0
- data/lib/seira/teleport/request.rb +31 -0
- data/lib/seira/teleport/role_requirements.rb +41 -0
- data/lib/seira/teleport/status.rb +58 -0
- data/lib/seira/teleport.rb +3 -0
- data/lib/seira/version.rb +1 -1
- data/lib/seira.rb +17 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb319292b2073d2caa5a7d526f70b7f6a707dfa8a7e8b7eba014d488c1ce50ee
|
4
|
+
data.tar.gz: b6dfc7dd336518acc1d510177d8eff2f02252351cece68e57c68d9019272d674
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 137620c27df4b7fb22580bb33249d8c6ea6b087f2203205b73f844eef456b20342af2f9c753264439e390ec9c82ad1e47dcda719885cd57ba2a980dbe9803ad9
|
7
|
+
data.tar.gz: f40b95e33ab48142deb3673b804507f7f9bf91e37b7a66827e92feb5afbdfaadf59032d6ea3d1848be956037037cd2f4e5d9910a8b442e0b86d34ff2a7b58cfe
|
data/lib/seira/cluster.rb
CHANGED
@@ -41,8 +41,26 @@ module Seira
|
|
41
41
|
cluster_metadata = settings.clusters[target_cluster]
|
42
42
|
|
43
43
|
puts("Switching to gcloud config of '#{target_cluster}' and kubernetes cluster of '#{cluster_metadata['cluster']}'") if verbose
|
44
|
-
|
45
|
-
|
44
|
+
unless system("gcloud config configurations activate #{target_cluster}")
|
45
|
+
puts("Try running `seira setup #{target_cluster}` if you have not yet configured this cluster.")
|
46
|
+
exit(1)
|
47
|
+
end
|
48
|
+
|
49
|
+
if settings.use_teleport?(target_cluster)
|
50
|
+
teleport_status = Seira::Teleport::Status.new
|
51
|
+
|
52
|
+
unless teleport_status.is_valid?
|
53
|
+
if teleport_status.active_cluster == settings.teleport_cluster(target_cluster)
|
54
|
+
exit(1) unless system("tsh login")
|
55
|
+
else
|
56
|
+
exit(1) unless system("tsh login --proxy=#{settings.teleport_cluster(target_cluster)}:443 --auth=#{settings.teleport_auth(target_cluster)}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
exit(1) unless system("tsh kube login #{settings.teleport_kubernetes_cluster(target_cluster)}")
|
61
|
+
else
|
62
|
+
exit(1) unless system("kubectl config use-context #{cluster_metadata['cluster']}")
|
63
|
+
end
|
46
64
|
|
47
65
|
# If we haven't exited by now, it was successful
|
48
66
|
true
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Seira
|
2
|
+
module Commands
|
3
|
+
class Teleport
|
4
|
+
attr_reader :context, :command
|
5
|
+
|
6
|
+
def initialize(command, context: nil)
|
7
|
+
@command = command
|
8
|
+
@context = context
|
9
|
+
end
|
10
|
+
|
11
|
+
def invoke(clean_output: false, return_output: false)
|
12
|
+
puts "Calling: #{calculated_command.green}" unless clean_output
|
13
|
+
|
14
|
+
if return_output
|
15
|
+
`#{calculated_command}`
|
16
|
+
else
|
17
|
+
system(calculated_command)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def calculated_command
|
24
|
+
@calculated_command ||= "tsh #{command}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/seira/commands.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'seira/commands/kubectl'
|
2
2
|
require 'seira/commands/gcloud'
|
3
|
+
require 'seira/commands/teleport'
|
3
4
|
|
4
5
|
module Seira
|
5
6
|
module Commands
|
@@ -18,5 +19,13 @@ module Seira
|
|
18
19
|
def self.gcloud(command, context:, clean_output: false, format: :boolean)
|
19
20
|
Gcloud.new(command, context: context, clean_output: clean_output, format: format).invoke
|
20
21
|
end
|
22
|
+
|
23
|
+
def tsh(command, context:, clean_output: false, return_output: false)
|
24
|
+
Seira::Commands.tsh(command, context: context, clean_output: clean_output, return_output: return_output)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.tsh(command, context:, clean_output: false, return_output: false)
|
28
|
+
Teleport.new(command, context: context).invoke(clean_output: clean_output, return_output: return_output)
|
29
|
+
end
|
21
30
|
end
|
22
31
|
end
|
data/lib/seira/pods.rb
CHANGED
@@ -41,7 +41,12 @@ module Seira
|
|
41
41
|
def run_help
|
42
42
|
puts SUMMARY
|
43
43
|
puts "\n\n"
|
44
|
-
puts "
|
44
|
+
puts "Possible actions:\n\n"
|
45
|
+
puts "list: List all the pods (output mode wide)."
|
46
|
+
puts "delete: Delete the pod (positional arg)."
|
47
|
+
puts "logs: Log the output of the pod (provided via positional arg)."
|
48
|
+
puts "top: Print the current resource usage for the specified pod (optional positional arg) or all the pods (default) in the context's namespace."
|
49
|
+
puts "connect: Connect to, or run a command on (--command=), a running pod (positional arg or --pod=), or create a new dedicated pod (--dedicated). Can override tier (--tier=)"
|
45
50
|
end
|
46
51
|
|
47
52
|
def run_list
|
@@ -53,7 +58,7 @@ module Seira
|
|
53
58
|
end
|
54
59
|
|
55
60
|
def run_logs
|
56
|
-
kubectl("logs #{pod_name} -c #{app}")
|
61
|
+
kubectl("logs #{pod_name} -c #{app}", context: context)
|
57
62
|
end
|
58
63
|
|
59
64
|
def run_top
|
@@ -62,7 +67,7 @@ module Seira
|
|
62
67
|
|
63
68
|
def run_connect
|
64
69
|
tier = nil
|
65
|
-
pod_name =
|
70
|
+
pod_name = pod_name
|
66
71
|
dedicated = false
|
67
72
|
command = 'sh'
|
68
73
|
|
data/lib/seira/settings.rb
CHANGED
@@ -68,6 +68,32 @@ module Seira
|
|
68
68
|
settings['seira']['expected_environment_variable_during_deploys']
|
69
69
|
end
|
70
70
|
|
71
|
+
def use_teleport?(cluster)
|
72
|
+
teleport_enabled = settings['seira']['clusters'][cluster].dig('teleport', 'enabled')
|
73
|
+
|
74
|
+
return false if teleport_enabled.nil?
|
75
|
+
|
76
|
+
teleport_enabled || ENV['SEIRA_TELEPORT_ENABLED'] == 'true'
|
77
|
+
end
|
78
|
+
|
79
|
+
def teleport_cluster(cluster)
|
80
|
+
settings['seira']['clusters'][cluster].dig('teleport', 'cluster')
|
81
|
+
end
|
82
|
+
|
83
|
+
def teleport_auth(cluster)
|
84
|
+
settings['seira']['clusters'][cluster].dig('teleport', 'auth')
|
85
|
+
end
|
86
|
+
|
87
|
+
def teleport_kubernetes_cluster(cluster)
|
88
|
+
settings['seira']['clusters'][cluster].dig('teleport', 'kubernetes_cluster') || cluster
|
89
|
+
end
|
90
|
+
|
91
|
+
def teleport_role_requirements(cluster)
|
92
|
+
requirements = settings['seira']['clusters'][cluster].dig('teleport', 'role_requirements') || []
|
93
|
+
|
94
|
+
requirements.map { |r| Seira::Teleport::RoleRequirement.new(r) }
|
95
|
+
end
|
96
|
+
|
71
97
|
private
|
72
98
|
|
73
99
|
def parse_settings
|
data/lib/seira/setup.rb
CHANGED
@@ -121,6 +121,11 @@ module Seira
|
|
121
121
|
puts "Installing kubectl..."
|
122
122
|
system('gcloud components install kubectl')
|
123
123
|
end
|
124
|
+
|
125
|
+
puts "Making sure tsh is installed..."
|
126
|
+
unless system('tsh version &> /dev/null')
|
127
|
+
puts "Go to https://goteleport.com/docs/installation/ to install tsh.".yellow
|
128
|
+
end
|
124
129
|
end
|
125
130
|
|
126
131
|
def run_status
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Seira
|
2
|
+
module Teleport
|
3
|
+
class Request
|
4
|
+
def initialize(role, reviewer: nil, context: nil)
|
5
|
+
@role = role
|
6
|
+
@reviewer = reviewer
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def invoke
|
11
|
+
command.invoke
|
12
|
+
end
|
13
|
+
|
14
|
+
def cmd
|
15
|
+
cmd = "request create --roles '#{@role}'"
|
16
|
+
cmd += " --reason '#{reason}'"
|
17
|
+
cmd += " --reviewers #{@reviewer}" unless @reviewer.nil?
|
18
|
+
|
19
|
+
cmd
|
20
|
+
end
|
21
|
+
|
22
|
+
def reason
|
23
|
+
"Running: seira #{@context[:cluster]} #{@context[:app]} #{@context[:category]} #{@context[:action]}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def command
|
27
|
+
@command ||= Seira::Commands::Teleport.new(cmd, context: @context)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Seira
|
2
|
+
module Teleport
|
3
|
+
class RoleRequirement
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
attr_reader :commands, :category, :role
|
7
|
+
|
8
|
+
def initialize(requirement)
|
9
|
+
@requirement = requirement
|
10
|
+
@category = requirement['category']
|
11
|
+
@commands = requirement['commands']
|
12
|
+
@role = requirement['role']
|
13
|
+
end
|
14
|
+
|
15
|
+
def matches?(category, command)
|
16
|
+
@category == category && command_matches?(command)
|
17
|
+
end
|
18
|
+
|
19
|
+
def <=>(other)
|
20
|
+
raise ArgumentError, 'Cannot compare different categories' if category != other.category
|
21
|
+
|
22
|
+
if commands.nil?
|
23
|
+
return -1
|
24
|
+
elsif other.commands.nil?
|
25
|
+
return 1
|
26
|
+
end
|
27
|
+
|
28
|
+
commands.length <=> other.commands.length
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def command_matches?(command)
|
34
|
+
return false if command == 'help'
|
35
|
+
return true if @requirement['commands'].nil?
|
36
|
+
|
37
|
+
@requirement['commands'].include?(command)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'date'
|
3
|
+
require 'seira/commands/teleport'
|
4
|
+
|
5
|
+
module Seira
|
6
|
+
module Teleport
|
7
|
+
class Status
|
8
|
+
attr_reader :data
|
9
|
+
|
10
|
+
def initialize(data: nil)
|
11
|
+
@data = data
|
12
|
+
@data ||= get_status_json
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
data[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
def active_cluster
|
20
|
+
data.dig('active', 'cluster')
|
21
|
+
end
|
22
|
+
|
23
|
+
def kubernetes_cluster
|
24
|
+
data.dig('active','kubernetes_cluster')
|
25
|
+
end
|
26
|
+
|
27
|
+
def roles
|
28
|
+
@roles ||= data.dig('active', 'roles')
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_role?(role)
|
32
|
+
return false if roles.nil?
|
33
|
+
|
34
|
+
roles.include?(role)
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_valid?
|
38
|
+
valid_until = data.dig('active', 'valid_until')
|
39
|
+
return false if valid_until.nil?
|
40
|
+
|
41
|
+
DateTime.parse(data.dig('active', 'valid_until')) > DateTime.now
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def get_status_json
|
47
|
+
cmd = Seira::Commands::Teleport.new('status -f json', context: :none)
|
48
|
+
|
49
|
+
out = cmd.invoke(clean_output: true, return_output: true)
|
50
|
+
if out == ''
|
51
|
+
{}
|
52
|
+
else
|
53
|
+
JSON.parse(cmd.invoke(clean_output: true, return_output: true))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/seira/version.rb
CHANGED
data/lib/seira.rb
CHANGED
@@ -20,6 +20,7 @@ require 'seira/settings'
|
|
20
20
|
require 'seira/setup'
|
21
21
|
require 'seira/node_pools'
|
22
22
|
require 'seira/util/resource_renderer'
|
23
|
+
require 'seira/teleport'
|
23
24
|
|
24
25
|
# A base runner class that does base checks and then delegates the actual
|
25
26
|
# work for the command to a class in lib/seira folder.
|
@@ -118,6 +119,16 @@ module Seira
|
|
118
119
|
exit(1)
|
119
120
|
end
|
120
121
|
|
122
|
+
if settings.use_teleport?(cluster)
|
123
|
+
role_requirements = settings.teleport_role_requirements(cluster)
|
124
|
+
required_role = role_requirements.filter { |rr| rr.matches?(category, action) }.sort.first&.role
|
125
|
+
status = Seira::Teleport::Status.new
|
126
|
+
|
127
|
+
unless required_role.nil? || status.has_role?(required_role)
|
128
|
+
Seira::Teleport::Request.new(required_role, reviewer: ENV['TELEPORT_REVIEWER'], context: passed_context).invoke
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
121
132
|
if category == 'cluster'
|
122
133
|
perform_action_validation(klass: command_class, action: action)
|
123
134
|
command_class.new(action: action, args: args, context: passed_context, settings: settings).run
|
@@ -142,6 +153,7 @@ module Seira
|
|
142
153
|
region: settings.region_for_cluster(cluster),
|
143
154
|
zone: settings.zone_for_cluster(cluster),
|
144
155
|
app: app,
|
156
|
+
category: category,
|
145
157
|
action: action,
|
146
158
|
args: args
|
147
159
|
}
|
@@ -159,6 +171,11 @@ module Seira
|
|
159
171
|
exit(1)
|
160
172
|
end
|
161
173
|
|
174
|
+
unless system("tsh version > /dev/null 2>&1")
|
175
|
+
puts "Teleport CLI not installed properly. Please install `tsh` before using seira.".red
|
176
|
+
exit(1)
|
177
|
+
end
|
178
|
+
|
162
179
|
# The first arg must always be the cluster. This ensures commands are not run by
|
163
180
|
# accident on the wrong kubernetes cluster or gcloud project.
|
164
181
|
exit(1) unless Seira::Cluster.new(action: nil, args: nil, context: nil, settings: settings).switch(target_cluster: cluster, verbose: false)
|
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.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Ringwelski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- lib/seira/commands.rb
|
124
124
|
- lib/seira/commands/gcloud.rb
|
125
125
|
- lib/seira/commands/kubectl.rb
|
126
|
+
- lib/seira/commands/teleport.rb
|
126
127
|
- lib/seira/config.rb
|
127
128
|
- lib/seira/db.rb
|
128
129
|
- lib/seira/db/create.rb
|
@@ -135,6 +136,10 @@ files:
|
|
135
136
|
- lib/seira/secrets.rb
|
136
137
|
- lib/seira/settings.rb
|
137
138
|
- lib/seira/setup.rb
|
139
|
+
- lib/seira/teleport.rb
|
140
|
+
- lib/seira/teleport/request.rb
|
141
|
+
- lib/seira/teleport/role_requirements.rb
|
142
|
+
- lib/seira/teleport/status.rb
|
138
143
|
- lib/seira/util/resource_renderer.rb
|
139
144
|
- lib/seira/version.rb
|
140
145
|
- resources/adjectives.txt
|