sct 0.1.25 → 0.1.30

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: b0014f7b902a222679cab47e9a2595a52c6c037e7bb3c47c0ae03e3b69c9f8d7
4
- data.tar.gz: 37cff1b39148c84cd7d4e626e5d55744017c2a1406183b0915fd0bf8013730dc
3
+ metadata.gz: 2dc9c664ca89d649033d4fcfdcad7e8d72d78b448d800caa8c8097ec1ea7ed47
4
+ data.tar.gz: f3cdba0dfbaacbf240e4f84f8530cb835308a19203999db78759b17d4eb18150
5
5
  SHA512:
6
- metadata.gz: 419ab66f62d5a1cd697b8a1ddd3a26a1bda26778d6be199b1424ac72d6c8a33854657a5ab2f80838ea25e3f456f0a33e81c5cf6b7418aa22e7869898a2ac72be
7
- data.tar.gz: 9487da0833e8c581c5c036ecd270794a40f62eee44c80520ddbe89c19b9bd80098a02bb60c94f47f0f08acc2823a25a9d0b13b469e2511af2bb68f3424e2dac3
6
+ metadata.gz: 56c7e96250c79f3fdb4de6fab3358e4e6eb443f813064d88e9353a766eccecc1ad1c7f2c2878716347676e3c24de1d09456763ccc2c857d13eb6cd4f058f7593
7
+ data.tar.gz: 27543415be2aac23a5032b2b96bb7504dd12b5cc3d41f73c489251416d1d3bc3ddd83c8af71f7163b96b0bfe1c22a1f8f06e8c9992a5a54d279a89a40d3c90b6
@@ -9,63 +9,71 @@ module Cluster
9
9
  self.new.run
10
10
  end
11
11
 
12
- def run
12
+ def run
13
13
  program :name, 'cluster'
14
14
  program :version, Sct::VERSION
15
15
  program :description, 'CLI for \'cluster\' - Manage your local kubernetes cluster'
16
16
 
17
17
  global_option('--verbose') { $verbose = true }
18
18
 
19
- command :up do |c|
19
+ command :start do |c|
20
+ c.syntax = "sct cluster start"
21
+ c.description = "start the cluster"
20
22
 
21
- c.syntax = "sct cluster up"
22
- c.description = "Start the cluster"
23
- c.option '--clean', 'start a clean cluster. Old cluster will be purged if available.'
24
-
25
- c.action do |args, options|
26
- if options.clean
27
- Cluster::Runner.new.reset
28
- else
29
- Cluster::Runner.new.launch
30
- end
23
+ c.action do |args, options|
24
+ Cluster::Runner.new.start
31
25
  end
32
26
 
33
27
  end
34
28
 
35
- command :down do |c|
36
-
37
- c.syntax = 'sct cluster down'
29
+ command :stop do |c|
30
+ c.syntax = 'sct cluster stop'
38
31
  c.description = 'stop the cluster'
39
32
 
40
- c.action do |args, options|
41
- Cluster::Runner.new.down
33
+ c.action do |args, options|
34
+ Cluster::Runner.new.stop
42
35
  end
43
36
  end
44
37
 
45
- command :reset do |c|
38
+ command :restart do |c|
39
+ c.syntax = "sct cluster restart"
40
+ c.description = "restart the cluster"
41
+
42
+ c.action do |args, options|
43
+ Cluster::Runner.new.restart
44
+ end
45
+
46
+ end
47
+
48
+ command :delete do |c|
49
+ c.syntax = "sct cluster delete"
50
+ c.description = "delete the cluster"
51
+
52
+ c.action do |args, options|
53
+ Cluster::Runner.new.delete
54
+ end
55
+
56
+ end
46
57
 
58
+ command :reset do |c|
47
59
  c.syntax = 'sct cluster reset'
48
- c.description = 'reset your cluster and start with a clean cluster'
60
+ c.description = 'delete the cluster and start a new cluster'
49
61
 
50
- c.action do |args, options|
62
+ c.action do |args, options|
51
63
  Cluster::Runner.new.reset
52
64
  end
53
65
  end
54
66
 
55
- alias_command :'setup', :'reset'
56
-
57
67
  command :status do |c|
58
-
59
68
  c.syntax = 'sct cluster status'
60
69
  c.description = 'see the status of your cluster'
61
70
 
62
- c.action do |args, options|
71
+ c.action do |args, options|
63
72
  Cluster::Runner.new.status
64
73
  end
65
74
  end
66
75
 
67
76
  command :'update config' do |c|
68
-
69
77
  c.syntax = 'sct cluster update config'
70
78
  c.description = 'update the cluster configuration'
71
79
 
@@ -74,36 +82,16 @@ module Cluster
74
82
  end
75
83
  end
76
84
 
77
- command :'delete pods' do |c|
78
- c.syntax = 'sct cluster delete stalled pods'
79
- c.description = 'delete stalled pods from the cluster'
80
- c.option '--stalled', 'delete stalled pods'
81
- c.option '--all', 'delete all pods'
82
-
83
- c.action do |args, options|
84
-
85
- Cluster::Runner.new.delete_stalled_pods if options.stalled
86
- Cluster::Runner.new.delete_all_pods if options.all
87
-
88
- Cluster::Runner.new.delete_pods(args) if !args.empty?
89
-
90
- end
91
- end
92
-
93
- command :'apply pods' do |c|
94
- c.syntax = 'sct cluster apply pods'
95
- c.description = 'apply pods from the k8s folder'
85
+ command :'apply deployments' do |c|
86
+ c.syntax = 'sct cluster apply deployments'
87
+ c.description = 'apply deployments from the k8s folder'
96
88
 
97
89
  c.action do |args, options|
98
-
99
- Cluster::Runner.new.apply_pods
100
-
90
+ Cluster::Runner.new.apply_deployments
101
91
  end
102
92
  end
103
93
 
104
- default_command :status
105
-
106
94
  run!
107
95
  end
108
96
  end
109
- end
97
+ end
@@ -2,6 +2,6 @@ module Cluster
2
2
 
3
3
  # import the helper functionality from SCT
4
4
  Helpers = Sct::Helper
5
- UI = Sct::UI
5
+ UI = Sct::UI
6
6
 
7
- end
7
+ end
@@ -1,118 +1,158 @@
1
1
  module Cluster
2
2
  class Runner
3
3
 
4
- def launch
5
- return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
4
+ def start
5
+ SctCore::Helper.ensure_windows_administrator # "sct hostfile" will need it later on
6
+
7
+ existing_cluster = cluster_exists?
8
+
6
9
  start_cluster
7
- run_command "kubectl delete pod -n kube-system #{pods("kube-system").map { |pod| pod[:name] if pod[:name].start_with? "registry-creds" } .compact.join(" ")}"
8
- run_command "kubectl rollout status -n kube-system deployment/registry-creds"
10
+
11
+ if existing_cluster
12
+ run_command "kubectl rollout restart -n kube-system deployment registry-creds"
13
+ run_command "kubectl rollout status -n kube-system deployment registry-creds"
14
+ else
15
+ create_secrets
16
+ enable_addons
17
+ wait_for_gcr_secret
18
+ run_command "kubectl apply -f ~/development/spend-cloud/k8s/ingress.yml"
19
+ wait_for_ingress_ip
20
+ run_command "kubectl apply -f ~/development/spend-cloud/k8s/dependencies.yml"
21
+ wait_for_pods
22
+ run_command "kubectl apply -f ~/development/spend-cloud/k8s/"
23
+ end
24
+
9
25
  post_start
10
26
  end
11
27
 
28
+ def stop
29
+ run_command "minikube stop"
30
+ end
31
+
32
+ def restart
33
+ SctCore::Helper.ensure_windows_administrator # "sct hostfile" will need it later on
34
+
35
+ stop
36
+ start
37
+ end
38
+
39
+ def delete
40
+ run_command "minikube delete"
41
+ end
42
+
43
+ def reset
44
+ SctCore::Helper.ensure_windows_administrator # "sct hostfile" will need it later on
45
+
46
+ delete
47
+ start
48
+ end
49
+
50
+ def status
51
+ print_contexts
52
+ print_minikube_status
53
+
54
+ if get_minikube_status.find_all { |status| status[1] == 'Stopped' }.count == 0
55
+ print_pods_status("kube-system")
56
+ print_pods_status
57
+ else
58
+ UI.important("Please check your minikube status. If all services are stopped you should start the minikube first.")
59
+ end
60
+ end
61
+
62
+ def update_config
63
+ run_command "kubectl config use-context minikube"
64
+
65
+ run_command "kubectl replace -n kube-system -f #{File.expand_path('resources/corefile.yml', __dir__)}"
66
+ run_command "kubectl rollout restart -n kube-system deployment coredns"
67
+ run_command "kubectl rollout status -n kube-system deployment coredns"
68
+ end
69
+
70
+ def apply_deployments
71
+ run_command "kubectl apply -f ~/development/spend-cloud/k8s/"
72
+ end
73
+
74
+
75
+ def cluster_exists?
76
+ if system "minikube status", { out: "/dev/null" }
77
+ # cluster exists and is running
78
+ return true
79
+ end
80
+
81
+ if $?.exitstatus == 85
82
+ # cluster does not exist
83
+ return false
84
+ end
85
+
86
+ # cluster exists but is stopped
87
+ return true
88
+ end
89
+
12
90
  def start_cluster
13
91
  if SctCore::Helper.operatingSystem == SctCore::Helper::MAC_OS
14
- run_command "#{SctCore::Helper.minikube} start --cpus=$(sysctl -n hw.ncpu) --memory=8G"
92
+ run_command "minikube start --driver=docker --cpus=$(sysctl -n hw.ncpu) --memory=8G"
15
93
  else
16
- run_command "#{SctCore::Helper.minikube} start --cpus=$(cat /proc/cpuinfo | grep processor | wc -l) --memory=10G"
94
+ run_command "minikube start --driver=docker --cpus=$(cat /proc/cpuinfo | grep processor | wc -l) --memory=3G"
17
95
  end
18
- run_command "#{SctCore::Helper.minikube} ssh -- 'sudo su -c \"echo 10048576 > /proc/sys/fs/inotify/max_user_watches\"'"
19
96
  update_config
20
97
  end
21
98
 
22
99
  def post_start
23
100
  wait_for_pods
101
+ copy_proactive_accounts_file
24
102
  run_command "sudo sct hostfile"
103
+ run_command "minikube tunnel &", { out: "/dev/null", err: "/dev/null" } if SctCore::Helper::is_windows? # leave this running detached forever in the background
25
104
  UI.success("\n✔️ You can visit your environment at 👉 https://spend-cloud.spend.cloud.local 👌")
26
105
  end
27
106
 
28
- def down
29
- run_command "#{SctCore::Helper.minikube} stop"
30
- end
31
-
32
- def reset
33
- run_command "#{SctCore::Helper.minikube} delete"
34
- start_cluster
35
- create_secrets
36
- enable_addons
37
- wait_for_gcr_secret
38
- run_command "kubectl apply -f ~/development/spend-cloud/k8s/ingress.yml"
39
- wait_for_ingress_ip
40
- run_command "kubectl apply -f ~/development/spend-cloud/k8s/dependencies.yml"
41
- wait_for_pods
42
- run_command "kubectl apply -f ~/development/spend-cloud/k8s/"
43
- post_start
44
- end
45
-
46
107
  def enable_addons
47
108
  enable_addon "registry-creds"
48
109
  enable_addon "ingress"
49
110
  end
50
111
 
51
112
  def enable_addon(addon)
52
- run_command "#{SctCore::Helper.minikube} addons enable #{addon}"
113
+ run_command "minikube addons enable #{addon}"
53
114
 
54
115
  deployment = deployments("kube-system").find { |deployment| deployment[:name].include? addon }
55
116
 
56
- run_command "kubectl rollout status -n kube-system deployment/#{deployment[:name]}"
117
+ run_command "kubectl rollout status -n kube-system deployment #{deployment[:name]}"
57
118
  end
58
119
 
59
120
  def wait_for_pods
60
121
  UI.important("Waiting for pods to become ready...")
61
122
 
62
- while ! pods.all? { |pod| pod[:status] == "Running" }
63
- delete_stalled_pods
123
+ previous_lines = 0
64
124
 
65
- sleep 5
66
- end
125
+ while ! pods.all? { |pod| pod[:ready] }
126
+ pods_status_lines = get_pods_status.to_s.lines.map { |line| line.chomp }
67
127
 
68
- UI.success("Pods are now ready.")
69
- end
70
-
71
- def delete_stalled_pods(feedback: false)
72
-
73
- return UI.success("No stalled pods found") unless !pods.to_a.empty?
128
+ current_lines = pods_status_lines.length
74
129
 
75
- stalled_pods = pods.select { |pod| pod[:stalled] }
130
+ line_difference = current_lines - previous_lines
76
131
 
77
- if stalled_pods.empty?
78
- UI.success("There are no stalled pods.") if feedback
79
- else
80
- run_command "kubectl delete pods #{stalled_pods.map { |pod| pod[:name] } .join(" ")}"
81
- end
82
- end
132
+ if line_difference < 0 # there are now less lines than before
133
+ line_difference.abs.times do
134
+ print "\033[1A\033[K" # move the cursor up a line and clear the line
135
+ end
83
136
 
84
- def delete_all_pods
85
- run_command "kubectl delete pods --all"
86
- end
87
-
88
- def delete_pods(args)
89
- run_command "kubectl delete pods #{args.join(" ")}"
90
- end
91
-
92
- def apply_pods
93
- run_command "kubectl apply -f ~/development/spend-cloud/k8s/"
94
- end
95
-
96
- def update_config
97
- if SctCore::Helper.operatingSystem == SctCore::Helper::WINDOWS
98
- windows_home_path = SctCore::Helper.windowsHomePath
99
- kube_file_path = windows_home_path+"/.kube/config"
137
+ print "\033[#{current_lines}A" # move the cursor all the way up to the start of the table
138
+ elsif previous_lines > 0
139
+ print "\033[#{previous_lines}A" # move the cursor all the way up to the start of the table
140
+ end
100
141
 
101
- if !File.exists?(kube_file_path)
102
- return UI.error("#{kube_file_path} doesn't exist")
142
+ pods_status_lines.each do |line|
143
+ print "#{line}\033[K#{$/}" # print the content of the line, clear remaining characters and add a new line
103
144
  end
104
145
 
105
- run_command "sed -e 's~\\\\~/~g' -e 's~C:~/mnt/c~g' < #{kube_file_path} > ~/.kube/minikube-config"
146
+ previous_lines = current_lines
106
147
 
107
- UI.success("#{kube_file_path} copied to ~/.kube/minikube-config")
148
+ sleep 5
108
149
  end
109
150
 
110
- run_command "kubectl config use-context minikube"
151
+ previous_lines.times do
152
+ print "\033[1A\033[K" # move the cursor up a line and clear the line
153
+ end
111
154
 
112
- run_command "kubectl replace -n kube-system -f #{File.expand_path('resources/corefile.yml', __dir__)}"
113
- old_list = pods("kube-system").map { |pod| pod[:name] if pod[:name].start_with? "coredns" }.compact
114
- run_command "kubectl delete pod -n kube-system #{old_list.join(" ")}" unless old_list.to_a.empty?
115
- run_command "kubectl rollout status -n kube-system deployment/coredns"
155
+ UI.success("Pods are now ready.")
116
156
  end
117
157
 
118
158
  def deployments(namespace = "default")
@@ -150,13 +190,15 @@ module Cluster
150
190
  columns = line.split(" ")
151
191
 
152
192
  name = columns[0]
193
+ ready = columns[1].split("/").reduce { |l, r| l == r }
194
+ replicas = columns[1]
153
195
  status = columns[2]
154
- stalled = status == "ErrImagePull" || status == "ImagePullBackOff"
155
196
 
156
197
  {
157
198
  name: name,
158
- status: status,
159
- stalled: stalled
199
+ ready: ready,
200
+ replicas: replicas,
201
+ status: status
160
202
  }
161
203
  end
162
204
  end
@@ -193,18 +235,6 @@ module Cluster
193
235
  UI.success("Ingress IP is now available.")
194
236
  end
195
237
 
196
- def status
197
- print_contexts
198
- print_minikube_status
199
-
200
- if get_minikube_status.find_all { |status| status[1] == 'Stopped' }.count == 0
201
- print_pods_status("kube-system")
202
- print_pods_status
203
- else
204
- UI.important("Please check your minikube status. If all services are stopped you should start the minikube first.")
205
- end
206
- end
207
-
208
238
  def print_contexts
209
239
  output = `kubectl config get-contexts`
210
240
 
@@ -223,12 +253,11 @@ module Cluster
223
253
  end
224
254
 
225
255
  def print_minikube_status
226
-
227
256
  puts Terminal::Table.new title: "Minikube status".green, headings: ['Name', 'Status'], rows: get_minikube_status
228
257
  end
229
258
 
230
259
  def get_minikube_status
231
- output = `#{SctCore::Helper.minikube} status`
260
+ output = `minikube status`
232
261
 
233
262
  lines = output.split "\n"
234
263
 
@@ -240,25 +269,48 @@ module Cluster
240
269
  end
241
270
 
242
271
  def print_pods_status(namespace = "default")
272
+ output = get_pods_status(namespace)
243
273
 
244
- pods_list = pods(namespace)
274
+ puts output if output
275
+ end
245
276
 
246
- if pods_list.to_a.empty?
247
- return
248
- end
277
+ def get_pods_status(namespace = "default")
278
+ rows = pods(namespace).map do |pod|
279
+ status = pod[:status]
280
+ replicas = pod[:replicas]
249
281
 
250
- rows = pods_list.map do |pod|
251
282
  [
252
283
  pod[:name],
253
- pod[:status] == "Running" ? pod[:status].green : pod[:status].red
284
+ status == "Running" ? status.green : status.red,
285
+ pod[:ready] ? replicas.green : replicas.red
254
286
  ]
255
287
  end
256
288
 
257
- puts Terminal::Table.new title: "Pods (namespace: #{namespace})".green, headings: ['Name', 'Status'], rows: rows
289
+ if rows.empty?
290
+ return
291
+ end
292
+
293
+ return Terminal::Table.new title: "Pods (namespace: #{namespace})".green, headings: ['Name', 'Status', 'Replicas ready'], rows: rows
294
+ end
295
+
296
+ def copy_proactive_accounts_file
297
+ pod_id = pods().select {|pod| pod[:name].start_with?("proactive-config")}.first[:name]
298
+
299
+ begin
300
+ UI.important("Checking ProActive accounts file...")
301
+ run_command "kubectl exec #{pod_id} -- test -e /data/proactive_accounts.ini", [:out, :err] => File::NULL
302
+ rescue => e
303
+ UI.important("Copying ProActive accounts file to deployments...")
304
+ src_path = "#{Dir.home()}/development/spend-cloud/k8s/conf/proactive_accounts.ini"
305
+ command = "kubectl cp #{src_path} #{pod_id}:/data/proactive_accounts.ini"
306
+ run_command command
307
+ end
308
+
309
+ UI.success("ProActive accounts file is available")
258
310
  end
259
311
 
260
- def run_command command
261
- if ! system command
312
+ def run_command command, options = {}
313
+ if ! system command, options
262
314
  raise command.red
263
315
  end
264
316
  end
@@ -2,13 +2,7 @@ module Sct
2
2
  class HostfileCommand
3
3
 
4
4
  def execute(args, options)
5
- return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
6
-
7
- return UI.error("This command needs to be run with sudo.") unless SctCore::Helper.isSudo
8
-
9
- return unless SctCore::Helper.ingressAddress
10
-
11
- ingressAddress = SctCore::Helper.ingressAddress
5
+ SctCore::Helper.ensure_permissions
12
6
 
13
7
  entries = [
14
8
  {
@@ -37,32 +31,42 @@ module Sct
37
31
  }
38
32
  ]
39
33
 
34
+ is_windows = SctCore::Helper::is_windows?
35
+
36
+ if is_windows
37
+ ingress_address = "127.0.0.1"
38
+ else
39
+ ingress_address = `sudo -u $SUDO_USER minikube ip`.chomp
40
+ end
41
+
42
+ windows_hosts_path = "/mnt/c/Windows/System32/drivers/etc/hosts"
43
+
40
44
  if options.path
41
45
  hosts_paths = [options.path]
42
46
  else
43
47
  hosts_paths = ["/etc/hosts"]
44
48
 
45
- if SctCore::Helper.operatingSystem == SctCore::Helper::WINDOWS
46
- hosts_paths << "/mnt/c/Windows/System32/drivers/etc/hosts"
49
+ if is_windows
50
+ hosts_paths << windows_hosts_path
47
51
  end
48
52
  end
49
53
 
50
54
  hosts_paths.each do |hosts_path|
51
- line_ending = hosts_path == "/mnt/c/Windows/System32/drivers/etc/hosts" ? "\r\n" : "\n"
55
+ line_ending = hosts_path == windows_hosts_path ? "\r\n" : "\n"
52
56
 
53
57
  lines = File.readlines hosts_path
54
58
 
55
59
  # select the lines that do not include any entry
56
- lines = lines.select { |line| ! entries.any? { |entry| line.include? entry[:host] } }
60
+ lines = lines.select { |line| ! entries.any? { |entry| line.include? " #{entry[:host]}" } }
57
61
 
58
62
  # add entries
59
63
  entries.each do |entry|
60
- lines << "#{ingressAddress} #{entry[:host]} # #{entry[:comment]}#{line_ending}"
64
+ lines << "#{ingress_address} #{entry[:host]} # #{entry[:comment]}#{line_ending}"
61
65
  end
62
66
 
63
67
  File.write hosts_path, lines.join
64
68
 
65
- UI.success("Patched #{hosts_path} with #{ingressAddress}")
69
+ UI.success("Patched #{hosts_path} with #{ingress_address}")
66
70
  end
67
71
 
68
72
  end
@@ -9,7 +9,7 @@ module Sct
9
9
  self.new.run
10
10
  end
11
11
 
12
- def run
12
+ def run
13
13
  program :name, 'sct'
14
14
  program :version, Sct::VERSION
15
15
  program :summary, 'CLI helper tool for local SCT development'
@@ -17,11 +17,11 @@ module Sct
17
17
 
18
18
  global_option('--verbose') { $verbose = true }
19
19
 
20
- command :init do |c|
20
+ command :init do |c|
21
21
  c.syntax = 'sct init'
22
22
  c.description = 'setup sct'
23
23
 
24
- c.action do |args, options|
24
+ c.action do |args, options|
25
25
  UI.important("setting up sct")
26
26
  Sct::InitCommand.new.execute(args, options)
27
27
  end
@@ -33,24 +33,38 @@ module Sct
33
33
  c.description = 'patch hostfile with kubernetes ip'
34
34
 
35
35
  c.action do |args, options|
36
- UI.important("Trying to patch hostfile")
36
+ UI.important("Trying to patch hosts file...")
37
37
  Sct::HostfileCommand.new.execute(args, options)
38
38
  end
39
39
  end
40
40
 
41
- command :'mysql proxy' do |c|
41
+ command :'mysql-proxy' do |c|
42
42
 
43
- c.syntax = 'sct mysql proxy'
43
+ c.syntax = 'sct mysql-proxy'
44
44
  c.description = 'setup google mysql proxy'
45
45
 
46
- c.action do |args, options|
46
+ c.action do |args, options|
47
47
  UI.important("Trying to setup mysql proxy")
48
48
  Sct::MysqlproxyCommand.new.execute(args, options)
49
49
  end
50
50
 
51
51
  end
52
52
 
53
+ command :'cluster' do |c|
54
+
55
+ c.syntax = 'sct cluster'
56
+ c.description = 'make changes to the cluster'
57
+
58
+ end
59
+
60
+ command :'shell' do |c|
61
+
62
+ c.syntax = 'sct shell'
63
+ c.description = 'run commands from the shell using docker containers'
64
+
65
+ end
66
+
53
67
  run!
54
68
  end
55
69
  end
56
- end
70
+ end
@@ -1,3 +1,3 @@
1
1
  module Sct
2
- VERSION = "0.1.25"
2
+ VERSION = "0.1.30"
3
3
  end
@@ -5,27 +5,6 @@ module SctCore
5
5
  MAC_OS = "MacOS"
6
6
  UBUNTU = "Ubuntu"
7
7
 
8
- def self.ingressAddress
9
- if self.operatingSystem == WINDOWS
10
- kubeconfig_file = "minikube-config"
11
- else
12
- kubeconfig_file = "config"
13
- end
14
-
15
- kubeconfig_path= "#{self.homePath}/.kube/#{kubeconfig_file}"
16
-
17
- ip = `KUBECONFIG="#{kubeconfig_path}" kubectl get ingress`
18
-
19
- if ip.nil? || ip.empty?
20
- puts "Can't fetch IP from kubectl".yellow
21
- return nil
22
- end
23
-
24
- match = ip.scan(/((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3})/)
25
-
26
- return match.first.first
27
- end
28
-
29
8
  def self.to_hash(str)
30
9
  Hash[
31
10
  str.split("\n").map{|i|i.split('=')}
@@ -60,7 +39,7 @@ module SctCore
60
39
  end
61
40
 
62
41
  def self.windowsHomePath
63
- if self.operatingSystem == WINDOWS
42
+ if self.is_windows?
64
43
  return self.convertWindowsToWSLPath(`cmd.exe /c echo %userprofile%`)
65
44
  end
66
45
 
@@ -68,7 +47,7 @@ module SctCore
68
47
  end
69
48
 
70
49
  def self.convertWindowsToWSLPath(path)
71
- if self.operatingSystem == WINDOWS
50
+ if self.is_windows?
72
51
  return path.gsub(/C:\\/, '/mnt/c/').gsub(/\\\\/, "/").gsub(/\\/, '/').gsub(/\r\n?/, '')
73
52
  end
74
53
 
@@ -76,23 +55,43 @@ module SctCore
76
55
  end
77
56
 
78
57
  def self.convertWSLToWindowsPath(path)
79
- if self.operatingSystem == WINDOWS
58
+ if self.is_windows?
80
59
  return path.gsub(/\/mnt\/c/, 'C:/').gsub(/\/\//, '/').gsub(/\\\\/, "/").gsub(/\r\n?/, '')
81
60
  end
82
61
 
83
62
  return path
84
63
  end
85
64
 
86
- def self.isSudo
65
+ def self.is_sudo?
87
66
  return !ENV["SUDO_USER"].nil? && !ENV["SUDO_USER"].empty?
88
67
  end
89
68
 
90
- def self.minikube
91
- if self.operatingSystem == WINDOWS
92
- return "minikube.exe"
93
- else
94
- return "minikube"
69
+ def self.is_windows?
70
+ return self.operatingSystem == WINDOWS
71
+ end
72
+
73
+ def self.is_windows_administrator?
74
+ # https://serverfault.com/a/95464
75
+ return `/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -c "(New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)"` == "True\r\n"
76
+ end
77
+
78
+ def self.ensure_sudo
79
+ if !self.is_sudo?
80
+ UI.error "This command needs to be run with sudo."
81
+ exit 1
95
82
  end
96
83
  end
84
+
85
+ def self.ensure_windows_administrator
86
+ if self.is_windows? && !self.is_windows_administrator?
87
+ UI.error "This command needs to be run in an admin shell."
88
+ exit 1
89
+ end
90
+ end
91
+
92
+ def self.ensure_permissions
93
+ self.ensure_sudo
94
+ self.ensure_windows_administrator
95
+ end
97
96
  end
98
97
  end
@@ -38,11 +38,7 @@ module SctCore
38
38
  UI.important("# An update for #{gem_name} is available. You are on #{current_version}.")
39
39
  end
40
40
  UI.important("# You should use the latest version.")
41
- UI.important("# Please update using `#{self.update_command(gem_name: gem_name)}`.")
42
-
43
- UI.important('#######################################################################')
44
- UI.important("# Run `sudo gem cleanup` from time to time to speed up sct.")
45
-
41
+ UI.important("# Please update by running `#{self.update_command(gem_name: gem_name)}`.")
46
42
  UI.important('#######################################################################')
47
43
 
48
44
  ensure_rubygems_source
@@ -62,7 +58,7 @@ module SctCore
62
58
  end
63
59
 
64
60
  def self.update_command(gem_name: "sct")
65
- "sudo gem install #{gem_name.downcase}"
61
+ "sudo gem update #{gem_name.downcase}"
66
62
  end
67
63
 
68
64
  def self.fetch_latest(gem_name)
@@ -1,3 +1,2 @@
1
- require_relative 'shell/tools'
2
1
  require_relative 'shell/runner'
3
- require_relative 'shell/module'
2
+ require_relative 'shell/module'
@@ -7,8 +7,8 @@ module Shell
7
7
  self.new.run
8
8
  end
9
9
 
10
- def run
10
+ def run
11
11
  Shell::Runner.new.launch
12
12
  end
13
13
  end
14
- end
14
+ end
@@ -4,6 +4,6 @@ module Shell
4
4
 
5
5
  # import the helper functionality from SCT
6
6
  Helpers = Sct::Helper
7
- UI = Sct::UI
7
+ UI = Sct::UI
8
8
 
9
- end
9
+ end
@@ -1,34 +1,83 @@
1
+ require 'yaml'
2
+
1
3
  module Shell
2
4
  class Runner
3
- # define launch work
4
- def launch
5
-
6
- tool_name = ARGV.first ? ARGV.first.downcase : nil
7
-
8
- if tool_name && Shell::TOOLS.include?(tool_name.to_sym)
9
-
10
- require_relative "docker/#{tool_name}"
11
- command = "#{ARGV[1..(ARGV.length+1)].join(" ")}"
12
-
13
- case ARGV.first
14
- when 'php'
15
- Shell::Php.exec(command)
16
- when 'composer'
17
- Shell::Composer.exec(command)
18
- when 'yarn'
19
- Shell::Yarn.exec(command)
20
- else
21
- show_error
22
- end
23
-
5
+
6
+ def launch
7
+ command = ARGV.join(" ")
8
+
9
+ if ! File.exist? "./okteto.yml"
10
+ error "Could not find file 'okteto.yml'."
11
+ end
12
+
13
+ manifest = YAML.load File.read "./okteto.yml"
14
+
15
+ deployment = manifest["name"]
16
+
17
+ pod = find_pod deployment
18
+
19
+ if command.empty?
20
+ system "kubectl exec #{pod} -it -- sh", { in: :in, out: :out, err: :err }
24
21
  else
25
- show_error
22
+ system "kubectl exec #{pod} -it -- #{command}", { in: :in, out: :out, err: :err }
23
+ end
24
+ end
25
+
26
+ def find_pod deployment
27
+ output = `kubectl get pods --show-labels`
28
+
29
+ # split output lines
30
+ lines = output.split "\n"
31
+
32
+ # exclude first line (table header)
33
+ lines = lines[1..-1]
34
+
35
+ # get the name and labels of each pod
36
+ pods = lines.map do |line|
37
+ columns = line.split " "
38
+
39
+ name = columns[0]
40
+
41
+ labels = columns[5].split(",").reduce({}) do |labels, label|
42
+ key, value = label.split "="
43
+ labels[key] = value
44
+ labels
45
+ end
46
+
47
+ {
48
+ name: name,
49
+ labels: labels
50
+ }
26
51
  end
52
+
53
+ # filter by deployment
54
+ pods = pods.filter { |pod| pod[:labels]["app"] == deployment }
55
+
56
+ if pods.length == 0
57
+ error "Could not find pod for deployment #{deployment}."
58
+ elsif pods.length > 1
59
+ error "Found more than one pod for deployment #{deployment}. Multiple pods are not supported."
60
+ end
61
+
62
+ pod = pods.first
63
+
64
+ if pod[:labels]["dev.okteto.com"] != "true"
65
+ print "The current pod is running a production image and was not started by Okteto. Are you sure you want to continue? [y/N] ".red
66
+
67
+ answer = $stdin.readline.chomp.downcase
68
+
69
+ if answer != "y"
70
+ exit
71
+ end
72
+ end
73
+
74
+ pod[:name]
27
75
  end
28
76
 
29
- def show_error
30
- tools = Shell::TOOLS.map { |tool| tool.to_s }.join(", ")
31
- UI.error("Tool not found. Try one of these: #{tools}")
77
+ def error message
78
+ UI.error message
79
+ exit 1
32
80
  end
81
+
33
82
  end
34
- end
83
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.25
4
+ version: 0.1.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reshad Farid
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-20 00:00:00.000000000 Z
11
+ date: 2020-11-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colored
@@ -227,17 +227,10 @@ files:
227
227
  - sct_core/lib/sct_core/ui/interface.rb
228
228
  - sct_core/lib/sct_core/ui/ui.rb
229
229
  - sct_core/lib/sct_core/update_checker/update_checker.rb
230
- - shell/README.md
231
230
  - shell/lib/shell.rb
232
- - shell/lib/shell/ClassLevelInheritableAttributes.rb
233
231
  - shell/lib/shell/commands_generator.rb
234
- - shell/lib/shell/docker/composer.rb
235
- - shell/lib/shell/docker/docker.rb
236
- - shell/lib/shell/docker/php.rb
237
- - shell/lib/shell/docker/yarn.rb
238
232
  - shell/lib/shell/module.rb
239
233
  - shell/lib/shell/runner.rb
240
- - shell/lib/shell/tools.rb
241
234
  homepage: https://gitlab.com/proactive-software/packages/sct
242
235
  licenses:
243
236
  - MIT
@@ -248,10 +241,10 @@ metadata:
248
241
  post_install_message:
249
242
  rdoc_options: []
250
243
  require_paths:
244
+ - shell/lib
251
245
  - cluster/lib
252
246
  - sct/lib
253
247
  - sct_core/lib
254
- - shell/lib
255
248
  required_ruby_version: !ruby/object:Gem::Requirement
256
249
  requirements:
257
250
  - - ">="
@@ -263,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
263
256
  - !ruby/object:Gem::Version
264
257
  version: '0'
265
258
  requirements: []
266
- rubygems_version: 3.0.6
259
+ rubygems_version: 3.1.2
267
260
  signing_key:
268
261
  specification_version: 4
269
262
  summary: Spend Cloud Tool.
File without changes
@@ -1,25 +0,0 @@
1
- module ClassLevelInheritableAttributes
2
- def self.included(base)
3
- base.extend(ClassMethods)
4
- end
5
-
6
- module ClassMethods
7
- def inheritable_attributes(*args)
8
- @inheritable_attributes ||= [:inheritable_attributes]
9
- @inheritable_attributes += args
10
- args.each do |arg|
11
- class_eval %(
12
- class << self; attr_accessor :#{arg} end
13
- )
14
- end
15
- @inheritable_attributes
16
- end
17
-
18
- def inherited(subclass)
19
- @inheritable_attributes.each do |inheritable_attribute|
20
- instance_var = "@#{inheritable_attribute}"
21
- subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
22
- end
23
- end
24
- end
25
- end
@@ -1,16 +0,0 @@
1
- require "sct_core"
2
- require_relative "docker"
3
-
4
- module Shell
5
- class Composer < Docker
6
-
7
- # Configure the Yarn command
8
- def self.config
9
- self.set_image("eu.gcr.io/dev-pasc-vcdm/helpers-composer:latest", true)
10
- self.set_pwd_as_volume("/app")
11
- self.add_volume(SctCore::Helper.convertWSLToWindowsPath("#{SctCore::Helper.windowsHomePath || SctCore::Helper.homePath}/.composer") , "/tmp")
12
- self.set_current_user_and_group()
13
- self.set_entrypoint("composer")
14
- end
15
- end
16
- end
@@ -1,218 +0,0 @@
1
- require "sct_core"
2
- require "shell/ClassLevelInheritableAttributes"
3
-
4
- module Shell
5
- class Docker
6
- include ClassLevelInheritableAttributes
7
- inheritable_attributes :image, :is_private_registry, :entrypoint, :volumes, :ports, :extra_arguments, :env_variables
8
-
9
- @image = nil
10
- @is_private_registry = false
11
- @entrypoint = nil
12
-
13
- @volumes = {}
14
- @ports = {}
15
- @user_group = []
16
- @extra_arguments = {}
17
- @env_variables = {}
18
-
19
- ###
20
- # The Docker command configuration. This has to be able to execute the command properly
21
- ###
22
- def self.config
23
- # Run some initialization commands
24
- end
25
-
26
- ###
27
- # Execute the configured command
28
- ###
29
- def self.exec(cli_arguments)
30
-
31
- self.add_extra_argument(cli_arguments)
32
-
33
- self.config
34
-
35
- # Check if the basic variables are set
36
- if !@image || @image.empty?
37
- raise LoadError, "The required image is not defined for this command"
38
- end
39
-
40
- if !self.check_for_image && @is_private_registry
41
- unless self.login_to_private_registry
42
- raise RuntimeError, "Could not authenticate to GCR (" + $?.exitstatus + ")"
43
- end
44
- end
45
-
46
- self.run_command
47
- end
48
-
49
- ###
50
- # The image for this Docker command
51
- ###
52
- def self.set_image(image, is_private_registry=false)
53
- @image = image
54
- @is_private_registry = is_private_registry
55
- end
56
-
57
- ###
58
- # Set the current PWD as a volume on the specified path in the container
59
- ###
60
- def self.set_pwd_as_volume(volume_path)
61
- pwd = `pwd -P`
62
-
63
- if SctCore::Helper.operatingSystem == SctCore::Helper::WINDOWS
64
- pwd=SctCore::Helper.convertWSLToWindowsPath(pwd)
65
- end
66
-
67
- add_volume(pwd, volume_path)
68
- end
69
-
70
- ###
71
- # Add an extra volume in the container
72
- ###
73
- def self.add_volume(local_path, volume_path)
74
- @volumes[local_path] = volume_path
75
- end
76
-
77
- ###
78
- # Add a port mapping for the container
79
- ###
80
- def self.map_port(external_port, container_port = nil)
81
-
82
- external_port=String(external_port)
83
- container_port=String(container_port)
84
-
85
- if container_port.empty?
86
- container_port = external_port
87
- end
88
-
89
- @ports[external_port] = container_port
90
- end
91
-
92
- ###
93
- # Set the current user and group in the container
94
- ###
95
- def self.set_current_user_and_group
96
- @user_group = []
97
- @user_group << `id -u`
98
- @user_group << `id -g`
99
- end
100
-
101
- ###
102
- # Set the entrypoint for the command in the container
103
- ###
104
- def self.set_entrypoint(entrypoint)
105
- @entrypoint=entrypoint
106
- end
107
-
108
- ###
109
- # Add extra arguments to be configured for the container
110
- ###
111
- def self.add_extra_argument(argument, value=nil)
112
- argument = String(argument)
113
-
114
- if value
115
- value = String(value)
116
- end
117
-
118
- self.extra_arguments[argument] = value
119
- end
120
-
121
- ###
122
- # Set environment variables for the container
123
- ###
124
- def self.set_environment_variables(env_variables)
125
- @env_variables = env_variables
126
- end
127
-
128
- ###
129
- # Check if the image is already present in the system
130
- ###
131
- def self.check_for_image
132
- image_list=`docker images -q #{@image} 2> /dev/null`
133
-
134
- return image_list && !image_list.empty?
135
- end
136
-
137
- ###
138
- # Login to the private container registry with the cloud credentials
139
- ###
140
- def self.login_to_private_registry
141
- `docker login -u oauth2accesstoken -p "$(gcloud auth application-default print-access-token)" https://eu.gcr.io &> /dev/null`
142
- return $?.success?
143
- end
144
-
145
- ###
146
- # Run the command
147
- ###
148
- def self.run_command
149
- command = self.compile_command
150
-
151
- SctCore::CommandExecutor.execute(command: command, print_all: true, suppress_output: false)
152
- end
153
-
154
- ###
155
- # Compile the command with all options
156
- ###
157
- def self.compile_command
158
- # Basic docker run command
159
- command = self.add_to_command_string("" , "docker run --rm -it")
160
-
161
- # Attach environment variables
162
- if @env_variables
163
- @env_variables.each do |key, value|
164
- if value && !value.empty?
165
- command = self.add_to_command_string(command, "-e " + key+"="+value)
166
- else
167
- command = self.add_to_command_string("-e " + key, value)
168
- end
169
- end
170
- end
171
-
172
- # Attach configured volumes
173
- if @volumes
174
- @volumes.each do |local_path, container_path|
175
- command = self.add_to_command_string(command, "--volume " + local_path +":"+ container_path)
176
- end
177
- end
178
-
179
- # Map configured ports
180
- if @ports
181
- @ports.each do |external_port, container_port|
182
- command = self.add_to_command_string(command, "-p " + external_port +":"+ container_port)
183
- end
184
- end
185
-
186
- if @user_group
187
- command = self.add_to_command_string(command, "--user "+ String(@user_group.shift) +":"+ String(@user_group.shift))
188
- end
189
-
190
- # Add image to command
191
- command = self.add_to_command_string(command, @image)
192
-
193
- if @entrypoint
194
- command = self.add_to_command_string(command, String(@entrypoint))
195
- end
196
-
197
- # Append arguments and options to command
198
- if @extra_arguments
199
- @extra_arguments.each do |argument, value|
200
- if value && !value.empty?
201
- command = self.add_to_command_string(command, argument+"="+value)
202
- else
203
- command = self.add_to_command_string(command, argument)
204
- end
205
- end
206
- end
207
-
208
- return command
209
- end
210
-
211
- ###
212
- # Append a part to the command string and remove any unwanted characters
213
- ###
214
- def self.add_to_command_string(command_string, append)
215
- return command_string + append.gsub(/\r?\n/, "") + " "
216
- end
217
- end
218
- end
@@ -1,52 +0,0 @@
1
- require "sct_core"
2
-
3
- require_relative "docker"
4
-
5
- module Shell
6
- class Php < Docker
7
-
8
- attr_accessor :make
9
-
10
- # Configure the Yarn command
11
- def self.config
12
- self.set_image("eu.gcr.io/dev-pasc-vcdm/proactive-base:latest", true)
13
- self.set_pwd_as_volume("/var/www")
14
- self.set_current_user_and_group
15
- self.set_entrypoint("php")
16
- self.set_environment_variables(get_service_ip_and_port)
17
- end
18
-
19
- def self.get_service_ip_and_port
20
- service_names = %w[mysql-service redis-service]
21
- environment_variables = {}
22
-
23
- minikube_status
24
-
25
- service_names.each { |service_name|
26
- url = `#{SctCore::Helper.minikube} service #{service_name} --url`
27
-
28
- ip_and_port = url.match /(?<ip>[0-9]+(?:\.[0-9]+){3}):(?<port>[0-9]+)/
29
-
30
- case service_name
31
- when "mysql-service"
32
- environment_variables.store("DB_HOST", ip_and_port[:ip])
33
- environment_variables.store("DB_PORT", ip_and_port[:port])
34
- when "redis-service"
35
- environment_variables.store("REDIS_HOST", ip_and_port[:ip])
36
- environment_variables.store("REDIS_PORT", ip_and_port[:port])
37
- end
38
- }
39
-
40
- return environment_variables
41
- end
42
-
43
- def self.minikube_status
44
- output = `#{SctCore::Helper.minikube} status`
45
-
46
- if output.scan(/Running/).length != 3 && output.scan(/Configured/).length != 1
47
- UI.important("Please check your minikube status. If all services are stopped you should start the minikube first.")
48
- exit
49
- end
50
- end
51
- end
52
- end
@@ -1,17 +0,0 @@
1
- require "sct_core"
2
- require_relative "docker"
3
-
4
- module Shell
5
- class Yarn < Docker
6
-
7
- # Configure the Yarn command
8
- def self.config
9
- self.set_image("eu.gcr.io/dev-pasc-vcdm/helpers-yarn:latest", true)
10
- self.set_pwd_as_volume("/app")
11
- self.add_volume(SctCore::Helper.convertWSLToWindowsPath("#{SctCore::Helper.windowsHomePath || SctCore::Helper.homePath}/.cache") , "/.cache")
12
- self.map_port(8081, 8080)
13
- self.map_port(9001)
14
- self.set_current_user_and_group()
15
- end
16
- end
17
- end
@@ -1,7 +0,0 @@
1
- module Shell
2
- TOOLS = [
3
- :yarn,
4
- :composer,
5
- :php
6
- ]
7
- end