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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06e2e516ae84d1bcdc4f3320eeb13c83dc6cd162bfbe5e249b53e2b3af74885c
4
- data.tar.gz: 027a214ded3ab47b25fe29b9e8943bd268fe908ff9aa87993ffa07e9c395e350
3
+ metadata.gz: eb319292b2073d2caa5a7d526f70b7f6a707dfa8a7e8b7eba014d488c1ce50ee
4
+ data.tar.gz: b6dfc7dd336518acc1d510177d8eff2f02252351cece68e57c68d9019272d674
5
5
  SHA512:
6
- metadata.gz: f6cc9ea8137d0ae4578a5fbdbeac88f8e8d01916dd8e64f8dc83d4ac30517fda718ae06d0d02b5c354e9d80e3ee3ab3f75df433dda45ac85b60e512cc878b058
7
- data.tar.gz: 828524836a6abc488bc29a3333733887e57b39351f9d54b8ecb9986c49520abd6e8564b97425f702fed90b2256f68c558303c76ee6be49fc58362a3898fc4f32
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
- exit(1) unless system("gcloud config configurations activate #{target_cluster}")
45
- exit(1) unless system("kubectl config use-context #{cluster_metadata['cluster']}")
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
@@ -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 "TODO"
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 = nil
70
+ pod_name = pod_name
66
71
  dedicated = false
67
72
  command = 'sh'
68
73
 
@@ -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
@@ -0,0 +1,3 @@
1
+ require 'seira/teleport/status'
2
+ require 'seira/teleport/role_requirements'
3
+ require 'seira/teleport/request'
data/lib/seira/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Seira
2
- VERSION = "0.7.5".freeze
2
+ VERSION = "0.8.1".freeze
3
3
  end
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.7.5
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-03-28 00:00:00.000000000 Z
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