sct 0.1.35 → 1.0.0

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: 730e908365c08b32f6c0bcffce79d1497b2139190f68980cb2c3d340a233dee8
4
- data.tar.gz: 813a1f8db688ecd7ad902bf87d2415c4000933c2aac86957d08b43fe0513a8e5
3
+ metadata.gz: 8be150a1d5ddc9339df696d2f7db5d6056dfdba0fbb48884e57cfacc700b79ea
4
+ data.tar.gz: d6fc67a9a3af7c51bf542353f476ec59b60f1c40e7387da64910c4287be857c7
5
5
  SHA512:
6
- metadata.gz: 2e813fe74dd20bc360a2644cf57bf4731b122b0916e4ccfb64259fad0e69d9f5238741b9eafcd6fa0b1a523dbd5f617b83d55dee709a61ce290fdf07e47b8031
7
- data.tar.gz: ab9e05165e62681cb5a851eac335320ef44030351482ab7307a36fad1b900f6fe8036a10b72d593d88c6d6edd3e2fc3b3b7c5a7fda5daae5484e77606ecab0f9
6
+ metadata.gz: e5046d7b3acb18f4cce8b17b7a8d32586758dfda47ba696b7e0f36192fd5b51d132fe2a770768410728279c08b70ebfeb263a79b82bad5531d889b3fe0b733cc
7
+ data.tar.gz: 3502a15df6d47b547af6dc7a15cd175a23f45700c6771ccf66055542d2df2d21baadb7c26c03c0736d469ead3108c5b09f968adc318c1d572fa036fea047f454
@@ -2,96 +2,101 @@ require 'commander'
2
2
  require_relative 'runner'
3
3
 
4
4
  module Cluster
5
- class CommandsGenerator
6
- include Commander::Methods
5
+ class CommandsGenerator
6
+ include Commander::Methods
7
7
 
8
- def self.start
9
- self.new.run
10
- end
11
-
12
- def run
13
- program :name, 'cluster'
14
- program :version, Sct::VERSION
15
- program :description, 'CLI for \'cluster\' - Manage your local kubernetes cluster'
16
-
17
- global_option('--verbose') { $verbose = true }
18
-
19
- command :start do |c|
20
- c.syntax = "sct cluster start"
21
- c.description = "start the cluster"
22
-
23
- c.action do |args, options|
24
- Cluster::Runner.new.start
25
- end
26
-
27
- end
28
-
29
- command :stop do |c|
30
- c.syntax = 'sct cluster stop'
31
- c.description = 'stop the cluster'
8
+ def self.start
9
+ self.new.run
10
+ end
32
11
 
33
- c.action do |args, options|
34
- Cluster::Runner.new.stop
35
- end
36
- end
12
+ def run
13
+ program :name, 'cluster'
14
+ program :version, Sct::VERSION
15
+ program :description, 'CLI for \'cluster\' - Manage your local Docker cluster'
37
16
 
38
- command :restart do |c|
39
- c.syntax = "sct cluster restart"
40
- c.description = "restart the cluster"
17
+ global_option('--verbose') { $verbose = true }
41
18
 
42
- c.action do |args, options|
43
- Cluster::Runner.new.restart
44
- end
19
+ command :start do |c|
20
+ c.syntax = "sct cluster start"
21
+ c.description = "start the cluster"
22
+ c.option '--build', '(re)build images before starting'
23
+ c.option '--pull', 'pull latest images before starting'
45
24
 
46
- end
25
+ c.action do |args, options|
26
+ Cluster::Runner.new.start args, options
27
+ end
28
+ end
47
29
 
48
- command :delete do |c|
49
- c.syntax = "sct cluster delete"
50
- c.description = "delete the cluster"
30
+ command :stop do |c|
31
+ c.syntax = 'sct cluster stop'
32
+ c.description = 'stop the cluster'
51
33
 
52
- c.action do |args, options|
53
- Cluster::Runner.new.delete
54
- end
34
+ c.action do |args, options|
35
+ Cluster::Runner.new.stop
36
+ end
37
+ end
55
38
 
56
- end
39
+ command :restart do |c|
40
+ c.syntax = "sct cluster restart"
41
+ c.description = "restart the cluster"
57
42
 
58
- command :reset do |c|
59
- c.syntax = 'sct cluster reset'
60
- c.description = 'delete the cluster and start a new cluster'
43
+ c.action do |args, options|
44
+ Cluster::Runner.new.restart
45
+ end
46
+ end
61
47
 
62
- c.action do |args, options|
63
- Cluster::Runner.new.reset
64
- end
65
- end
48
+ command :delete do |c|
49
+ c.syntax = "sct cluster delete"
50
+ c.description = "delete the cluster"
66
51
 
67
- command :status do |c|
68
- c.syntax = 'sct cluster status'
69
- c.description = 'see the status of your cluster'
52
+ c.action do |args, options|
53
+ Cluster::Runner.new.delete
54
+ end
55
+ end
70
56
 
71
- c.action do |args, options|
72
- Cluster::Runner.new.status
73
- end
74
- end
57
+ command :reset do |c|
58
+ c.syntax = 'sct cluster reset'
59
+ c.description = 'delete the cluster and start a new cluster'
75
60
 
76
- command :'update config' do |c|
77
- c.syntax = 'sct cluster update config'
78
- c.description = 'update the cluster configuration'
61
+ c.action do |args, options|
62
+ Cluster::Runner.new.reset args, options
63
+ end
64
+ end
79
65
 
80
- c.action do |args, options|
81
- Cluster::Runner.new.update_config
82
- end
83
- end
66
+ command :pull do |c|
67
+ c.syntax = 'sct cluster pull'
68
+ c.description = 'pull new image versions'
84
69
 
85
- command :'apply deployments' do |c|
86
- c.syntax = 'sct cluster apply deployments'
87
- c.description = 'apply deployments from the k8s folder'
70
+ c.action do |args, options|
71
+ Cluster::Runner.new.pull
72
+ end
73
+ end
88
74
 
89
- c.action do |args, options|
90
- Cluster::Runner.new.apply_deployments
91
- end
92
- end
75
+ command :status do |c|
76
+ c.syntax = 'sct cluster status'
77
+ c.description = 'see the status of your cluster'
93
78
 
94
- run!
79
+ c.action do |args, options|
80
+ Cluster::Runner.new.status
81
+ end
82
+ end
83
+
84
+ command :logs do |c|
85
+ c.syntax = 'sct cluster logs'
86
+ c.description = 'see the logs of your cluster'
87
+ c.option '-f', 'follow log output'
88
+ c.option '--follow', 'follow log output'
89
+ c.option '-t', 'show timestamps'
90
+ c.option '--timestamps', 'show timestamps'
91
+ c.option '--tail LINES', 'number of lines to show from the end of the logs for each container (default: "all")'
92
+
93
+ c.action do |args, options|
94
+ Cluster::Runner.new.logs args, options
95
95
  end
96
+ end
97
+
98
+ run!
96
99
  end
100
+
101
+ end
97
102
  end
@@ -1,343 +1,73 @@
1
1
  module Cluster
2
- class Runner
2
+ class Runner
3
3
 
4
- def start
5
- SctCore::Helper.ensure_windows_administrator # "sct hostfile" will need it later on
6
-
7
- existing_cluster = cluster_exists?
8
-
9
- start_cluster
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
- create_keycloak_database_user
23
- run_command "kubectl apply -f ~/development/spend-cloud/k8s/keycloak-server.yml"
24
- wait_for_pods
25
- run_command "kubectl apply -f ~/development/spend-cloud/k8s/"
26
- end
27
-
28
- post_start
29
- end
30
-
31
- def stop
32
- run_command "minikube stop"
33
- end
34
-
35
- def restart
36
- SctCore::Helper.ensure_windows_administrator # "sct hostfile" will need it later on
37
-
38
- stop
39
- start
40
- end
41
-
42
- def delete
43
- run_command "minikube delete"
44
- end
45
-
46
- def reset
47
- SctCore::Helper.ensure_windows_administrator # "sct hostfile" will need it later on
48
-
49
- delete
50
- start
51
- end
52
-
53
- def status
54
- print_contexts
55
- print_minikube_status
56
-
57
- if get_minikube_status.find_all { |status| status[1] == 'Stopped' }.count == 0
58
- print_pods_status("kube-system")
59
- print_pods_status
60
- else
61
- UI.important("Please check your minikube status. If all services are stopped you should start the minikube first.")
62
- end
63
- end
64
-
65
- def update_config
66
- run_command "kubectl config use-context minikube"
67
-
68
- run_command "kubectl replace -n kube-system -f #{File.expand_path('resources/corefile.yml', __dir__)}"
69
- run_command "kubectl rollout restart -n kube-system deployment coredns"
70
- run_command "kubectl rollout status -n kube-system deployment coredns"
71
- end
72
-
73
- def apply_deployments
74
- run_command "kubectl apply -f ~/development/spend-cloud/k8s/"
75
- end
76
-
77
-
78
- def cluster_exists?
79
- if system "minikube status", { out: "/dev/null" }
80
- # cluster exists and is running
81
- return true
82
- end
83
-
84
- if $?.exitstatus == 85
85
- # cluster does not exist
86
- return false
87
- end
88
-
89
- # cluster exists but is stopped
90
- return true
91
- end
92
-
93
- def start_cluster
94
- if SctCore::Helper.operatingSystem == SctCore::Helper::MAC_OS
95
- run_command "minikube start --driver=hyperkit --vm=true --cpus=$(sysctl -n hw.ncpu) --memory=8G"
96
- else
97
- run_command "minikube start --driver=docker --cpus=$(cat /proc/cpuinfo | grep processor | wc -l) --memory=3G"
98
- end
99
- update_config
100
- end
101
-
102
- def post_start
103
- wait_for_pods
104
- copy_proactive_accounts_file
105
- if SctCore::Helper.operatingSystem == SctCore::Helper::UBUNTU
106
- UI.success("\nAdding SSH tunnel to port 443!")
107
- run_command "sudo ssh -f -N -i $(minikube ssh-key) docker@$(minikube ip) -L 443:127.0.0.1:443"
108
- end
109
- # run_command "sudo sct hostfile"
110
- run_command "minikube tunnel &", { out: "/dev/null", err: "/dev/null" } if SctCore::Helper::is_windows? # leave this running detached forever in the background
111
- UI.success("\n✔️ You can visit your environment at 👉 https://spend-cloud.dev.spend.cloud 👌")
112
- end
113
-
114
- def enable_addons
115
- enable_addon "registry-creds"
116
- enable_addon "ingress"
117
- end
118
-
119
- def enable_addon(addon)
120
- run_command "minikube addons enable #{addon}"
121
-
122
- deployment = deployments("kube-system").find { |deployment| deployment[:name].include? addon }
123
-
124
- run_command "kubectl rollout status -n kube-system deployment #{deployment[:name]}"
125
- end
126
-
127
- def wait_for_pods
128
- UI.important("Waiting for pods to become ready...")
129
-
130
- previous_lines = 0
131
-
132
- while ! pods.all? { |pod| pod[:ready] }
133
- pods_status_lines = get_pods_status.to_s.lines.map { |line| line.chomp }
134
-
135
- current_lines = pods_status_lines.length
136
-
137
- line_difference = current_lines - previous_lines
138
-
139
- if line_difference < 0 # there are now less lines than before
140
- line_difference.abs.times do
141
- print "\033[1A\033[K" # move the cursor up a line and clear the line
142
- end
143
-
144
- print "\033[#{current_lines}A" # move the cursor all the way up to the start of the table
145
- elsif previous_lines > 0
146
- print "\033[#{previous_lines}A" # move the cursor all the way up to the start of the table
147
- end
148
-
149
- pods_status_lines.each do |line|
150
- print "#{line}\033[K#{$/}" # print the content of the line, clear remaining characters and add a new line
151
- end
152
-
153
- previous_lines = current_lines
154
-
155
- sleep 5
156
- end
157
-
158
- previous_lines.times do
159
- print "\033[1A\033[K" # move the cursor up a line and clear the line
160
- end
161
-
162
- UI.success("Pods are now ready.")
163
- end
164
-
165
- def deployments(namespace = "default")
166
- output = `kubectl get deployments -n #{namespace}`
167
-
168
- # split output lines
169
- lines = output.split "\n"
170
-
171
- # exclude first line (table header)
172
- lines = lines[1..-1]
173
-
174
- # get name and status of each pod
175
- lines.map do |line|
176
- columns = line.split(" ")
177
-
178
- name = columns[0]
179
-
180
- {
181
- name: name
182
- }
183
- end
184
- end
185
-
186
- def pods(namespace = "default")
187
- output = `kubectl get pods -n #{namespace}`
188
-
189
- # split output lines
190
- lines = output.split "\n"
191
-
192
- # exclude first line (table header)
193
- lines = lines[1..-1]
194
-
195
- # get name and status of each pod
196
- lines.map do |line|
197
- columns = line.split(" ")
198
-
199
- name = columns[0]
200
- ready = columns[1].split("/").reduce { |l, r| l == r }
201
- replicas = columns[1]
202
- status = columns[2]
203
-
204
- {
205
- name: name,
206
- ready: ready,
207
- replicas: replicas,
208
- status: status
209
- }
210
- end
4
+ def run command, options = {}
5
+ begin
6
+ if !system command, options
7
+ raise command.red
211
8
  end
9
+ rescue Interrupt
10
+ # user pressed Ctrl+C, do nothing
11
+ end
12
+ end
212
13
 
213
- def create_secrets
214
- run_command "kubectl create secret generic gcloud-credentials --from-file=\"$(echo ~)/.config/gcloud/application_default_credentials.json\""
215
- run_command "kubectl create secret generic -n kube-system registry-creds-dpr --from-literal DOCKER_PRIVATE_REGISTRY_PASSWORD=changeme --from-literal DOCKER_PRIVATE_REGISTRY_SERVER=changeme --from-literal DOCKER_PRIVATE_REGISTRY_USER=changeme"
216
- run_command "kubectl patch secret -n kube-system registry-creds-dpr -p='{\"metadata\": {\"labels\": { \"app\": \"registry-creds\", \"cloud\": \"dpr\", \"kubernetes.io/minikube-addons\": \"registry-creds\"}}}'"
217
- run_command "kubectl create secret generic -n kube-system registry-creds-ecr --from-literal AWS_ACCESS_KEY_ID=changeme --from-literal AWS_SECRET_ACCESS_KEY=changeme --from-literal AWS_SESSION_TOKEN=\"\" --from-literal aws-account=changeme --from-literal aws-assume-role=changeme --from-literal aws-region=changeme"
218
- run_command "kubectl patch secret -n kube-system registry-creds-ecr -p='{\"metadata\": {\"labels\": { \"app\": \"registry-creds\", \"cloud\": \"ecr\", \"kubernetes.io/minikube-addons\": \"registry-creds\"}}}'"
219
- run_command "kubectl create secret generic -n kube-system registry-creds-gcr --from-file=\"$(echo ~)/.config/gcloud/application_default_credentials.json\" --from-literal=gcrurl=\"https://eu.gcr.io\""
220
- run_command "kubectl patch secret -n kube-system registry-creds-gcr -p='{\"metadata\": {\"labels\": { \"app\": \"registry-creds\", \"cloud\": \"gcr\", \"kubernetes.io/minikube-addons\": \"registry-creds\"}}}'"
221
- run_command "kubectl create secret generic -n kube-system registry-creds-acr --from-literal ACR_PASSWORD=changeme --from-literal ACR_CLIENT_ID=changeme --from-literal ACR_URL=changeme"
222
- run_command "kubectl patch secret -n kube-system registry-creds-acr -p='{\"metadata\": {\"labels\": { \"app\": \"registry-creds\", \"cloud\": \"acr\", \"kubernetes.io/minikube-addons\": \"registry-creds\"}}}'"
223
- end
224
-
225
- def wait_for_gcr_secret
226
- UI.important("Waiting for Google Cloud Registry secret to become available...")
227
-
228
- while ! `kubectl get secrets`.include? "gcr-secret"
229
- sleep 5
230
- end
231
-
232
- UI.success("Google Cloud Registry secret is now available.")
233
- end
234
-
235
- def wait_for_ingress_ip
236
- UI.important("Waiting for ingress IP to become available...")
237
-
238
- while `kubectl describe ingress | grep "Address" | awk '{print $2}'`.empty?
239
- sleep 5
240
- end
241
-
242
- UI.success("Ingress IP is now available.")
243
- end
244
-
245
- def print_contexts
246
- output = `kubectl config get-contexts`
247
-
248
- lines = output.split "\n"
249
- lines = lines[1..-1]
250
-
251
- rows = lines.map do |line|
252
- columns = line.split(" ")
253
-
254
- current_context = columns[0] == "*" ? "Yes".green : "No".red
255
-
256
- [columns[2], current_context]
257
- end
258
-
259
- puts Terminal::Table.new title: "Contexts".green, headings: ['Cluster', 'Using context'], rows: rows
260
- end
261
-
262
- def print_minikube_status
263
- puts Terminal::Table.new title: "Minikube status".green, headings: ['Name', 'Status'], rows: get_minikube_status
264
- end
265
-
266
- def get_minikube_status
267
- output = `minikube status`
268
-
269
- lines = output.split "\n"
270
-
271
- rows = lines.map do |line|
272
- columns = line.split(" ")
273
-
274
- [columns[0][0..-2], columns[1]]
275
- end
276
- end
14
+ def run_dc command, options = {}
15
+ run "docker-compose -f ~/development/spend-cloud/docker-compose.yml #{command}", options
16
+ end
277
17
 
278
- def print_pods_status(namespace = "default")
279
- output = get_pods_status(namespace)
18
+ def start args, options
19
+ if options.pull
20
+ run_dc "pull"
21
+ end
280
22
 
281
- puts output if output
282
- end
23
+ if options.build
24
+ run_dc "build #{options.pull ? "--pull" : ""}"
25
+ end
283
26
 
284
- def get_pods_status(namespace = "default")
285
- rows = pods(namespace).map do |pod|
286
- status = pod[:status]
287
- replicas = pod[:replicas]
27
+ run_dc "up --detach"
288
28
 
289
- [
290
- pod[:name],
291
- status == "Running" ? status.green : status.red,
292
- pod[:ready] ? replicas.green : replicas.red
293
- ]
294
- end
29
+ if options.pull or options.build
30
+ system "docker image prune -f"
31
+ end
295
32
 
296
- if rows.empty?
297
- return
298
- end
33
+ UI.success("\n✔️ You can visit your environment at 👉 https://spend-cloud.dev.spend.cloud 👌")
34
+ end
299
35
 
300
- return Terminal::Table.new title: "Pods (namespace: #{namespace})".green, headings: ['Name', 'Status', 'Replicas ready'], rows: rows
301
- end
36
+ def stop
37
+ run_dc "down --remove-orphans"
38
+ end
302
39
 
303
- def copy_proactive_accounts_file
304
- container_name = "proactive-config"
305
- pod_id = pods().select {|pod| pod[:name].start_with?(container_name)}.first[:name]
40
+ def restart
41
+ run_dc "restart"
42
+ end
306
43
 
307
- begin
308
- UI.important("Checking ProActive accounts file...")
309
- run_command "kubectl exec #{pod_id} -- test -e /data/proactive_accounts.ini", [:out, :err] => File::NULL
310
- rescue => e
311
- UI.important("Copying ProActive accounts file to deployments...")
312
- src_path = "#{Dir.home()}/development/spend-cloud/k8s/conf/proactive_accounts.ini"
313
- command = "kubectl cp #{src_path} #{pod_id}:/data/proactive_accounts.ini -c #{container_name}"
314
- run_command command
315
- end
44
+ def delete
45
+ run_dc "down --remove-orphans -v"
46
+ end
316
47
 
317
- UI.success("ProActive accounts file is available")
318
- end
48
+ def reset args, options
49
+ delete
50
+ start args, options
51
+ end
319
52
 
320
- def create_keycloak_database_user
321
- container_name = "mysql-service"
322
- pod_id = pods().select {|pod| pod[:name].start_with?(container_name)}.first[:name]
53
+ def pull
54
+ run_dc "pull"
55
+ run "docker image prune -f"
56
+ end
323
57
 
324
- UI.important("Creating keycloak user")
325
- create_user = 'CREATE USER "keycloak"@"%" IDENTIFIED BY "keycloak";'
326
- run_command "kubectl exec #{pod_id} -- mysql -e '#{create_user}' >> /dev/null"
58
+ def status
59
+ run_dc "ps"
60
+ end
327
61
 
328
- UI.important("Creating keycloak database")
329
- create_database = "CREATE DATABASE keycloak CHARACTER SET utf8 COLLATE UTF8_UNICODE_CI;"
330
- run_command "kubectl exec #{pod_id} -- mysql -e '#{create_database}' >> /dev/null"
62
+ def logs args, options
63
+ command = "logs"
331
64
 
332
- UI.important("Granting privileges to keycloak user")
333
- grant_privileges = 'GRANT ALL PRIVILEGES ON keycloak.* TO "keycloak"@"%";'
334
- run_command "kubectl exec #{pod_id} -- mysql -e '#{grant_privileges}' >> /dev/null"
335
- end
65
+ command << " --follow" if options.f or options.follow
66
+ command << " --timestamps" if options.t or options.timestamps
67
+ command << " --tail #{options.tail}" if options.tail
336
68
 
337
- def run_command command, options = {}
338
- if ! system command, options
339
- raise command.red
340
- end
341
- end
69
+ run_dc "#{command} #{args.join " "}"
342
70
  end
71
+
72
+ end
343
73
  end
@@ -0,0 +1,43 @@
1
+ require 'yaml'
2
+
3
+ module Sct
4
+ class DevCommand
5
+
6
+ def error message
7
+ UI.error message
8
+ exit 1
9
+ end
10
+
11
+ def execute args, options
12
+ file = "docker-compose.dev.yml"
13
+
14
+ if !File.exist? file
15
+ error "Could not find file '#{file}'."
16
+ end
17
+
18
+ manifest = YAML.load File.read file
19
+
20
+ services = manifest["services"].to_a
21
+
22
+ if services.length != 1
23
+ error "Currently sct only supports a single service declaration in '#{file}'. Contact the infra guild if you consider this a limitation."
24
+ end
25
+
26
+ service, service_spec = services.first
27
+
28
+ container = service_spec["container_name"]
29
+ command = service_spec["command"] || ""
30
+
31
+ if options.build
32
+ return unless system "docker-compose -f #{file} build #{options.pull ? "--pull" : ""}"
33
+ end
34
+
35
+ return unless system "docker-compose -f ~/development/spend-cloud/docker-compose.yml rm --stop --force #{service}"
36
+
37
+ system "docker-compose -f #{file} run --rm --service-ports --name #{container} #{service} #{command}"
38
+
39
+ system "docker-compose -f ~/development/spend-cloud/docker-compose.yml up --detach #{service}"
40
+ end
41
+
42
+ end
43
+ end
@@ -1,20 +1,14 @@
1
1
  module Sct
2
2
  class MysqlproxyCommand
3
-
3
+
4
4
  DEFAULT_SECRET_NAME = "gcloud-credentials"
5
5
 
6
6
  def execute(args, options)
7
-
8
- return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
9
-
10
- path = SctCore::Config.get('cloud-proxy-path')
11
-
12
7
  system("kubectl delete secret gcloud-credentials")
13
- system("kubectl create secret generic gcloud-credentials --from-file=#{path}")
14
-
8
+ system("kubectl create secret generic gcloud-credentials --from-file=~/.config/gcloud/application_default_credentials.json")
9
+
15
10
  UI.success("Authenticated with secret-name: '#{DEFAULT_SECRET_NAME}'")
16
11
  end
17
-
18
- end
19
12
 
20
- end
13
+ end
14
+ end
@@ -17,51 +17,35 @@ module Sct
17
17
 
18
18
  global_option('--verbose') { $verbose = true }
19
19
 
20
- command :init do |c|
21
- c.syntax = 'sct init'
22
- c.description = 'setup sct'
23
-
24
- c.action do |args, options|
25
- UI.important("setting up sct")
26
- Sct::InitCommand.new.execute(args, options)
27
- end
28
- end
29
-
30
- command :hostfile do |c|
31
-
32
- c.syntax = 'sct hostfile'
33
- c.description = 'patch hostfile with kubernetes ip'
34
-
35
- c.action do |args, options|
36
- UI.important("Trying to patch hosts file...")
37
- Sct::HostfileCommand.new.execute(args, options)
38
- end
39
- end
40
-
41
20
  command :'mysql-proxy' do |c|
42
-
43
21
  c.syntax = 'sct mysql-proxy'
44
22
  c.description = 'setup google mysql proxy'
45
23
 
46
24
  c.action do |args, options|
47
25
  UI.important("Trying to setup mysql proxy")
48
- Sct::MysqlproxyCommand.new.execute(args, options)
26
+ Sct::MysqlproxyCommand.new.execute args, options
49
27
  end
50
-
51
28
  end
52
29
 
53
30
  command :'cluster' do |c|
54
-
55
31
  c.syntax = 'sct cluster'
56
32
  c.description = 'make changes to the cluster'
57
-
58
33
  end
59
34
 
60
35
  command :'shell' do |c|
61
-
62
36
  c.syntax = 'sct shell'
63
37
  c.description = 'run commands from the shell using docker containers'
38
+ end
39
+
40
+ command :'dev' do |c|
41
+ c.syntax = 'sct dev'
42
+ c.description = 'start development container in the current directory'
43
+ c.option '--build', '(re)build image from Dockerfile before starting'
44
+ c.option '--pull', 'pull latest base image from Dockerfile before (re)building. only used in combination with --build flag'
64
45
 
46
+ c.action do |args, options|
47
+ Sct::DevCommand.new.execute args, options
48
+ end
65
49
  end
66
50
 
67
51
  run!
@@ -1,3 +1,3 @@
1
1
  module Sct
2
- VERSION = "0.1.35"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,5 +1,4 @@
1
1
  require_relative 'sct_core/core_ext/string'
2
- require_relative 'sct_core/config'
3
2
  require_relative 'sct_core/helper'
4
3
  require_relative 'sct_core/update_checker/update_checker'
5
4
  require_relative 'sct_core/command_executor'
@@ -11,4 +10,4 @@ require 'colored'
11
10
  require 'commander'
12
11
 
13
12
  # these need to be imported after commander
14
- require_relative 'sct_core/module'
13
+ require_relative 'sct_core/module'
@@ -5,13 +5,13 @@ module SctCore
5
5
  MAC_OS = "MacOS"
6
6
  UBUNTU = "Ubuntu"
7
7
 
8
- def self.to_hash(str)
8
+ def self.to_hash str
9
9
  Hash[
10
10
  str.split("\n").map{|i|i.split('=')}
11
11
  ]
12
12
  end
13
13
 
14
- def self.operatingSystem
14
+ def self.operating_system
15
15
  proc = `uname -a`
16
16
 
17
17
  case proc.downcase
@@ -29,7 +29,7 @@ module SctCore
29
29
  def self.homePath
30
30
  user = ENV["SUDO_USER"] || ENV["USER"]
31
31
 
32
- if self.operatingSystem == MAC_OS
32
+ if self.operating_system == MAC_OS
33
33
  home = "/Users"
34
34
  else
35
35
  home = "/home"
@@ -46,7 +46,7 @@ module SctCore
46
46
  return nil
47
47
  end
48
48
 
49
- def self.convertWindowsToWSLPath(path)
49
+ def self.convertWindowsToWSLPath path
50
50
  if self.is_windows?
51
51
  return path.gsub(/C:\\/, '/mnt/c/').gsub(/\\\\/, "/").gsub(/\\/, '/').gsub(/\r\n?/, '')
52
52
  end
@@ -54,7 +54,7 @@ module SctCore
54
54
  return path
55
55
  end
56
56
 
57
- def self.convertWSLToWindowsPath(path)
57
+ def self.convertWSLToWindowsPath path
58
58
  if self.is_windows?
59
59
  return path.gsub(/\/mnt\/c/, 'C:/').gsub(/\/\//, '/').gsub(/\\\\/, "/").gsub(/\r\n?/, '')
60
60
  end
@@ -67,7 +67,7 @@ module SctCore
67
67
  end
68
68
 
69
69
  def self.is_windows?
70
- return self.operatingSystem == WINDOWS
70
+ return self.operating_system == WINDOWS
71
71
  end
72
72
 
73
73
  def self.is_windows_administrator?
@@ -93,5 +93,6 @@ module SctCore
93
93
  self.ensure_sudo
94
94
  self.ensure_windows_administrator
95
95
  end
96
+
96
97
  end
97
98
  end
@@ -1,83 +1,48 @@
1
1
  require 'yaml'
2
2
 
3
3
  module Shell
4
- class Runner
4
+ class Runner
5
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 }
21
- else
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]
6
+ def error message
7
+ UI.error message
8
+ exit 1
9
+ end
34
10
 
35
- # get the name and labels of each pod
36
- pods = lines.map do |line|
37
- columns = line.split " "
11
+ def launch
12
+ command = ARGV.empty? ? "sh" : ARGV.join(" ")
38
13
 
39
- name = columns[0]
14
+ file = "docker-compose.dev.yml"
40
15
 
41
- labels = columns[5].split(",").reduce({}) do |labels, label|
42
- key, value = label.split "="
43
- labels[key] = value
44
- labels
45
- end
16
+ if !File.exist? file
17
+ error "Could not find file '#{file}'."
18
+ end
46
19
 
47
- {
48
- name: name,
49
- labels: labels
50
- }
51
- end
20
+ manifest = YAML.load File.read file
52
21
 
53
- # filter by deployment
54
- pods = pods.filter { |pod| pod[:labels]["app"] == deployment }
22
+ services = manifest["services"].to_a
55
23
 
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
24
+ if services.length != 1
25
+ error "Currently sct only supports a single service declaration in '#{file}'. Contact the infra guild if you consider this a limitation."
26
+ end
61
27
 
62
- pod = pods.first
28
+ service, service_spec = services.first
63
29
 
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
30
+ container = service_spec["container_name"]
66
31
 
67
- answer = $stdin.readline.chomp.downcase
32
+ project = `docker container inspect --format '{{index .Config.Labels "com.docker.compose.project"}}' #{container}`.chomp
68
33
 
69
- if answer != "y"
70
- exit
71
- end
72
- end
34
+ if project == "spend-cloud"
35
+ print "This container was not started with 'sct dev'. Are you sure you want to continue? [y/N] ".red
73
36
 
74
- pod[:name]
75
- end
37
+ answer = $stdin.readline.chomp.downcase
76
38
 
77
- def error message
78
- UI.error message
79
- exit 1
39
+ if answer != "y"
40
+ exit
80
41
  end
42
+ end
81
43
 
44
+ system "docker exec -it #{container} #{command}"
82
45
  end
46
+
47
+ end
83
48
  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.35
4
+ version: 1.0.0
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-12-24 00:00:00.000000000 Z
11
+ date: 2021-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colored
@@ -200,16 +200,13 @@ files:
200
200
  - cluster/lib/cluster.rb
201
201
  - cluster/lib/cluster/commands_generator.rb
202
202
  - cluster/lib/cluster/module.rb
203
- - cluster/lib/cluster/resources/.DS_Store
204
- - cluster/lib/cluster/resources/corefile.yml
205
203
  - cluster/lib/cluster/runner.rb
206
204
  - sct/lib/.DS_Store
207
205
  - sct/lib/sct.rb
208
206
  - sct/lib/sct/.DS_Store
209
207
  - sct/lib/sct/cli_tools_distributor.rb
210
208
  - sct/lib/sct/command.rb
211
- - sct/lib/sct/commands/hostfile.rb
212
- - sct/lib/sct/commands/init.rb
209
+ - sct/lib/sct/commands/dev.rb
213
210
  - sct/lib/sct/commands/mysqlproxy.rb
214
211
  - sct/lib/sct/commands_generator.rb
215
212
  - sct/lib/sct/tools.rb
@@ -218,7 +215,6 @@ files:
218
215
  - sct_core/lib/sct_core.rb
219
216
  - sct_core/lib/sct_core/.DS_Store
220
217
  - sct_core/lib/sct_core/command_executor.rb
221
- - sct_core/lib/sct_core/config.rb
222
218
  - sct_core/lib/sct_core/core_ext/string.rb
223
219
  - sct_core/lib/sct_core/helper.rb
224
220
  - sct_core/lib/sct_core/module.rb
@@ -1,45 +0,0 @@
1
- apiVersion: v1
2
- data:
3
- Corefile: |
4
- .:53 {
5
- errors
6
- health {
7
- lameduck 5s
8
- }
9
- ready
10
- kubernetes cluster.local in-addr.arpa ip6.arpa {
11
- pods insecure
12
- fallthrough in-addr.arpa ip6.arpa
13
- ttl 30
14
- }
15
- prometheus :9153
16
- forward . 8.8.8.8
17
- cache 30
18
- loop
19
- reload
20
- loadbalance
21
- }
22
- Corefile-backup: |
23
- .:53 {
24
- errors
25
- health {
26
- lameduck 5s
27
- }
28
- ready
29
- kubernetes cluster.local in-addr.arpa ip6.arpa {
30
- pods insecure
31
- fallthrough in-addr.arpa ip6.arpa
32
- ttl 30
33
- }
34
- prometheus :9153
35
- forward . /etc/resolv.conf
36
- cache 30
37
- loop
38
- reload
39
- loadbalance
40
- }
41
- kind: ConfigMap
42
- metadata:
43
- creationTimestamp: null
44
- name: coredns
45
- selfLink: /api/v1/namespaces/kube-system/configmaps/coredns
@@ -1,76 +0,0 @@
1
- module Sct
2
- class HostfileCommand
3
-
4
- def execute(args, options)
5
- SctCore::Helper.ensure_permissions
6
-
7
- entries = [
8
- {
9
- host: "spend.cloud.local",
10
- comment: "The spend cloud ingress url"
11
- },
12
- {
13
- host: "mail.spend.cloud.local",
14
- comment: "The spend cloud mail url"
15
- },
16
- {
17
- host: "config.spend.cloud.local",
18
- comment: "The spend cloud config url"
19
- },
20
- {
21
- host: "spend-cloud.spend.cloud.local",
22
- comment: "The spend cloud web app url"
23
- },
24
- {
25
- host: "docs.spend.cloud.local",
26
- comment: "The spend cloud documentation url"
27
- },
28
- {
29
- host: "henk.spend.cloud.local",
30
- comment: "The spend cloud Henk web-interface"
31
- }
32
- ]
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
-
44
- if options.path
45
- hosts_paths = [options.path]
46
- else
47
- hosts_paths = ["/etc/hosts"]
48
-
49
- if is_windows
50
- hosts_paths << windows_hosts_path
51
- end
52
- end
53
-
54
- hosts_paths.each do |hosts_path|
55
- line_ending = hosts_path == windows_hosts_path ? "\r\n" : "\n"
56
-
57
- lines = File.readlines hosts_path
58
-
59
- # select the lines that do not include any entry
60
- lines = lines.select { |line| ! entries.any? { |entry| line.include? " #{entry[:host]}" } }
61
-
62
- # add entries
63
- entries.each do |entry|
64
- lines << "#{ingress_address} #{entry[:host]} # #{entry[:comment]}#{line_ending}"
65
- end
66
-
67
- File.write hosts_path, lines.join
68
-
69
- UI.success("Patched #{hosts_path} with #{ingress_address}")
70
- end
71
-
72
- end
73
-
74
- end
75
-
76
- end
@@ -1,37 +0,0 @@
1
- require 'sct_core/ui/ui'
2
- require 'sct_core/config'
3
-
4
- module Sct
5
-
6
- class InitCommand
7
-
8
- def execute(args, options)
9
-
10
- dir = SctCore::Config.dir
11
-
12
- cli = HighLine.new
13
-
14
- email = cli.ask("What is your email address?") { |q|
15
- q.validate = URI::MailTo::EMAIL_REGEXP
16
- }
17
-
18
- cloud_proxy_path = cli.ask("What is the path of your cloud proxy json credentials?") { |q|
19
- q.default = "~/.config/gcloud/application_default_credentials.json"
20
- }
21
-
22
- contents = ""
23
- contents << "email=#{email}\n"
24
- contents << "cloud-proxy-path=#{File.expand_path(cloud_proxy_path)}\n"
25
-
26
- if !File.directory?(dir)
27
- FileUtils.mkdir_p(dir)
28
- end
29
-
30
- File.write(SctCore::Config.path, contents)
31
-
32
- puts "Generated config file at #{SctCore::Config.path}"
33
- end
34
-
35
- end
36
-
37
- end
@@ -1,36 +0,0 @@
1
- module SctCore
2
- class Config
3
-
4
- def self.dir
5
- return "#{SctCore::Helper.homePath}/.config/sct"
6
- end
7
-
8
- def self.path
9
- return File.expand_path(File.join(self.dir, 'config'))
10
- end
11
-
12
- def self.exists
13
- return File.exists?(Config.path)
14
- end
15
-
16
- def self.get(key)
17
- config = self.read
18
-
19
- if !config.key?(key)
20
- return nil
21
- end
22
-
23
- return config[key]
24
- end
25
-
26
- def self.read
27
- if !self.exists
28
- return {}
29
- end
30
-
31
- contents = File.read(self.path)
32
-
33
- return SctCore::Helper.to_hash(contents)
34
- end
35
- end
36
- end