sct 0.1.35 → 1.0.0

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