sct 0.1.28 → 0.1.29

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: 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