sct 0.1.28 → 0.1.29

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
  SHA256:
3
- metadata.gz: 2795077123ba193f891933659f88c61cb4a986ebc4a5c7bf8ced2fd9b9b54a97
4
- data.tar.gz: 8478af6c3a869f524b09bc607ae09acbc48eed401777366947fc270a39166a2b
3
+ metadata.gz: d96c99f55b060e2403cbc2e63dc4559bb14bb7fe7a3204c30c50591688a9ea3c
4
+ data.tar.gz: fe5f3c027f2a334a83f31fc9ab11c43f85898db0fb1d04395bbb74fdd14b74ec
5
5
  SHA512:
6
- metadata.gz: deecf2931622dda191ee00ffc6412a41c7aa4ac8df88006f8eeab183c8d50c543fb2d25f5012c47157f0faa1208431d450716e9b6f50506991aaa1a5f3e95dbc
7
- data.tar.gz: afcf8914cbd3efba0e46764b5ed8633f570ec2e9b272a70a28cf48d11fd29bd41beaa1b9cd4896a263f99d657835fccb5329a245a160a009a47f17a4915589cb
6
+ metadata.gz: 4608475ca7570f3422afc13eaf43c0d8429304e667e688ebfa90a3bc26f168a062e45122d22794615c1824a740dbcb501bc9f0b6175083a60dbc6b89606d5a25
7
+ data.tar.gz: 8a5c1afac5d76c0fb820ee84d1edd9896a6c5bb51be0359600d4202bba035d1052ae18a1ffd6e9870e7c285952b230ecbf8e9dda6f2970e67ca2154b61ae1766
@@ -9,74 +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
38
  command :restart do |c|
46
-
47
- c.syntax = 'sct cluster restart'
48
- c.description = 'restart the cluster (this is a short hand for sct cluster down && sct cluster up)'
39
+ c.syntax = "sct cluster restart"
40
+ c.description = "restart the cluster"
49
41
 
50
42
  c.action do |args, options|
51
- Cluster::Runner.new.down
52
- Cluster::Runner.new.launch
43
+ Cluster::Runner.new.restart
53
44
  end
45
+
54
46
  end
55
47
 
56
- command :reset do |c|
48
+ command :delete do |c|
49
+ c.syntax = "sct cluster delete"
50
+ c.description = "delete the cluster"
57
51
 
52
+ c.action do |args, options|
53
+ Cluster::Runner.new.delete
54
+ end
55
+
56
+ end
57
+
58
+ command :reset do |c|
58
59
  c.syntax = 'sct cluster reset'
59
- c.description = 'reset your cluster and start with a clean cluster'
60
+ c.description = 'delete the cluster and start a new cluster'
60
61
 
61
- c.action do |args, options|
62
+ c.action do |args, options|
62
63
  Cluster::Runner.new.reset
63
64
  end
64
65
  end
65
66
 
66
- alias_command :'setup', :'reset'
67
-
68
67
  command :status do |c|
69
-
70
68
  c.syntax = 'sct cluster status'
71
69
  c.description = 'see the status of your cluster'
72
70
 
73
- c.action do |args, options|
71
+ c.action do |args, options|
74
72
  Cluster::Runner.new.status
75
73
  end
76
74
  end
77
75
 
78
76
  command :'update config' do |c|
79
-
80
77
  c.syntax = 'sct cluster update config'
81
78
  c.description = 'update the cluster configuration'
82
79
 
@@ -85,36 +82,16 @@ module Cluster
85
82
  end
86
83
  end
87
84
 
88
- command :'delete pods' do |c|
89
- c.syntax = 'sct cluster delete stalled pods'
90
- c.description = 'delete stalled pods from the cluster'
91
- c.option '--stalled', 'delete stalled pods'
92
- c.option '--all', 'delete all pods'
93
-
94
- c.action do |args, options|
95
-
96
- Cluster::Runner.new.delete_stalled_pods if options.stalled
97
- Cluster::Runner.new.delete_all_pods if options.all
98
-
99
- Cluster::Runner.new.delete_pods(args) if !args.empty?
100
-
101
- end
102
- end
103
-
104
- command :'apply pods' do |c|
105
- c.syntax = 'sct cluster apply pods'
106
- 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'
107
88
 
108
89
  c.action do |args, options|
109
-
110
- Cluster::Runner.new.apply_pods
111
-
90
+ Cluster::Runner.new.apply_deployments
112
91
  end
113
92
  end
114
93
 
115
- default_command :status
116
-
117
94
  run!
118
95
  end
119
96
  end
120
- 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,157 @@
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
24
101
  run_command "sudo sct hostfile"
102
+ run_command "minikube tunnel &", { out: "/dev/null", err: "/dev/null" } if SctCore::Helper::is_windows? # leave this running detached forever in the background
25
103
  UI.success("\n✔️ You can visit your environment at 👉 https://spend-cloud.spend.cloud.local 👌")
26
104
  end
27
105
 
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
106
  def enable_addons
47
107
  enable_addon "registry-creds"
48
108
  enable_addon "ingress"
49
109
  end
50
110
 
51
111
  def enable_addon(addon)
52
- run_command "#{SctCore::Helper.minikube} addons enable #{addon}"
112
+ run_command "minikube addons enable #{addon}"
53
113
 
54
114
  deployment = deployments("kube-system").find { |deployment| deployment[:name].include? addon }
55
115
 
56
- run_command "kubectl rollout status -n kube-system deployment/#{deployment[:name]}"
116
+ run_command "kubectl rollout status -n kube-system deployment #{deployment[:name]}"
57
117
  end
58
118
 
59
119
  def wait_for_pods
60
120
  UI.important("Waiting for pods to become ready...")
61
121
 
62
- while ! pods.all? { |pod| pod[:status] == "Running" }
63
- delete_stalled_pods
64
-
65
- sleep 5
66
- end
67
-
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?
74
-
75
- stalled_pods = pods.select { |pod| pod[:stalled] }
122
+ previous_lines = 0
76
123
 
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
124
+ while ! pods.all? { |pod| pod[:ready] }
125
+ pods_status_lines = get_pods_status.to_s.lines.map { |line| line.chomp }
83
126
 
84
- def delete_all_pods
85
- run_command "kubectl delete pods --all"
86
- end
127
+ current_lines = pods_status_lines.length
87
128
 
88
- def delete_pods(args)
89
- run_command "kubectl delete pods #{args.join(" ")}"
90
- end
129
+ line_difference = current_lines - previous_lines
91
130
 
92
- def apply_pods
93
- run_command "kubectl apply -f ~/development/spend-cloud/k8s/"
94
- end
131
+ if line_difference < 0 # there are now less lines than before
132
+ line_difference.abs.times do
133
+ print "\033[1A\033[K" # move the cursor up a line and clear the line
134
+ end
95
135
 
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"
136
+ print "\033[#{current_lines}A" # move the cursor all the way up to the start of the table
137
+ elsif previous_lines > 0
138
+ print "\033[#{previous_lines}A" # move the cursor all the way up to the start of the table
139
+ end
100
140
 
101
- if !File.exists?(kube_file_path)
102
- return UI.error("#{kube_file_path} doesn't exist")
141
+ pods_status_lines.each do |line|
142
+ print "#{line}\033[K#{$/}" # print the content of the line, clear remaining characters and add a new line
103
143
  end
104
144
 
105
- run_command "sed -e 's~\\\\~/~g' -e 's~C:~/mnt/c~g' < #{kube_file_path} > ~/.kube/minikube-config"
145
+ previous_lines = current_lines
106
146
 
107
- UI.success("#{kube_file_path} copied to ~/.kube/minikube-config")
147
+ sleep 5
108
148
  end
109
149
 
110
- run_command "kubectl config use-context minikube"
150
+ previous_lines.times do
151
+ print "\033[1A\033[K" # move the cursor up a line and clear the line
152
+ end
111
153
 
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"
154
+ UI.success("Pods are now ready.")
116
155
  end
117
156
 
118
157
  def deployments(namespace = "default")
@@ -150,13 +189,15 @@ module Cluster
150
189
  columns = line.split(" ")
151
190
 
152
191
  name = columns[0]
192
+ ready = columns[1].split("/").reduce { |l, r| l == r }
193
+ replicas = columns[1]
153
194
  status = columns[2]
154
- stalled = status == "ErrImagePull" || status == "ImagePullBackOff"
155
195
 
156
196
  {
157
197
  name: name,
158
- status: status,
159
- stalled: stalled
198
+ ready: ready,
199
+ replicas: replicas,
200
+ status: status
160
201
  }
161
202
  end
162
203
  end
@@ -193,18 +234,6 @@ module Cluster
193
234
  UI.success("Ingress IP is now available.")
194
235
  end
195
236
 
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
237
  def print_contexts
209
238
  output = `kubectl config get-contexts`
210
239
 
@@ -223,12 +252,11 @@ module Cluster
223
252
  end
224
253
 
225
254
  def print_minikube_status
226
-
227
255
  puts Terminal::Table.new title: "Minikube status".green, headings: ['Name', 'Status'], rows: get_minikube_status
228
256
  end
229
257
 
230
258
  def get_minikube_status
231
- output = `#{SctCore::Helper.minikube} status`
259
+ output = `minikube status`
232
260
 
233
261
  lines = output.split "\n"
234
262
 
@@ -240,25 +268,32 @@ module Cluster
240
268
  end
241
269
 
242
270
  def print_pods_status(namespace = "default")
271
+ output = get_pods_status(namespace)
243
272
 
244
- pods_list = pods(namespace)
273
+ puts output if output
274
+ end
245
275
 
246
- if pods_list.to_a.empty?
247
- return
248
- end
276
+ def get_pods_status(namespace = "default")
277
+ rows = pods(namespace).map do |pod|
278
+ status = pod[:status]
279
+ replicas = pod[:replicas]
249
280
 
250
- rows = pods_list.map do |pod|
251
281
  [
252
282
  pod[:name],
253
- pod[:status] == "Running" ? pod[:status].green : pod[:status].red
283
+ status == "Running" ? status.green : status.red,
284
+ pod[:ready] ? replicas.green : replicas.red
254
285
  ]
255
286
  end
256
287
 
257
- puts Terminal::Table.new title: "Pods (namespace: #{namespace})".green, headings: ['Name', 'Status'], rows: rows
288
+ if rows.empty?
289
+ return
290
+ end
291
+
292
+ return Terminal::Table.new title: "Pods (namespace: #{namespace})".green, headings: ['Name', 'Status', 'Replicas ready'], rows: rows
258
293
  end
259
294
 
260
- def run_command command
261
- if ! system command
295
+ def run_command command, options = {}
296
+ if ! system command, options
262
297
  raise command.red
263
298
  end
264
299
  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,17 +33,17 @@ 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
@@ -67,4 +67,4 @@ module Sct
67
67
  run!
68
68
  end
69
69
  end
70
- end
70
+ end
@@ -1,3 +1,3 @@
1
1
  module Sct
2
- VERSION = "0.1.28"
2
+ VERSION = "0.1.29"
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.28
4
+ version: 0.1.29
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-10-15 00:00:00.000000000 Z
11
+ date: 2020-10-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
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,60 +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(self.get_environment_variables)
17
- end
18
-
19
- def self.get_environment_variables
20
- environment_variables = {}
21
- environment_variables.store("ENVIRONMENT", "local")
22
-
23
- environment_variables = self.add_service_ip_and_port(environment_variables)
24
-
25
- return environment_variables
26
- end
27
-
28
- def self.add_service_ip_and_port(environment_variables)
29
- service_names = %w[mysql-service redis-service]
30
-
31
- minikube_status
32
-
33
- service_names.each { |service_name|
34
- url = `#{SctCore::Helper.minikube} service #{service_name} --url`
35
-
36
- ip_and_port = url.match /(?<ip>[0-9]+(?:\.[0-9]+){3}):(?<port>[0-9]+)/
37
-
38
- case service_name
39
- when "mysql-service"
40
- environment_variables.store("DB_HOST", ip_and_port[:ip])
41
- environment_variables.store("DB_PORT", ip_and_port[:port])
42
- when "redis-service"
43
- environment_variables.store("REDIS_HOST", ip_and_port[:ip])
44
- environment_variables.store("REDIS_PORT", ip_and_port[:port])
45
- end
46
- }
47
-
48
- return environment_variables
49
- end
50
-
51
- def self.minikube_status
52
- output = `#{SctCore::Helper.minikube} status`
53
-
54
- if output.scan(/Running/).length != 3 && output.scan(/Configured/).length != 1
55
- UI.important("Please check your minikube status. If all services are stopped you should start the minikube first.")
56
- exit
57
- end
58
- end
59
- end
60
- 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