cpl 1.1.2.rc.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rspec.yml +1 -1
- data/CHANGELOG.md +36 -1
- data/CONTRIBUTING.md +2 -6
- data/Gemfile.lock +7 -7
- data/README.md +94 -53
- data/docs/commands.md +22 -5
- data/docs/migrating.md +3 -3
- data/examples/controlplane.yml +63 -4
- data/lib/command/apply_template.rb +30 -54
- data/lib/command/base.rb +43 -0
- data/lib/command/copy_image_from_upstream.rb +5 -2
- data/lib/command/delete.rb +40 -11
- data/lib/command/env.rb +1 -0
- data/lib/command/generate.rb +45 -0
- data/lib/command/info.rb +5 -5
- data/lib/command/latest_image.rb +1 -0
- data/lib/command/maintenance.rb +1 -0
- data/lib/command/no_command.rb +6 -3
- data/lib/command/open_console.rb +26 -0
- data/lib/command/ps.rb +5 -1
- data/lib/command/run.rb +2 -2
- data/lib/command/run_detached.rb +2 -1
- data/lib/command/setup_app.rb +3 -3
- data/lib/command/version.rb +1 -0
- data/lib/core/config.rb +185 -54
- data/lib/core/controlplane.rb +76 -24
- data/lib/core/controlplane_api.rb +9 -1
- data/lib/core/controlplane_api_direct.rb +20 -2
- data/lib/core/helpers.rb +10 -0
- data/lib/core/shell.rb +36 -2
- data/lib/cpl/version.rb +1 -1
- data/lib/cpl.rb +28 -2
- data/lib/generator_templates/Dockerfile +27 -0
- data/lib/generator_templates/controlplane.yml +57 -0
- data/lib/generator_templates/entrypoint.sh +8 -0
- data/lib/generator_templates/templates/gvc.yml +21 -0
- data/lib/generator_templates/templates/postgres.yml +176 -0
- data/lib/generator_templates/templates/rails.yml +36 -0
- metadata +14 -5
@@ -7,6 +7,7 @@ module Command
|
|
7
7
|
REQUIRES_ARGS = true
|
8
8
|
OPTIONS = [
|
9
9
|
app_option(required: true),
|
10
|
+
location_option,
|
10
11
|
skip_confirm_option
|
11
12
|
].freeze
|
12
13
|
DESCRIPTION = "Applies application-specific configs from templates"
|
@@ -35,13 +36,12 @@ module Command
|
|
35
36
|
```
|
36
37
|
EX
|
37
38
|
|
38
|
-
def call # rubocop:disable Metrics/MethodLength
|
39
|
+
def call # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
|
39
40
|
ensure_templates!
|
40
41
|
|
41
|
-
@
|
42
|
-
@
|
43
|
-
@
|
44
|
-
@skipped_workloads = []
|
42
|
+
@created_items = []
|
43
|
+
@failed_templates = []
|
44
|
+
@skipped_templates = []
|
45
45
|
|
46
46
|
@asked_for_confirmation = false
|
47
47
|
|
@@ -57,9 +57,11 @@ module Command
|
|
57
57
|
|
58
58
|
pending_templates.each do |template, filename|
|
59
59
|
step("Applying template '#{template}'", abort_on_error: false) do
|
60
|
-
apply_template(filename)
|
61
|
-
if
|
62
|
-
|
60
|
+
items = apply_template(filename)
|
61
|
+
if items
|
62
|
+
items.each do |item|
|
63
|
+
report_success(item)
|
64
|
+
end
|
63
65
|
else
|
64
66
|
report_failure(template)
|
65
67
|
end
|
@@ -68,10 +70,9 @@ module Command
|
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
print_skipped_workloads
|
73
|
+
print_created_items
|
74
|
+
print_failed_templates
|
75
|
+
print_skipped_templates
|
75
76
|
end
|
76
77
|
|
77
78
|
private
|
@@ -126,7 +127,7 @@ module Command
|
|
126
127
|
def apply_template(filename)
|
127
128
|
data = File.read(filename)
|
128
129
|
.gsub("APP_GVC", config.app)
|
129
|
-
.gsub("APP_LOCATION", config
|
130
|
+
.gsub("APP_LOCATION", config.location)
|
130
131
|
.gsub("APP_ORG", config.org)
|
131
132
|
.gsub("APP_IMAGE", latest_image)
|
132
133
|
|
@@ -134,62 +135,37 @@ module Command
|
|
134
135
|
cp.apply_template(data)
|
135
136
|
end
|
136
137
|
|
137
|
-
def report_success(
|
138
|
-
|
139
|
-
@app_status = :success
|
140
|
-
else
|
141
|
-
@created_workloads.push(template)
|
142
|
-
end
|
138
|
+
def report_success(item)
|
139
|
+
@created_items.push(item)
|
143
140
|
end
|
144
141
|
|
145
142
|
def report_failure(template)
|
146
|
-
|
147
|
-
@app_status = :failure
|
148
|
-
else
|
149
|
-
@failed_workloads.push(template)
|
150
|
-
end
|
143
|
+
@failed_templates.push(template)
|
151
144
|
end
|
152
145
|
|
153
146
|
def report_skipped(template)
|
154
|
-
|
155
|
-
@app_status = :skipped
|
156
|
-
else
|
157
|
-
@skipped_workloads.push(template)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def print_app_status
|
162
|
-
return if @app_status == :existing
|
163
|
-
|
164
|
-
case @app_status
|
165
|
-
when :success
|
166
|
-
progress.puts("\n#{Shell.color("Created app '#{config.app}'.", :green)}")
|
167
|
-
when :failure
|
168
|
-
progress.puts("\n#{Shell.color("Failed to create app '#{config.app}'.", :red)}")
|
169
|
-
when :skipped
|
170
|
-
progress.puts("\n#{Shell.color("Skipped app '#{config.app}' (already exists).", :blue)}")
|
171
|
-
end
|
147
|
+
@skipped_templates.push(template)
|
172
148
|
end
|
173
149
|
|
174
|
-
def
|
175
|
-
return unless @
|
150
|
+
def print_created_items
|
151
|
+
return unless @created_items.any?
|
176
152
|
|
177
|
-
|
178
|
-
progress.puts("\n#{Shell.color('Created
|
153
|
+
created = @created_items.map { |item| " - [#{item[:kind]}] #{item[:name]}" }.join("\n")
|
154
|
+
progress.puts("\n#{Shell.color('Created items:', :green)}\n#{created}")
|
179
155
|
end
|
180
156
|
|
181
|
-
def
|
182
|
-
return unless @
|
157
|
+
def print_failed_templates
|
158
|
+
return unless @failed_templates.any?
|
183
159
|
|
184
|
-
|
185
|
-
progress.puts("\n#{Shell.color('Failed to
|
160
|
+
failed = @failed_templates.map { |template| " - #{template}" }.join("\n")
|
161
|
+
progress.puts("\n#{Shell.color('Failed to apply templates:', :red)}\n#{failed}")
|
186
162
|
end
|
187
163
|
|
188
|
-
def
|
189
|
-
return unless @
|
164
|
+
def print_skipped_templates
|
165
|
+
return unless @skipped_templates.any?
|
190
166
|
|
191
|
-
|
192
|
-
progress.puts("\n#{Shell.color('Skipped
|
167
|
+
skipped = @skipped_templates.map { |template| " - #{template}" }.join("\n")
|
168
|
+
progress.puts("\n#{Shell.color('Skipped templates (already exist):', :blue)}\n#{skipped}")
|
193
169
|
end
|
194
170
|
end
|
195
171
|
end
|
data/lib/command/base.rb
CHANGED
@@ -23,6 +23,8 @@ module Command
|
|
23
23
|
EXAMPLES = ""
|
24
24
|
# If `true`, hides the command from `cpl help`
|
25
25
|
HIDE = false
|
26
|
+
# Whether or not to show key information like ORG and APP name in commands
|
27
|
+
WITH_INFO_HEADER = true
|
26
28
|
|
27
29
|
NO_IMAGE_AVAILABLE = "NO_IMAGE_AVAILABLE"
|
28
30
|
|
@@ -38,6 +40,10 @@ module Command
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
43
|
+
def self.common_options
|
44
|
+
[org_option, verbose_option, trace_option]
|
45
|
+
end
|
46
|
+
|
41
47
|
def self.org_option(required: false)
|
42
48
|
{
|
43
49
|
name: :org,
|
@@ -103,6 +109,19 @@ module Command
|
|
103
109
|
}
|
104
110
|
end
|
105
111
|
|
112
|
+
def self.location_option(required: false)
|
113
|
+
{
|
114
|
+
name: :location,
|
115
|
+
params: {
|
116
|
+
aliases: ["-l"],
|
117
|
+
banner: "LOCATION_NAME",
|
118
|
+
desc: "Location name",
|
119
|
+
type: :string,
|
120
|
+
required: required
|
121
|
+
}
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
106
125
|
def self.upstream_token_option(required: false)
|
107
126
|
{
|
108
127
|
name: :upstream_token,
|
@@ -176,6 +195,29 @@ module Command
|
|
176
195
|
}
|
177
196
|
end
|
178
197
|
|
198
|
+
def self.verbose_option(required: false)
|
199
|
+
{
|
200
|
+
name: :verbose,
|
201
|
+
params: {
|
202
|
+
aliases: ["-d"],
|
203
|
+
desc: "Shows detailed logs",
|
204
|
+
type: :boolean,
|
205
|
+
required: required
|
206
|
+
}
|
207
|
+
}
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.trace_option(required: false)
|
211
|
+
{
|
212
|
+
name: :trace,
|
213
|
+
params: {
|
214
|
+
desc: "Shows trace of API calls. WARNING: may contain sensitive data",
|
215
|
+
type: :boolean,
|
216
|
+
required: required
|
217
|
+
}
|
218
|
+
}
|
219
|
+
end
|
220
|
+
|
179
221
|
def self.all_options
|
180
222
|
methods.grep(/_option$/).map { |method| send(method.to_s) }
|
181
223
|
end
|
@@ -227,6 +269,7 @@ module Command
|
|
227
269
|
end
|
228
270
|
|
229
271
|
def latest_image_next(app = config.app, org = config.org, commit: nil)
|
272
|
+
# debugger
|
230
273
|
commit ||= config.options[:commit]
|
231
274
|
|
232
275
|
@latest_image_next ||= {}
|
@@ -29,7 +29,7 @@ module Command
|
|
29
29
|
ensure_docker_running!
|
30
30
|
|
31
31
|
@upstream = config[:upstream]
|
32
|
-
@upstream_org = config.apps[@upstream.to_sym][:cpln_org]
|
32
|
+
@upstream_org = config.apps[@upstream.to_sym][:cpln_org] || ENV.fetch("CPLN_ORG_UPSTREAM", nil)
|
33
33
|
ensure_upstream_org!
|
34
34
|
|
35
35
|
create_upstream_profile
|
@@ -51,7 +51,10 @@ module Command
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def ensure_upstream_org!
|
54
|
-
|
54
|
+
return if @upstream_org
|
55
|
+
|
56
|
+
raise "Can't find option 'cpln_org' for app '#{@upstream}' in 'controlplane.yml', " \
|
57
|
+
"and CPLN_ORG_UPSTREAM env var is not set."
|
55
58
|
end
|
56
59
|
|
57
60
|
def create_upstream_profile
|
data/lib/command/delete.rb
CHANGED
@@ -7,21 +7,45 @@ module Command
|
|
7
7
|
app_option(required: true),
|
8
8
|
skip_confirm_option
|
9
9
|
].freeze
|
10
|
-
DESCRIPTION = "Deletes the whole app (GVC with all workloads and all images)"
|
10
|
+
DESCRIPTION = "Deletes the whole app (GVC with all workloads, all volumesets and all images)"
|
11
11
|
LONG_DESCRIPTION = <<~DESC
|
12
|
-
- Deletes the whole app (GVC with all workloads and all images)
|
12
|
+
- Deletes the whole app (GVC with all workloads, all volumesets and all images)
|
13
13
|
- Will ask for explicit user confirmation
|
14
14
|
DESC
|
15
15
|
|
16
16
|
def call
|
17
|
+
return progress.puts("App '#{config.app}' does not exist.") if cp.fetch_gvc.nil?
|
18
|
+
|
19
|
+
check_volumesets
|
20
|
+
check_images
|
17
21
|
return unless confirm_delete
|
18
22
|
|
23
|
+
delete_volumesets
|
19
24
|
delete_gvc
|
20
25
|
delete_images
|
21
26
|
end
|
22
27
|
|
23
28
|
private
|
24
29
|
|
30
|
+
def check_volumesets
|
31
|
+
@volumesets = cp.fetch_volumesets["items"]
|
32
|
+
return progress.puts("No volumesets to delete.") unless @volumesets.any?
|
33
|
+
|
34
|
+
message = "The following volumesets will be deleted along with the app:"
|
35
|
+
volumesets_list = @volumesets.map { |volumeset| "- #{volumeset['name']}" }.join("\n")
|
36
|
+
progress.puts("#{Shell.color(message, :red)}\n#{volumesets_list}\n\n")
|
37
|
+
end
|
38
|
+
|
39
|
+
def check_images
|
40
|
+
@images = cp.query_images["items"]
|
41
|
+
.select { |image| image["name"].start_with?("#{config.app}:") }
|
42
|
+
return progress.puts("No images to delete.") unless @images.any?
|
43
|
+
|
44
|
+
message = "The following images will be deleted along with the app:"
|
45
|
+
images_list = @images.map { |image| "- #{image['name']}" }.join("\n")
|
46
|
+
progress.puts("#{Shell.color(message, :red)}\n#{images_list}\n\n")
|
47
|
+
end
|
48
|
+
|
25
49
|
def confirm_delete
|
26
50
|
return true if config.options[:yes]
|
27
51
|
|
@@ -33,22 +57,27 @@ module Command
|
|
33
57
|
end
|
34
58
|
|
35
59
|
def delete_gvc
|
36
|
-
return progress.puts("App '#{config.app}' does not exist.") if cp.fetch_gvc.nil?
|
37
|
-
|
38
60
|
step("Deleting app '#{config.app}'") do
|
39
61
|
cp.gvc_delete
|
40
62
|
end
|
41
63
|
end
|
42
64
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
65
|
+
def delete_volumesets
|
66
|
+
@volumesets.each do |volumeset|
|
67
|
+
step("Deleting volumeset '#{volumeset['name']}'") do
|
68
|
+
# If the volumeset is attached to a workload, we need to delete the workload first
|
69
|
+
workload = volumeset.dig("status", "usedByWorkload")&.split("/")&.last
|
70
|
+
cp.delete_workload(workload) if workload
|
46
71
|
|
47
|
-
|
72
|
+
cp.delete_volumeset(volumeset["name"])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
48
76
|
|
49
|
-
|
50
|
-
|
51
|
-
|
77
|
+
def delete_images
|
78
|
+
@images.each do |image|
|
79
|
+
step("Deleting image '#{image['name']}'") do
|
80
|
+
cp.image_delete(image["name"])
|
52
81
|
end
|
53
82
|
end
|
54
83
|
end
|
data/lib/command/env.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Command
|
4
|
+
class Generator < Thor::Group
|
5
|
+
include Thor::Actions
|
6
|
+
|
7
|
+
def copy_files
|
8
|
+
directory("generator_templates", ".controlplane")
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.source_root
|
12
|
+
File.expand_path("../", __dir__)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Generate < Base
|
17
|
+
NAME = "generate"
|
18
|
+
DESCRIPTION = "Creates base Control Plane config and template files"
|
19
|
+
LONG_DESCRIPTION = <<~DESC
|
20
|
+
Creates base Control Plane config and template files
|
21
|
+
DESC
|
22
|
+
EXAMPLES = <<~EX
|
23
|
+
```sh
|
24
|
+
# Creates .controlplane directory with Control Plane config and other templates
|
25
|
+
cpl generate
|
26
|
+
```
|
27
|
+
EX
|
28
|
+
WITH_INFO_HEADER = false
|
29
|
+
|
30
|
+
def call
|
31
|
+
if controlplane_directory_exists?
|
32
|
+
Shell.warn("The directory '.controlplane' already exists!")
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
Generator.start
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def controlplane_directory_exists?
|
42
|
+
Dir.exist? ".controlplane"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/command/info.rb
CHANGED
@@ -4,7 +4,6 @@ module Command
|
|
4
4
|
class Info < Base # rubocop:disable Metrics/ClassLength
|
5
5
|
NAME = "info"
|
6
6
|
OPTIONS = [
|
7
|
-
org_option,
|
8
7
|
app_option
|
9
8
|
].freeze
|
10
9
|
DESCRIPTION = "Displays the diff between defined/available apps/workloads (apps equal GVCs)"
|
@@ -17,7 +16,7 @@ module Command
|
|
17
16
|
DESC
|
18
17
|
EXAMPLES = <<~EX
|
19
18
|
```sh
|
20
|
-
# Shows diff for all apps in all orgs.
|
19
|
+
# Shows diff for all apps in all orgs (based on `.controlplane/controlplane.yml`).
|
21
20
|
cpl info
|
22
21
|
|
23
22
|
# Shows diff for all apps in a specific org.
|
@@ -27,6 +26,7 @@ module Command
|
|
27
26
|
cpl info -a $APP_NAME
|
28
27
|
```
|
29
28
|
EX
|
29
|
+
WITH_INFO_HEADER = false
|
30
30
|
|
31
31
|
def call
|
32
32
|
@missing_apps_workloads = {}
|
@@ -84,14 +84,14 @@ module Command
|
|
84
84
|
def orgs # rubocop:disable Metrics/MethodLength
|
85
85
|
result = []
|
86
86
|
|
87
|
-
if config.
|
88
|
-
result.push(config.
|
87
|
+
if config.org
|
88
|
+
result.push(config.org)
|
89
89
|
else
|
90
90
|
config.apps.each do |app_name, app_options|
|
91
91
|
next if config.app && !app_matches?(config.app, app_name, app_options)
|
92
92
|
|
93
93
|
org = app_options[:cpln_org]
|
94
|
-
result.push(org)
|
94
|
+
result.push(org) if org && !result.include?(org)
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
data/lib/command/latest_image.rb
CHANGED
data/lib/command/maintenance.rb
CHANGED
@@ -14,6 +14,7 @@ module Command
|
|
14
14
|
- Optionally specify the maintenance workload through `maintenance_workload` in the `.controlplane/controlplane.yml` file (defaults to 'maintenance')
|
15
15
|
- Maintenance mode is only supported for domains that use path based routing mode and have a route configured for the prefix '/' on either port 80 or 443
|
16
16
|
DESC
|
17
|
+
WITH_INFO_HEADER = false
|
17
18
|
|
18
19
|
def call # rubocop:disable Metrics/MethodLength
|
19
20
|
one_off_workload = config[:one_off_workload]
|
data/lib/command/no_command.rb
CHANGED
@@ -9,11 +9,14 @@ module Command
|
|
9
9
|
- Called when no command was specified
|
10
10
|
DESC
|
11
11
|
HIDE = true
|
12
|
+
WITH_INFO_HEADER = false
|
12
13
|
|
13
14
|
def call
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
if config.options[:version]
|
16
|
+
Cpl::Cli.start(["version"])
|
17
|
+
else
|
18
|
+
Cpl::Cli.start(["help"])
|
19
|
+
end
|
17
20
|
end
|
18
21
|
end
|
19
22
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Command
|
4
|
+
class OpenConsole < Base
|
5
|
+
NAME = "open-console"
|
6
|
+
OPTIONS = [
|
7
|
+
app_option(required: true),
|
8
|
+
workload_option
|
9
|
+
].freeze
|
10
|
+
DESCRIPTION = "Opens the app console on Control Plane in the default browser"
|
11
|
+
LONG_DESCRIPTION = <<~DESC
|
12
|
+
- Opens the app console on Control Plane in the default browser
|
13
|
+
- Can also go directly to a workload page if `--workload` is provided
|
14
|
+
DESC
|
15
|
+
|
16
|
+
def call
|
17
|
+
workload = config.options[:workload]
|
18
|
+
url = "https://console.cpln.io/console/org/#{config.org}/gvc/#{config.app}"
|
19
|
+
url += "/workload/#{workload}" if workload
|
20
|
+
url += "/-info"
|
21
|
+
opener = `which xdg-open open`.split("\n").grep_v("not found").first
|
22
|
+
|
23
|
+
exec %(#{opener} "#{url}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/command/ps.rb
CHANGED
@@ -5,6 +5,7 @@ module Command
|
|
5
5
|
NAME = "ps"
|
6
6
|
OPTIONS = [
|
7
7
|
app_option(required: true),
|
8
|
+
location_option,
|
8
9
|
workload_option
|
9
10
|
].freeze
|
10
11
|
DESCRIPTION = "Shows running replicas in app"
|
@@ -20,16 +21,19 @@ module Command
|
|
20
21
|
cpl ps -a $APP_NAME -w $WORKLOAD_NAME
|
21
22
|
```
|
22
23
|
EX
|
24
|
+
WITH_INFO_HEADER = false
|
23
25
|
|
24
26
|
def call
|
25
27
|
cp.fetch_gvc!
|
26
28
|
|
29
|
+
location = config.location
|
30
|
+
|
27
31
|
workloads = [config.options[:workload]] if config.options[:workload]
|
28
32
|
workloads ||= config[:app_workloads] + config[:additional_workloads]
|
29
33
|
workloads.each do |workload|
|
30
34
|
cp.fetch_workload!(workload)
|
31
35
|
|
32
|
-
result = cp.workload_get_replicas(workload, location:
|
36
|
+
result = cp.workload_get_replicas(workload, location: location)
|
33
37
|
result["items"].each { |replica| puts replica }
|
34
38
|
end
|
35
39
|
end
|
data/lib/command/run.rb
CHANGED
@@ -10,6 +10,7 @@ module Command
|
|
10
10
|
app_option(required: true),
|
11
11
|
image_option,
|
12
12
|
workload_option,
|
13
|
+
location_option,
|
13
14
|
use_local_token_option,
|
14
15
|
terminal_size_option
|
15
16
|
].freeze
|
@@ -17,7 +18,6 @@ module Command
|
|
17
18
|
LONG_DESCRIPTION = <<~DESC
|
18
19
|
- Runs one-off **_interactive_** replicas (analog of `heroku run`)
|
19
20
|
- Uses `Standard` workload type and `cpln exec` as the execution method, with CLI streaming
|
20
|
-
- May not work correctly with tasks that last over 5 minutes (there's a Control Plane scaling bug at the moment)
|
21
21
|
- If `fix_terminal_size` is `true` in the `.controlplane/controlplane.yml` file, the remote terminal size will be fixed to match the local terminal size (may also be overriden through `--terminal-size`)
|
22
22
|
|
23
23
|
> **IMPORTANT:** Useful for development where it's needed for interaction, and where network connection drops and
|
@@ -57,7 +57,7 @@ module Command
|
|
57
57
|
attr_reader :location, :workload, :one_off, :container
|
58
58
|
|
59
59
|
def call # rubocop:disable Metrics/MethodLength
|
60
|
-
@location = config
|
60
|
+
@location = config.location
|
61
61
|
@workload = config.options["workload"] || config[:one_off_workload]
|
62
62
|
@one_off = "#{workload}-run-#{rand(1000..9999)}"
|
63
63
|
|
data/lib/command/run_detached.rb
CHANGED
@@ -9,6 +9,7 @@ module Command
|
|
9
9
|
app_option(required: true),
|
10
10
|
image_option,
|
11
11
|
workload_option,
|
12
|
+
location_option,
|
12
13
|
use_local_token_option
|
13
14
|
].freeze
|
14
15
|
DESCRIPTION = "Runs one-off **_non-interactive_** replicas (close analog of `heroku run:detached`)"
|
@@ -47,7 +48,7 @@ module Command
|
|
47
48
|
attr_reader :location, :workload, :one_off, :container
|
48
49
|
|
49
50
|
def call # rubocop:disable Metrics/MethodLength
|
50
|
-
@location = config
|
51
|
+
@location = config.location
|
51
52
|
@workload = config.options["workload"] || config[:one_off_workload]
|
52
53
|
@one_off = "#{workload}-runner-#{rand(1000..9999)}"
|
53
54
|
|
data/lib/command/setup_app.rb
CHANGED
@@ -9,12 +9,12 @@ module Command
|
|
9
9
|
DESCRIPTION = "Creates an app and all its workloads"
|
10
10
|
LONG_DESCRIPTION = <<~DESC
|
11
11
|
- Creates an app and all its workloads
|
12
|
-
- Specify the templates for the app and workloads through `
|
13
|
-
- This should
|
12
|
+
- Specify the templates for the app and workloads through `setup_app_templates` in the `.controlplane/controlplane.yml` file
|
13
|
+
- This should only be used for temporary apps like review apps, never for persistent apps like production (to update workloads for those, use 'cpl apply-template' instead)
|
14
14
|
DESC
|
15
15
|
|
16
16
|
def call
|
17
|
-
templates = config[:
|
17
|
+
templates = config[:setup_app_templates]
|
18
18
|
|
19
19
|
app = cp.fetch_gvc
|
20
20
|
if app
|