cpl 1.3.0 → 2.0.0.rc.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 +4 -4
- data/.github/workflows/command_docs.yml +1 -1
- data/.github/workflows/rspec-shared.yml +56 -0
- data/.github/workflows/rspec.yml +19 -31
- data/.github/workflows/rubocop.yml +2 -10
- data/.gitignore +2 -0
- data/.simplecov_spawn.rb +10 -0
- data/CHANGELOG.md +28 -1
- data/CONTRIBUTING.md +32 -2
- data/Gemfile.lock +38 -29
- data/README.md +43 -17
- data/cpl.gemspec +2 -1
- data/docs/commands.md +68 -59
- data/docs/dns.md +6 -0
- data/docs/migrating.md +10 -10
- data/docs/tips.md +15 -3
- data/examples/circleci.yml +3 -3
- data/examples/controlplane.yml +35 -9
- data/lib/command/apply_template.rb +66 -18
- data/lib/command/base.rb +168 -27
- data/lib/command/build_image.rb +4 -9
- data/lib/command/cleanup_stale_apps.rb +1 -3
- data/lib/command/copy_image_from_upstream.rb +0 -7
- data/lib/command/delete.rb +39 -7
- data/lib/command/deploy_image.rb +35 -2
- data/lib/command/exists.rb +1 -1
- data/lib/command/generate.rb +1 -1
- data/lib/command/info.rb +7 -3
- data/lib/command/logs.rb +22 -2
- data/lib/command/maintenance_off.rb +1 -1
- data/lib/command/maintenance_on.rb +1 -1
- data/lib/command/open.rb +2 -2
- data/lib/command/open_console.rb +2 -2
- data/lib/command/promote_app_from_upstream.rb +5 -25
- data/lib/command/ps.rb +1 -1
- data/lib/command/ps_start.rb +2 -1
- data/lib/command/ps_stop.rb +40 -8
- data/lib/command/ps_wait.rb +3 -2
- data/lib/command/run.rb +430 -68
- data/lib/command/setup_app.rb +22 -2
- data/lib/constants/exit_code.rb +7 -0
- data/lib/core/config.rb +11 -3
- data/lib/core/controlplane.rb +126 -47
- data/lib/core/controlplane_api.rb +15 -1
- data/lib/core/controlplane_api_cli.rb +3 -3
- data/lib/core/controlplane_api_direct.rb +33 -5
- data/lib/core/shell.rb +15 -9
- data/lib/cpl/version.rb +1 -1
- data/lib/cpl.rb +50 -9
- data/lib/deprecated_commands.json +2 -1
- data/lib/generator_templates/controlplane.yml +5 -0
- data/lib/generator_templates/templates/{gvc.yml → app.yml} +4 -4
- data/lib/generator_templates/templates/postgres.yml +1 -1
- data/lib/generator_templates/templates/rails.yml +1 -1
- data/script/check_cpln_links +3 -3
- data/templates/app.yml +18 -0
- data/templates/daily-task.yml +3 -2
- data/templates/rails.yml +3 -2
- data/templates/secrets.yml +11 -0
- data/templates/sidekiq.yml +3 -2
- metadata +38 -25
- data/.rspec +0 -1
- data/lib/command/run_cleanup.rb +0 -116
- data/lib/command/run_detached.rb +0 -175
- data/lib/core/scripts.rb +0 -34
- data/templates/gvc.yml +0 -13
- data/templates/identity.yml +0 -2
data/script/check_cpln_links
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env bash
|
2
2
|
|
3
|
-
bad_links=("controlplane.com/shakacode")
|
4
|
-
proper_links=("shakacode.controlplane.com")
|
3
|
+
bad_links=("controlplane.com/shakacode" "https://docs.controlplane.com")
|
4
|
+
proper_links=("shakacode.controlplane.com" "https://shakadocs.controlplane.com")
|
5
5
|
|
6
6
|
bold=$(tput bold)
|
7
7
|
normal=$(tput sgr0)
|
@@ -19,7 +19,7 @@ for ((idx = 0; idx < ${#bad_links[@]}; idx++)); do
|
|
19
19
|
--heading \
|
20
20
|
--color=always -- \
|
21
21
|
"${bad_links[idx]}" \
|
22
|
-
':!script/check_cpln_links')
|
22
|
+
':!script/check_cpln_links' '*.md')
|
23
23
|
|
24
24
|
# Line would become really unwieldly if everything was mushed into the
|
25
25
|
# conditional, so let's ignore this check here.
|
data/templates/app.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
kind: gvc
|
2
|
+
name: {{APP_NAME}}
|
3
|
+
spec:
|
4
|
+
env:
|
5
|
+
- name: MEMCACHE_SERVERS
|
6
|
+
value: memcached.{{APP_NAME}}.cpln.local
|
7
|
+
- name: REDIS_URL
|
8
|
+
value: redis://redis.{{APP_NAME}}.cpln.local:6379
|
9
|
+
- name: DATABASE_URL
|
10
|
+
value: postgres://postgres:password123@postgres.{{APP_NAME}}.cpln.local:5432/{{APP_NAME}}
|
11
|
+
staticPlacement:
|
12
|
+
locationLinks:
|
13
|
+
- {{APP_LOCATION_LINK}}
|
14
|
+
---
|
15
|
+
# Identity is needed to access secrets
|
16
|
+
kind: identity
|
17
|
+
name: {{APP_IDENTITY}}
|
18
|
+
|
data/templates/daily-task.yml
CHANGED
@@ -18,7 +18,7 @@ spec:
|
|
18
18
|
- rails
|
19
19
|
- db:prepare
|
20
20
|
inheritEnv: true
|
21
|
-
image:
|
21
|
+
image: {{APP_IMAGE_LINK}}
|
22
22
|
defaultOptions:
|
23
23
|
autoscaling:
|
24
24
|
minScale: 1
|
@@ -28,4 +28,5 @@ spec:
|
|
28
28
|
external:
|
29
29
|
outboundAllowCIDR:
|
30
30
|
- 0.0.0.0/0
|
31
|
-
|
31
|
+
# Identity is used for binding workload to secrets
|
32
|
+
identityLink: {{APP_IDENTITY_LINK}}
|
data/templates/rails.yml
CHANGED
@@ -7,7 +7,7 @@ spec:
|
|
7
7
|
cpu: 512m
|
8
8
|
memory: 1Gi
|
9
9
|
inheritEnv: true
|
10
|
-
image:
|
10
|
+
image: {{APP_IMAGE_LINK}}
|
11
11
|
ports:
|
12
12
|
- number: 3000
|
13
13
|
protocol: http
|
@@ -23,4 +23,5 @@ spec:
|
|
23
23
|
- 0.0.0.0/0
|
24
24
|
outboundAllowCIDR:
|
25
25
|
- 0.0.0.0/0
|
26
|
-
|
26
|
+
# Identity is used for binding workload to secrets
|
27
|
+
identityLink: {{APP_IDENTITY_LINK}}
|
data/templates/sidekiq.yml
CHANGED
@@ -13,7 +13,7 @@ spec:
|
|
13
13
|
- "-C"
|
14
14
|
- config/sidekiq.yml
|
15
15
|
inheritEnv: true
|
16
|
-
image:
|
16
|
+
image: {{APP_IMAGE_LINK}}
|
17
17
|
ports:
|
18
18
|
- number: 7433
|
19
19
|
protocol: http
|
@@ -34,4 +34,5 @@ spec:
|
|
34
34
|
external:
|
35
35
|
outboundAllowCIDR:
|
36
36
|
- 0.0.0.0/0
|
37
|
-
|
37
|
+
# Identity is used for binding workload to secrets
|
38
|
+
identityLink: {{APP_IDENTITY_LINK}}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cpl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.rc.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Gordon
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-05-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debug
|
@@ -39,6 +39,20 @@ dependencies:
|
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: 2.8.1
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: jwt
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 2.8.1
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 2.8.1
|
42
56
|
- !ruby/object:Gem::Dependency
|
43
57
|
name: psych
|
44
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,6 +109,20 @@ dependencies:
|
|
95
109
|
- - "~>"
|
96
110
|
- !ruby/object:Gem::Version
|
97
111
|
version: 3.12.0
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: rspec-retry
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 0.6.2
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.6.2
|
98
126
|
- !ruby/object:Gem::Dependency
|
99
127
|
name: rubocop
|
100
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -165,20 +193,6 @@ dependencies:
|
|
165
193
|
- - "~>"
|
166
194
|
- !ruby/object:Gem::Version
|
167
195
|
version: 0.9.6
|
168
|
-
- !ruby/object:Gem::Dependency
|
169
|
-
name: vcr
|
170
|
-
requirement: !ruby/object:Gem::Requirement
|
171
|
-
requirements:
|
172
|
-
- - "~>"
|
173
|
-
- !ruby/object:Gem::Version
|
174
|
-
version: 6.1.0
|
175
|
-
type: :development
|
176
|
-
prerelease: false
|
177
|
-
version_requirements: !ruby/object:Gem::Requirement
|
178
|
-
requirements:
|
179
|
-
- - "~>"
|
180
|
-
- !ruby/object:Gem::Version
|
181
|
-
version: 6.1.0
|
182
196
|
- !ruby/object:Gem::Dependency
|
183
197
|
name: webmock
|
184
198
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,12 +218,13 @@ extra_rdoc_files: []
|
|
204
218
|
files:
|
205
219
|
- ".github/workflows/check_cpln_links.yml"
|
206
220
|
- ".github/workflows/command_docs.yml"
|
221
|
+
- ".github/workflows/rspec-shared.yml"
|
207
222
|
- ".github/workflows/rspec.yml"
|
208
223
|
- ".github/workflows/rubocop.yml"
|
209
224
|
- ".gitignore"
|
210
225
|
- ".overcommit.yml"
|
211
|
-
- ".rspec"
|
212
226
|
- ".rubocop.yml"
|
227
|
+
- ".simplecov_spawn.rb"
|
213
228
|
- CHANGELOG.md
|
214
229
|
- CONTRIBUTING.md
|
215
230
|
- Gemfile
|
@@ -262,18 +277,16 @@ files:
|
|
262
277
|
- lib/command/ps_stop.rb
|
263
278
|
- lib/command/ps_wait.rb
|
264
279
|
- lib/command/run.rb
|
265
|
-
- lib/command/run_cleanup.rb
|
266
|
-
- lib/command/run_detached.rb
|
267
280
|
- lib/command/setup_app.rb
|
268
281
|
- lib/command/test.rb
|
269
282
|
- lib/command/version.rb
|
283
|
+
- lib/constants/exit_code.rb
|
270
284
|
- lib/core/config.rb
|
271
285
|
- lib/core/controlplane.rb
|
272
286
|
- lib/core/controlplane_api.rb
|
273
287
|
- lib/core/controlplane_api_cli.rb
|
274
288
|
- lib/core/controlplane_api_direct.rb
|
275
289
|
- lib/core/helpers.rb
|
276
|
-
- lib/core/scripts.rb
|
277
290
|
- lib/core/shell.rb
|
278
291
|
- lib/cpl.rb
|
279
292
|
- lib/cpl/version.rb
|
@@ -281,7 +294,7 @@ files:
|
|
281
294
|
- lib/generator_templates/Dockerfile
|
282
295
|
- lib/generator_templates/controlplane.yml
|
283
296
|
- lib/generator_templates/entrypoint.sh
|
284
|
-
- lib/generator_templates/templates/
|
297
|
+
- lib/generator_templates/templates/app.yml
|
285
298
|
- lib/generator_templates/templates/postgres.yml
|
286
299
|
- lib/generator_templates/templates/rails.yml
|
287
300
|
- rakelib/create_release.rake
|
@@ -290,14 +303,14 @@ files:
|
|
290
303
|
- script/check_cpln_links
|
291
304
|
- script/rename_command
|
292
305
|
- script/update_command_docs
|
306
|
+
- templates/app.yml
|
293
307
|
- templates/daily-task.yml
|
294
|
-
- templates/gvc.yml
|
295
|
-
- templates/identity.yml
|
296
308
|
- templates/maintenance.yml
|
297
309
|
- templates/memcached.yml
|
298
310
|
- templates/postgres.yml
|
299
311
|
- templates/rails.yml
|
300
312
|
- templates/redis.yml
|
313
|
+
- templates/secrets.yml
|
301
314
|
- templates/sidekiq.yml
|
302
315
|
homepage: https://github.com/shakacode/heroku-to-control-plane
|
303
316
|
licenses:
|
@@ -315,9 +328,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
315
328
|
version: 2.7.0
|
316
329
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
317
330
|
requirements:
|
318
|
-
- - "
|
331
|
+
- - ">"
|
319
332
|
- !ruby/object:Gem::Version
|
320
|
-
version:
|
333
|
+
version: 1.3.1
|
321
334
|
requirements: []
|
322
335
|
rubygems_version: 3.4.21
|
323
336
|
signing_key:
|
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--require spec_helper
|
data/lib/command/run_cleanup.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Command
|
4
|
-
class RunCleanup < Base
|
5
|
-
NAME = "run:cleanup"
|
6
|
-
OPTIONS = [
|
7
|
-
app_option(required: true),
|
8
|
-
skip_confirm_option
|
9
|
-
].freeze
|
10
|
-
DESCRIPTION = "Deletes stale run workloads for an app"
|
11
|
-
LONG_DESCRIPTION = <<~DESC
|
12
|
-
- Deletes stale run workloads for an app
|
13
|
-
- Workloads are considered stale based on how many days since created
|
14
|
-
- `stale_run_workload_created_days` in the `.controlplane/controlplane.yml` file specifies the number of days after created that the workload is considered stale
|
15
|
-
- Works for both interactive workloads (created with `cpl run`) and non-interactive workloads (created with `cpl run:detached`)
|
16
|
-
- Will ask for explicit user confirmation of deletion
|
17
|
-
DESC
|
18
|
-
|
19
|
-
def call # rubocop:disable Metrics/MethodLength
|
20
|
-
return progress.puts("No stale run workloads found.") if stale_run_workloads.empty?
|
21
|
-
|
22
|
-
progress.puts("Stale run workloads:")
|
23
|
-
stale_run_workloads.each do |workload|
|
24
|
-
output = ""
|
25
|
-
output += if config.should_app_start_with?(config.app)
|
26
|
-
" #{workload[:app]} - #{workload[:name]}"
|
27
|
-
else
|
28
|
-
" #{workload[:name]}"
|
29
|
-
end
|
30
|
-
output += " (#{Shell.color("#{workload[:date]} - #{workload[:days]} days ago", :red)})"
|
31
|
-
progress.puts(output)
|
32
|
-
end
|
33
|
-
|
34
|
-
return unless confirm_delete
|
35
|
-
|
36
|
-
progress.puts
|
37
|
-
stale_run_workloads.each do |workload|
|
38
|
-
delete_workload(workload)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def app_matches?(app, app_name, app_options)
|
45
|
-
app == app_name.to_s || (app_options[:match_if_app_name_starts_with] && app.start_with?(app_name.to_s))
|
46
|
-
end
|
47
|
-
|
48
|
-
def find_app_options(app)
|
49
|
-
@app_options ||= {}
|
50
|
-
@app_options[app] ||= config.apps.find do |app_name, app_options|
|
51
|
-
app_matches?(app, app_name, app_options)
|
52
|
-
end&.last
|
53
|
-
end
|
54
|
-
|
55
|
-
def find_workloads(app)
|
56
|
-
app_options = find_app_options(app)
|
57
|
-
return [] if app_options.nil?
|
58
|
-
|
59
|
-
(app_options[:app_workloads] + app_options[:additional_workloads] + [app_options[:one_off_workload]]).uniq
|
60
|
-
end
|
61
|
-
|
62
|
-
def stale_run_workloads # rubocop:disable Metrics/MethodLength
|
63
|
-
@stale_run_workloads ||=
|
64
|
-
begin
|
65
|
-
defined_workloads = find_workloads(config.app)
|
66
|
-
|
67
|
-
run_workloads = []
|
68
|
-
|
69
|
-
now = DateTime.now
|
70
|
-
stale_run_workload_created_days = config[:stale_run_workload_created_days]
|
71
|
-
|
72
|
-
interactive_workloads = cp.query_workloads("-run-", partial_workload_match: true)["items"]
|
73
|
-
non_interactive_workloads = cp.query_workloads("-runner-", partial_workload_match: true)["items"]
|
74
|
-
workloads = interactive_workloads + non_interactive_workloads
|
75
|
-
|
76
|
-
workloads.each do |workload|
|
77
|
-
app_name = workload["links"].find { |link| link["rel"] == "gvc" }["href"].split("/").last
|
78
|
-
workload_name = workload["name"]
|
79
|
-
|
80
|
-
original_workload_name, workload_number = workload_name.split(/-run-|-runner-/)
|
81
|
-
next unless defined_workloads.include?(original_workload_name) && workload_number.match?(/^\d{4}$/)
|
82
|
-
|
83
|
-
created_date = DateTime.parse(workload["created"])
|
84
|
-
diff_in_days = (now - created_date).to_i
|
85
|
-
next unless diff_in_days >= stale_run_workload_created_days
|
86
|
-
|
87
|
-
run_workloads.push({
|
88
|
-
app: app_name,
|
89
|
-
name: workload_name,
|
90
|
-
date: created_date,
|
91
|
-
days: diff_in_days
|
92
|
-
})
|
93
|
-
end
|
94
|
-
|
95
|
-
run_workloads
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def confirm_delete
|
100
|
-
return true if config.options[:yes]
|
101
|
-
|
102
|
-
Shell.confirm("\nAre you sure you want to delete these #{stale_run_workloads.length} run workloads?")
|
103
|
-
end
|
104
|
-
|
105
|
-
def delete_workload(workload)
|
106
|
-
message = if config.should_app_start_with?(config.app)
|
107
|
-
"Deleting run workload '#{workload[:app]} - #{workload[:name]}'"
|
108
|
-
else
|
109
|
-
"Deleting run workload '#{workload[:name]}'"
|
110
|
-
end
|
111
|
-
step(message) do
|
112
|
-
cp.delete_workload(workload[:name], workload[:app])
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
data/lib/command/run_detached.rb
DELETED
@@ -1,175 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Command
|
4
|
-
class RunDetached < Base # rubocop:disable Metrics/ClassLength
|
5
|
-
NAME = "run:detached"
|
6
|
-
USAGE = "run:detached COMMAND"
|
7
|
-
REQUIRES_ARGS = true
|
8
|
-
OPTIONS = [
|
9
|
-
app_option(required: true),
|
10
|
-
image_option,
|
11
|
-
workload_option,
|
12
|
-
location_option,
|
13
|
-
use_local_token_option,
|
14
|
-
clean_on_failure_option
|
15
|
-
].freeze
|
16
|
-
DESCRIPTION = "Runs one-off **_non-interactive_** replicas (close analog of `heroku run:detached`)"
|
17
|
-
LONG_DESCRIPTION = <<~DESC
|
18
|
-
- Runs one-off **_non-interactive_** replicas (close analog of `heroku run:detached`)
|
19
|
-
- Uses `Cron` workload type with log async fetching
|
20
|
-
- Implemented with only async execution methods, more suitable for production tasks
|
21
|
-
- Has alternative log fetch implementation with only JSON-polling and no WebSockets
|
22
|
-
- Less responsive but more stable, useful for CI tasks
|
23
|
-
- Deletes the workload whenever finished with success
|
24
|
-
- Deletes the workload whenever finished with failure by default
|
25
|
-
- Use `--no-clean-on-failure` to disable cleanup to help with debugging failed runs
|
26
|
-
DESC
|
27
|
-
EXAMPLES = <<~EX
|
28
|
-
```sh
|
29
|
-
cpl run:detached rails db:prepare -a $APP_NAME
|
30
|
-
|
31
|
-
# Need to quote COMMAND if setting ENV value or passing args.
|
32
|
-
cpl run:detached -a $APP_NAME -- 'LOG_LEVEL=warn rails db:migrate'
|
33
|
-
|
34
|
-
# Uses a different image (which may not be promoted yet).
|
35
|
-
cpl run:detached -a $APP_NAME --image appimage:123 -- rails db:migrate # Exact image name
|
36
|
-
cpl run:detached -a $APP_NAME --image latest -- rails db:migrate # Latest sequential image
|
37
|
-
|
38
|
-
# Uses a different workload than `one_off_workload` from `.controlplane/controlplane.yml`.
|
39
|
-
cpl run:detached -a $APP_NAME -w other-workload -- rails db:migrate:status
|
40
|
-
|
41
|
-
# Overrides remote CPLN_TOKEN env variable with local token.
|
42
|
-
# Useful when superuser rights are needed in remote container.
|
43
|
-
cpl run:detached -a $APP_NAME --use-local-token -- rails db:migrate:status
|
44
|
-
```
|
45
|
-
EX
|
46
|
-
|
47
|
-
WORKLOAD_SLEEP_CHECK = 2
|
48
|
-
|
49
|
-
attr_reader :location, :workload_to_clone, :workload_clone, :container
|
50
|
-
|
51
|
-
def call
|
52
|
-
@location = config.location
|
53
|
-
@workload_to_clone = config.options["workload"] || config[:one_off_workload]
|
54
|
-
@workload_clone = "#{workload_to_clone}-runner-#{random_four_digits}"
|
55
|
-
|
56
|
-
step("Cloning workload '#{workload_to_clone}' on app '#{config.options[:app]}' to '#{workload_clone}'") do
|
57
|
-
clone_workload
|
58
|
-
end
|
59
|
-
|
60
|
-
wait_for_workload(workload_clone)
|
61
|
-
show_logs_waiting
|
62
|
-
ensure
|
63
|
-
exit(1) if @crashed
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def clone_workload # rubocop:disable Metrics/MethodLength
|
69
|
-
# Get base specs of workload
|
70
|
-
spec = cp.fetch_workload!(workload_to_clone).fetch("spec")
|
71
|
-
container_spec = spec["containers"].detect { _1["name"] == workload_to_clone } || spec["containers"].first
|
72
|
-
@container = container_spec["name"]
|
73
|
-
|
74
|
-
# remove other containers if any
|
75
|
-
spec["containers"] = [container_spec]
|
76
|
-
|
77
|
-
# Set runner
|
78
|
-
container_spec["command"] = "bash"
|
79
|
-
container_spec["args"] = ["-c", 'eval "$CONTROLPLANE_RUNNER"']
|
80
|
-
|
81
|
-
# Ensure one-off workload will be running
|
82
|
-
spec["defaultOptions"]["suspend"] = false
|
83
|
-
|
84
|
-
# Ensure no scaling
|
85
|
-
spec["defaultOptions"]["autoscaling"]["minScale"] = 1
|
86
|
-
spec["defaultOptions"]["autoscaling"]["maxScale"] = 1
|
87
|
-
spec["defaultOptions"]["capacityAI"] = false
|
88
|
-
|
89
|
-
# Override image if specified
|
90
|
-
image = config.options[:image]
|
91
|
-
image = latest_image if image == "latest"
|
92
|
-
container_spec["image"] = "/org/#{config.org}/image/#{image}" if image
|
93
|
-
|
94
|
-
# Set cron job props
|
95
|
-
spec["type"] = "cron"
|
96
|
-
spec["job"] = { "schedule" => "* * * * *", "restartPolicy" => "Never" }
|
97
|
-
spec["defaultOptions"]["autoscaling"] = {}
|
98
|
-
container_spec.delete("ports")
|
99
|
-
|
100
|
-
container_spec["env"] ||= []
|
101
|
-
container_spec["env"] << { "name" => "CONTROLPLANE_TOKEN", "value" => ControlplaneApiDirect.new.api_token }
|
102
|
-
container_spec["env"] << { "name" => "CONTROLPLANE_RUNNER", "value" => runner_script }
|
103
|
-
|
104
|
-
# Create workload clone
|
105
|
-
cp.apply_hash("kind" => "workload", "name" => workload_clone, "spec" => spec)
|
106
|
-
end
|
107
|
-
|
108
|
-
def runner_script # rubocop:disable Metrics/MethodLength
|
109
|
-
script = "echo '-- STARTED RUNNER SCRIPT --'\n"
|
110
|
-
script += Scripts.helpers_cleanup
|
111
|
-
|
112
|
-
if config.options["use_local_token"]
|
113
|
-
script += <<~SHELL
|
114
|
-
CPLN_TOKEN=$CONTROLPLANE_TOKEN
|
115
|
-
SHELL
|
116
|
-
end
|
117
|
-
|
118
|
-
script += <<~SHELL
|
119
|
-
crashed=0
|
120
|
-
if ! eval "#{args_join(config.args)}"; then
|
121
|
-
crashed=1
|
122
|
-
echo "----- CRASHED -----"
|
123
|
-
fi
|
124
|
-
clean_on_failure=#{config.options[:clean_on_failure] ? 1 : 0}
|
125
|
-
if [ $crashed -eq 0 ] || [ $clean_on_failure -eq 1 ]; then
|
126
|
-
echo "-- FINISHED RUNNER SCRIPT, DELETING WORKLOAD --"
|
127
|
-
sleep 30 # grace time for logs propagation
|
128
|
-
curl ${CPLN_ENDPOINT}${CPLN_WORKLOAD} -H "Authorization: ${CONTROLPLANE_TOKEN}" -X DELETE -s -o /dev/null
|
129
|
-
while true; do sleep 1; done # wait for SIGTERM
|
130
|
-
else
|
131
|
-
echo "-- FINISHED RUNNER SCRIPT --"
|
132
|
-
fi
|
133
|
-
SHELL
|
134
|
-
|
135
|
-
script
|
136
|
-
end
|
137
|
-
|
138
|
-
def show_logs_waiting # rubocop:disable Metrics/MethodLength
|
139
|
-
progress.puts("Scheduled, fetching logs (it's a cron job, so it may take up to a minute to start)...\n\n")
|
140
|
-
begin
|
141
|
-
@finished = false
|
142
|
-
while cp.fetch_workload(workload_clone) && !@finished
|
143
|
-
sleep(WORKLOAD_SLEEP_CHECK)
|
144
|
-
print_uniq_logs
|
145
|
-
end
|
146
|
-
rescue RuntimeError => e
|
147
|
-
progress.puts(Shell.color("ERROR: #{e}", :red))
|
148
|
-
retry
|
149
|
-
end
|
150
|
-
progress.puts("\nFinished workload and logger.")
|
151
|
-
end
|
152
|
-
|
153
|
-
def print_uniq_logs
|
154
|
-
@printed_log_entries ||= []
|
155
|
-
ts = Time.now.to_i
|
156
|
-
entries = normalized_log_entries(from: ts - 60, to: ts)
|
157
|
-
|
158
|
-
(entries - @printed_log_entries).sort.each do |(_ts, val)|
|
159
|
-
@crashed = true if val.match?(/^----- CRASHED -----$/)
|
160
|
-
@finished = true if val.match?(/^-- FINISHED RUNNER SCRIPT(, DELETING WORKLOAD)? --$/)
|
161
|
-
puts val
|
162
|
-
end
|
163
|
-
|
164
|
-
@printed_log_entries = entries # as well truncate old entries if any
|
165
|
-
end
|
166
|
-
|
167
|
-
def normalized_log_entries(from:, to:)
|
168
|
-
log = cp.log_get(workload: workload_clone, from: from, to: to)
|
169
|
-
|
170
|
-
log["data"]["result"]
|
171
|
-
.each_with_object([]) { |obj, result| result.concat(obj["values"]) }
|
172
|
-
.select { |ts, _val| ts[..-10].to_i > from }
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
data/lib/core/scripts.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Scripts
|
4
|
-
module_function
|
5
|
-
|
6
|
-
def assert_replicas(gvc:, workload:, location:)
|
7
|
-
<<~SHELL
|
8
|
-
REPLICAS_QTY=$( \
|
9
|
-
curl ${CPLN_ENDPOINT}/org/shakacode-staging/gvc/#{gvc}/workload/#{workload}/deployment/#{location} \
|
10
|
-
-H "Authorization: ${CONTROLPLANE_TOKEN}" -s | grep -o '"replicas":[0-9]*' | grep -o '[0-9]*')
|
11
|
-
|
12
|
-
if [ "$REPLICAS_QTY" -gt 0 ]; then
|
13
|
-
echo "-- MULTIPLE REPLICAS ATTEMPT: $REPLICAS_QTY --"
|
14
|
-
exit -1
|
15
|
-
fi
|
16
|
-
SHELL
|
17
|
-
end
|
18
|
-
|
19
|
-
def helpers_cleanup
|
20
|
-
<<~SHELL
|
21
|
-
unset CONTROLPLANE_RUNNER
|
22
|
-
SHELL
|
23
|
-
end
|
24
|
-
|
25
|
-
# NOTE: please escape all '/' as '//' (as it is ruby interpolation here as well)
|
26
|
-
def http_dummy_server_ruby
|
27
|
-
'require "socket";s=TCPServer.new(ENV["PORT"] || 80);' \
|
28
|
-
'loop do c=s.accept;c.puts("HTTP/1.1 200 OK\\nContent-Length: 2\\n\\nOk");c.close end'
|
29
|
-
end
|
30
|
-
|
31
|
-
def http_ping_ruby
|
32
|
-
'require "net/http";uri=URI(ENV["CPLN_GLOBAL_ENDPOINT"]);loop do puts(Net::HTTP.get(uri));sleep(5);end'
|
33
|
-
end
|
34
|
-
end
|
data/templates/gvc.yml
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
kind: gvc
|
2
|
-
name: APP_GVC
|
3
|
-
spec:
|
4
|
-
env:
|
5
|
-
- name: MEMCACHE_SERVERS
|
6
|
-
value: memcached.APP_GVC.cpln.local
|
7
|
-
- name: REDIS_URL
|
8
|
-
value: redis://redis.APP_GVC.cpln.local:6379
|
9
|
-
- name: DATABASE_URL
|
10
|
-
value: postgres://postgres:password123@postgres.APP_GVC.cpln.local:5432/APP_GVC
|
11
|
-
staticPlacement:
|
12
|
-
locationLinks:
|
13
|
-
- /org/APP_ORG/location/APP_LOCATION
|
data/templates/identity.yml
DELETED