cpflow 3.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 +7 -0
- data/.github/workflows/check_cpln_links.yml +19 -0
- data/.github/workflows/command_docs.yml +24 -0
- data/.github/workflows/rspec-shared.yml +56 -0
- data/.github/workflows/rspec.yml +28 -0
- data/.github/workflows/rubocop.yml +24 -0
- data/.gitignore +18 -0
- data/.overcommit.yml +16 -0
- data/.rubocop.yml +22 -0
- data/.simplecov_spawn.rb +10 -0
- data/CHANGELOG.md +259 -0
- data/CONTRIBUTING.md +73 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +126 -0
- data/LICENSE +21 -0
- data/README.md +546 -0
- data/Rakefile +21 -0
- data/bin/cpflow +6 -0
- data/cpflow +6 -0
- data/cpflow.gemspec +41 -0
- data/docs/assets/grafana-alert.png +0 -0
- data/docs/assets/memcached.png +0 -0
- data/docs/assets/sidekiq-pre-stop-hook.png +0 -0
- data/docs/commands.md +454 -0
- data/docs/dns.md +15 -0
- data/docs/migrating.md +262 -0
- data/docs/postgres.md +436 -0
- data/docs/redis.md +128 -0
- data/docs/secrets-and-env-values.md +42 -0
- data/docs/tips.md +150 -0
- data/docs/troubleshooting.md +6 -0
- data/examples/circleci.yml +104 -0
- data/examples/controlplane.yml +159 -0
- data/lib/command/apply_template.rb +209 -0
- data/lib/command/base.rb +540 -0
- data/lib/command/build_image.rb +49 -0
- data/lib/command/cleanup_images.rb +136 -0
- data/lib/command/cleanup_stale_apps.rb +79 -0
- data/lib/command/config.rb +48 -0
- data/lib/command/copy_image_from_upstream.rb +108 -0
- data/lib/command/delete.rb +149 -0
- data/lib/command/deploy_image.rb +56 -0
- data/lib/command/doctor.rb +47 -0
- data/lib/command/env.rb +22 -0
- data/lib/command/exists.rb +23 -0
- data/lib/command/generate.rb +45 -0
- data/lib/command/info.rb +222 -0
- data/lib/command/latest_image.rb +19 -0
- data/lib/command/logs.rb +49 -0
- data/lib/command/maintenance.rb +42 -0
- data/lib/command/maintenance_off.rb +62 -0
- data/lib/command/maintenance_on.rb +62 -0
- data/lib/command/maintenance_set_page.rb +34 -0
- data/lib/command/no_command.rb +23 -0
- data/lib/command/open.rb +33 -0
- data/lib/command/open_console.rb +26 -0
- data/lib/command/promote_app_from_upstream.rb +38 -0
- data/lib/command/ps.rb +41 -0
- data/lib/command/ps_restart.rb +37 -0
- data/lib/command/ps_start.rb +51 -0
- data/lib/command/ps_stop.rb +82 -0
- data/lib/command/ps_wait.rb +40 -0
- data/lib/command/run.rb +573 -0
- data/lib/command/setup_app.rb +113 -0
- data/lib/command/test.rb +23 -0
- data/lib/command/version.rb +18 -0
- data/lib/constants/exit_code.rb +7 -0
- data/lib/core/config.rb +316 -0
- data/lib/core/controlplane.rb +552 -0
- data/lib/core/controlplane_api.rb +170 -0
- data/lib/core/controlplane_api_direct.rb +112 -0
- data/lib/core/doctor_service.rb +104 -0
- data/lib/core/helpers.rb +26 -0
- data/lib/core/shell.rb +100 -0
- data/lib/core/template_parser.rb +76 -0
- data/lib/cpflow/version.rb +6 -0
- data/lib/cpflow.rb +288 -0
- data/lib/deprecated_commands.json +9 -0
- data/lib/generator_templates/Dockerfile +27 -0
- data/lib/generator_templates/controlplane.yml +62 -0
- data/lib/generator_templates/entrypoint.sh +8 -0
- data/lib/generator_templates/templates/app.yml +21 -0
- data/lib/generator_templates/templates/postgres.yml +176 -0
- data/lib/generator_templates/templates/rails.yml +36 -0
- data/rakelib/create_release.rake +81 -0
- data/script/add_command +37 -0
- data/script/check_command_docs +3 -0
- data/script/check_cpln_links +45 -0
- data/script/rename_command +43 -0
- data/script/update_command_docs +62 -0
- data/templates/app.yml +13 -0
- data/templates/daily-task.yml +32 -0
- data/templates/maintenance.yml +25 -0
- data/templates/memcached.yml +24 -0
- data/templates/postgres.yml +32 -0
- data/templates/rails.yml +27 -0
- data/templates/redis.yml +21 -0
- data/templates/redis2.yml +37 -0
- data/templates/sidekiq.yml +38 -0
- metadata +341 -0
data/lib/command/test.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "debug"
|
4
|
+
|
5
|
+
module Command
|
6
|
+
class Test < Base
|
7
|
+
NAME = "test"
|
8
|
+
OPTIONS = all_options
|
9
|
+
DESCRIPTION = "For debugging purposes"
|
10
|
+
LONG_DESCRIPTION = <<~DESC
|
11
|
+
- For debugging purposes
|
12
|
+
DESC
|
13
|
+
HIDE = true
|
14
|
+
VALIDATIONS = [].freeze
|
15
|
+
|
16
|
+
def call
|
17
|
+
# Modify this method to trigger the code you want to test.
|
18
|
+
# You can use `debugger` to debug.
|
19
|
+
# You can use `Cpflow::Cli.start` to simulate a command
|
20
|
+
# (e.g., `Cpflow::Cli.start(["deploy-image", "-a", "my-app-name"])`).
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Command
|
4
|
+
class Version < Base
|
5
|
+
NAME = "version"
|
6
|
+
DESCRIPTION = "Displays the current version of the CLI"
|
7
|
+
LONG_DESCRIPTION = <<~DESC
|
8
|
+
- Displays the current version of the CLI
|
9
|
+
- Can also be done with `cpflow --version` or `cpflow -v`
|
10
|
+
DESC
|
11
|
+
WITH_INFO_HEADER = false
|
12
|
+
VALIDATIONS = [].freeze
|
13
|
+
|
14
|
+
def call
|
15
|
+
puts Cpflow::VERSION
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/core/config.rb
ADDED
@@ -0,0 +1,316 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "helpers"
|
4
|
+
|
5
|
+
class Config # rubocop:disable Metrics/ClassLength
|
6
|
+
attr_reader :org_comes_from_env, :app_comes_from_env,
|
7
|
+
# command line options
|
8
|
+
:args, :options, :required_options
|
9
|
+
|
10
|
+
include Helpers
|
11
|
+
|
12
|
+
CONFIG_FILE_LOCATION = ".controlplane/controlplane.yml"
|
13
|
+
|
14
|
+
def initialize(args, options, required_options)
|
15
|
+
@args = args
|
16
|
+
@options = options
|
17
|
+
@required_options = required_options
|
18
|
+
|
19
|
+
ensure_required_options!
|
20
|
+
|
21
|
+
warn_deprecated_options
|
22
|
+
|
23
|
+
Shell.verbose_mode(options[:verbose])
|
24
|
+
trace_mode = options[:trace]
|
25
|
+
return unless trace_mode
|
26
|
+
|
27
|
+
ControlplaneApiDirect.trace = trace_mode
|
28
|
+
Shell.warn("Trace mode is enabled, this will print sensitive information to the console.")
|
29
|
+
end
|
30
|
+
|
31
|
+
def org
|
32
|
+
@org ||= load_org_from_options || load_org_from_env || load_org_from_file
|
33
|
+
end
|
34
|
+
|
35
|
+
def app
|
36
|
+
@app ||= load_app_from_options || load_app_from_env
|
37
|
+
end
|
38
|
+
|
39
|
+
def app_prefix
|
40
|
+
current&.fetch(:name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def identity
|
44
|
+
"#{app}-identity"
|
45
|
+
end
|
46
|
+
|
47
|
+
def identity_link
|
48
|
+
"/org/#{org}/gvc/#{app}/identity/#{identity}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def secrets
|
52
|
+
current&.dig(:secrets_name) || "#{app_prefix}-secrets"
|
53
|
+
end
|
54
|
+
|
55
|
+
def secrets_policy
|
56
|
+
current&.dig(:secrets_policy_name) || "#{secrets}-policy"
|
57
|
+
end
|
58
|
+
|
59
|
+
def location
|
60
|
+
@location ||= load_location_from_options || load_location_from_env || load_location_from_file
|
61
|
+
end
|
62
|
+
|
63
|
+
def location_link
|
64
|
+
"/org/#{org}/location/#{location}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def image_link(image)
|
68
|
+
"/org/#{org}/image/#{image}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def domain
|
72
|
+
@domain ||= load_domain_from_options || load_domain_from_file
|
73
|
+
end
|
74
|
+
|
75
|
+
def [](key)
|
76
|
+
ensure_current_config!
|
77
|
+
|
78
|
+
raise "Can't find option '#{key}' for app '#{app}' in 'controlplane.yml'." unless current.key?(key)
|
79
|
+
|
80
|
+
current.fetch(key)
|
81
|
+
end
|
82
|
+
|
83
|
+
def script_path
|
84
|
+
Pathname.new(__dir__).parent.parent
|
85
|
+
end
|
86
|
+
|
87
|
+
def app_cpln_dir
|
88
|
+
"#{app_dir}/.controlplane"
|
89
|
+
end
|
90
|
+
|
91
|
+
def should_app_start_with?(app_name)
|
92
|
+
apps[app_name.to_sym]&.dig(:match_if_app_name_starts_with) || false
|
93
|
+
end
|
94
|
+
|
95
|
+
def app_dir
|
96
|
+
Pathname.new(config_file_path).parent.parent.to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
def config
|
100
|
+
@config ||= begin
|
101
|
+
global_config = YAML.safe_load_file(config_file_path, symbolize_names: true, aliases: true)
|
102
|
+
ensure_config!(global_config)
|
103
|
+
ensure_config_apps!(global_config)
|
104
|
+
|
105
|
+
global_config
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def apps
|
110
|
+
@apps ||= config[:apps].to_h do |app_name, app_options|
|
111
|
+
ensure_config_app!(app_name, app_options)
|
112
|
+
|
113
|
+
check_deprecated_options(app_options)
|
114
|
+
|
115
|
+
app_options_with_new_keys = app_options.to_h do |key, value|
|
116
|
+
new_key = new_option_keys[key]
|
117
|
+
new_key ? [new_key, value] : [key, value]
|
118
|
+
end
|
119
|
+
|
120
|
+
[app_name, app_options_with_new_keys]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def current
|
125
|
+
return unless app
|
126
|
+
|
127
|
+
@current ||= find_app_config(app)
|
128
|
+
end
|
129
|
+
|
130
|
+
def app_matches?(app_name1, app_name2, app_options)
|
131
|
+
app_name1 && app_name2 &&
|
132
|
+
(app_name1.to_s == app_name2.to_s ||
|
133
|
+
(app_options[:match_if_app_name_starts_with] && app_name1.to_s.start_with?(app_name2.to_s))
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
def find_app_config(app_name1)
|
138
|
+
@app_configs ||= {}
|
139
|
+
|
140
|
+
@app_configs[app_name1] ||= apps.filter_map do |app_name2, app_config|
|
141
|
+
next unless app_matches?(app_name1, app_name2, app_config)
|
142
|
+
|
143
|
+
app_config[:name] = app_name2
|
144
|
+
app_config
|
145
|
+
end&.last
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def ensure_current_config!
|
151
|
+
raise "Can't find current config, please specify an app." unless current
|
152
|
+
end
|
153
|
+
|
154
|
+
def ensure_config!(global_config)
|
155
|
+
raise "'controlplane.yml' is empty." unless global_config
|
156
|
+
end
|
157
|
+
|
158
|
+
def ensure_config_apps!(global_config)
|
159
|
+
raise "Can't find key 'apps' in 'controlplane.yml'." unless global_config[:apps]
|
160
|
+
end
|
161
|
+
|
162
|
+
def ensure_config_app!(app_name, app_options)
|
163
|
+
raise "Can't find config for app '#{app_name}' in 'controlplane.yml'." unless app_options
|
164
|
+
end
|
165
|
+
|
166
|
+
def ensure_app!
|
167
|
+
return if app
|
168
|
+
|
169
|
+
raise "No app provided. " \
|
170
|
+
"The app can be provided either through the CPLN_APP env var " \
|
171
|
+
"('allow_app_override_by_env' must be set to true in 'controlplane.yml'), " \
|
172
|
+
"or the --app command option."
|
173
|
+
end
|
174
|
+
|
175
|
+
def ensure_org!
|
176
|
+
return if org
|
177
|
+
|
178
|
+
raise "No org provided. " \
|
179
|
+
"The org can be provided either through the CPLN_ORG env var " \
|
180
|
+
"('allow_org_override_by_env' must be set to true in 'controlplane.yml'), " \
|
181
|
+
"the --org command option, " \
|
182
|
+
"or the 'cpln_org' key in 'controlplane.yml'."
|
183
|
+
end
|
184
|
+
|
185
|
+
def ensure_required_options! # rubocop:disable Metrics/CyclomaticComplexity
|
186
|
+
ensure_app! if required_options.include?(:app)
|
187
|
+
ensure_org! if required_options.include?(:org) || app
|
188
|
+
|
189
|
+
missing_str = required_options
|
190
|
+
.reject { |option_name| %i[org app].include?(option_name) || options.key?(option_name) }
|
191
|
+
.map { |option_name| "--#{option_name}" }
|
192
|
+
.join(", ")
|
193
|
+
|
194
|
+
raise "Required options missing: #{missing_str}" unless missing_str.empty?
|
195
|
+
end
|
196
|
+
|
197
|
+
def config_file_path # rubocop:disable Metrics/MethodLength
|
198
|
+
@config_file_path ||= ENV["CONFIG_FILE_PATH"] || begin
|
199
|
+
path = Pathname.new(".").expand_path
|
200
|
+
|
201
|
+
loop do
|
202
|
+
config_file = path + CONFIG_FILE_LOCATION
|
203
|
+
break config_file if File.file?(config_file)
|
204
|
+
|
205
|
+
path = path.parent
|
206
|
+
|
207
|
+
if path.root?
|
208
|
+
raise "Can't find project config file at 'project_folder/#{CONFIG_FILE_LOCATION}', please create it."
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def new_option_keys
|
215
|
+
{
|
216
|
+
org: :cpln_org,
|
217
|
+
location: :default_location,
|
218
|
+
prefix: :match_if_app_name_starts_with,
|
219
|
+
setup: :setup_app_templates,
|
220
|
+
old_image_retention_days: :image_retention_days
|
221
|
+
}
|
222
|
+
end
|
223
|
+
|
224
|
+
def load_app_from_env
|
225
|
+
app_from_env = strip_str_and_validate(ENV.fetch("CPLN_APP", nil))
|
226
|
+
return unless app_from_env
|
227
|
+
|
228
|
+
app_config = find_app_config(app_from_env)
|
229
|
+
ensure_config_app!(app_from_env, app_config)
|
230
|
+
|
231
|
+
key_exists = app_config.key?(:allow_app_override_by_env)
|
232
|
+
allowed_locally = key_exists && app_config[:allow_app_override_by_env]
|
233
|
+
allowed_globally = !key_exists && config[:allow_app_override_by_env]
|
234
|
+
return unless allowed_locally || allowed_globally
|
235
|
+
|
236
|
+
@app_comes_from_env = true
|
237
|
+
|
238
|
+
app_from_env
|
239
|
+
end
|
240
|
+
|
241
|
+
def load_app_from_options
|
242
|
+
app_from_options = strip_str_and_validate(options[:app])
|
243
|
+
return unless app_from_options
|
244
|
+
|
245
|
+
app_config = find_app_config(app_from_options)
|
246
|
+
ensure_config_app!(app_from_options, app_config)
|
247
|
+
|
248
|
+
app_from_options
|
249
|
+
end
|
250
|
+
|
251
|
+
def load_org_from_env
|
252
|
+
org_from_env = strip_str_and_validate(ENV.fetch("CPLN_ORG", nil))
|
253
|
+
return unless org_from_env
|
254
|
+
|
255
|
+
key_exists = current&.key?(:allow_org_override_by_env)
|
256
|
+
allowed_locally = key_exists && current[:allow_org_override_by_env]
|
257
|
+
allowed_globally = !key_exists && config[:allow_org_override_by_env]
|
258
|
+
return unless allowed_locally || allowed_globally
|
259
|
+
|
260
|
+
@org_comes_from_env = true
|
261
|
+
|
262
|
+
org_from_env
|
263
|
+
end
|
264
|
+
|
265
|
+
def load_org_from_options
|
266
|
+
strip_str_and_validate(options[:org])
|
267
|
+
end
|
268
|
+
|
269
|
+
def load_org_from_file
|
270
|
+
return unless current&.key?(:cpln_org)
|
271
|
+
|
272
|
+
strip_str_and_validate(current[:cpln_org])
|
273
|
+
end
|
274
|
+
|
275
|
+
def load_location_from_options
|
276
|
+
strip_str_and_validate(options[:location])
|
277
|
+
end
|
278
|
+
|
279
|
+
def load_location_from_env
|
280
|
+
strip_str_and_validate(ENV.fetch("CPLN_LOCATION", nil))
|
281
|
+
end
|
282
|
+
|
283
|
+
def load_location_from_file
|
284
|
+
return unless current&.key?(:default_location)
|
285
|
+
|
286
|
+
strip_str_and_validate(current.fetch(:default_location))
|
287
|
+
end
|
288
|
+
|
289
|
+
def load_domain_from_options
|
290
|
+
strip_str_and_validate(options[:domain])
|
291
|
+
end
|
292
|
+
|
293
|
+
def load_domain_from_file
|
294
|
+
return unless current&.key?(:default_domain)
|
295
|
+
|
296
|
+
strip_str_and_validate(current.fetch(:default_domain))
|
297
|
+
end
|
298
|
+
|
299
|
+
def check_deprecated_options(app_options)
|
300
|
+
@deprecated_option_keys ||= {}
|
301
|
+
|
302
|
+
new_option_keys.each do |old_key, new_key|
|
303
|
+
@deprecated_option_keys[old_key] = new_key if app_options.key?(old_key)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def warn_deprecated_options
|
308
|
+
return if !@deprecated_option_keys || @deprecated_option_keys.empty?
|
309
|
+
|
310
|
+
@deprecated_option_keys.each do |old_key, new_key|
|
311
|
+
Shell.warn_deprecated("Option '#{old_key}' is deprecated, " \
|
312
|
+
"please use '#{new_key}' instead (in 'controlplane.yml').")
|
313
|
+
end
|
314
|
+
$stderr.puts
|
315
|
+
end
|
316
|
+
end
|