cpflow 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/check_cpln_links.yml +19 -0
  3. data/.github/workflows/command_docs.yml +24 -0
  4. data/.github/workflows/rspec-shared.yml +56 -0
  5. data/.github/workflows/rspec.yml +28 -0
  6. data/.github/workflows/rubocop.yml +24 -0
  7. data/.gitignore +18 -0
  8. data/.overcommit.yml +16 -0
  9. data/.rubocop.yml +22 -0
  10. data/.simplecov_spawn.rb +10 -0
  11. data/CHANGELOG.md +259 -0
  12. data/CONTRIBUTING.md +73 -0
  13. data/Gemfile +7 -0
  14. data/Gemfile.lock +126 -0
  15. data/LICENSE +21 -0
  16. data/README.md +546 -0
  17. data/Rakefile +21 -0
  18. data/bin/cpflow +6 -0
  19. data/cpflow +6 -0
  20. data/cpflow.gemspec +41 -0
  21. data/docs/assets/grafana-alert.png +0 -0
  22. data/docs/assets/memcached.png +0 -0
  23. data/docs/assets/sidekiq-pre-stop-hook.png +0 -0
  24. data/docs/commands.md +454 -0
  25. data/docs/dns.md +15 -0
  26. data/docs/migrating.md +262 -0
  27. data/docs/postgres.md +436 -0
  28. data/docs/redis.md +128 -0
  29. data/docs/secrets-and-env-values.md +42 -0
  30. data/docs/tips.md +150 -0
  31. data/docs/troubleshooting.md +6 -0
  32. data/examples/circleci.yml +104 -0
  33. data/examples/controlplane.yml +159 -0
  34. data/lib/command/apply_template.rb +209 -0
  35. data/lib/command/base.rb +540 -0
  36. data/lib/command/build_image.rb +49 -0
  37. data/lib/command/cleanup_images.rb +136 -0
  38. data/lib/command/cleanup_stale_apps.rb +79 -0
  39. data/lib/command/config.rb +48 -0
  40. data/lib/command/copy_image_from_upstream.rb +108 -0
  41. data/lib/command/delete.rb +149 -0
  42. data/lib/command/deploy_image.rb +56 -0
  43. data/lib/command/doctor.rb +47 -0
  44. data/lib/command/env.rb +22 -0
  45. data/lib/command/exists.rb +23 -0
  46. data/lib/command/generate.rb +45 -0
  47. data/lib/command/info.rb +222 -0
  48. data/lib/command/latest_image.rb +19 -0
  49. data/lib/command/logs.rb +49 -0
  50. data/lib/command/maintenance.rb +42 -0
  51. data/lib/command/maintenance_off.rb +62 -0
  52. data/lib/command/maintenance_on.rb +62 -0
  53. data/lib/command/maintenance_set_page.rb +34 -0
  54. data/lib/command/no_command.rb +23 -0
  55. data/lib/command/open.rb +33 -0
  56. data/lib/command/open_console.rb +26 -0
  57. data/lib/command/promote_app_from_upstream.rb +38 -0
  58. data/lib/command/ps.rb +41 -0
  59. data/lib/command/ps_restart.rb +37 -0
  60. data/lib/command/ps_start.rb +51 -0
  61. data/lib/command/ps_stop.rb +82 -0
  62. data/lib/command/ps_wait.rb +40 -0
  63. data/lib/command/run.rb +573 -0
  64. data/lib/command/setup_app.rb +113 -0
  65. data/lib/command/test.rb +23 -0
  66. data/lib/command/version.rb +18 -0
  67. data/lib/constants/exit_code.rb +7 -0
  68. data/lib/core/config.rb +316 -0
  69. data/lib/core/controlplane.rb +552 -0
  70. data/lib/core/controlplane_api.rb +170 -0
  71. data/lib/core/controlplane_api_direct.rb +112 -0
  72. data/lib/core/doctor_service.rb +104 -0
  73. data/lib/core/helpers.rb +26 -0
  74. data/lib/core/shell.rb +100 -0
  75. data/lib/core/template_parser.rb +76 -0
  76. data/lib/cpflow/version.rb +6 -0
  77. data/lib/cpflow.rb +288 -0
  78. data/lib/deprecated_commands.json +9 -0
  79. data/lib/generator_templates/Dockerfile +27 -0
  80. data/lib/generator_templates/controlplane.yml +62 -0
  81. data/lib/generator_templates/entrypoint.sh +8 -0
  82. data/lib/generator_templates/templates/app.yml +21 -0
  83. data/lib/generator_templates/templates/postgres.yml +176 -0
  84. data/lib/generator_templates/templates/rails.yml +36 -0
  85. data/rakelib/create_release.rake +81 -0
  86. data/script/add_command +37 -0
  87. data/script/check_command_docs +3 -0
  88. data/script/check_cpln_links +45 -0
  89. data/script/rename_command +43 -0
  90. data/script/update_command_docs +62 -0
  91. data/templates/app.yml +13 -0
  92. data/templates/daily-task.yml +32 -0
  93. data/templates/maintenance.yml +25 -0
  94. data/templates/memcached.yml +24 -0
  95. data/templates/postgres.yml +32 -0
  96. data/templates/rails.yml +27 -0
  97. data/templates/redis.yml +21 -0
  98. data/templates/redis2.yml +37 -0
  99. data/templates/sidekiq.yml +38 -0
  100. metadata +341 -0
@@ -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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExitCode
4
+ SUCCESS = 0
5
+ ERROR_DEFAULT = 64
6
+ INTERRUPT = 130
7
+ end
@@ -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