cpl 1.1.2 → 1.3.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check_cpln_links.yml +19 -0
  3. data/.github/workflows/rspec.yml +1 -1
  4. data/.overcommit.yml +3 -0
  5. data/CHANGELOG.md +47 -2
  6. data/CONTRIBUTING.md +2 -6
  7. data/Gemfile.lock +8 -8
  8. data/README.md +57 -15
  9. data/docs/commands.md +29 -23
  10. data/docs/dns.md +9 -0
  11. data/docs/migrating.md +3 -3
  12. data/examples/controlplane.yml +67 -4
  13. data/lib/command/apply_template.rb +2 -1
  14. data/lib/command/base.rb +62 -0
  15. data/lib/command/build_image.rb +5 -1
  16. data/lib/command/config.rb +0 -5
  17. data/lib/command/copy_image_from_upstream.rb +5 -4
  18. data/lib/command/delete.rb +40 -11
  19. data/lib/command/env.rb +1 -0
  20. data/lib/command/generate.rb +45 -0
  21. data/lib/command/info.rb +15 -33
  22. data/lib/command/latest_image.rb +1 -0
  23. data/lib/command/maintenance.rb +9 -4
  24. data/lib/command/maintenance_off.rb +8 -4
  25. data/lib/command/maintenance_on.rb +8 -4
  26. data/lib/command/no_command.rb +1 -0
  27. data/lib/command/ps.rb +5 -1
  28. data/lib/command/run.rb +20 -23
  29. data/lib/command/run_detached.rb +38 -30
  30. data/lib/command/setup_app.rb +3 -3
  31. data/lib/command/version.rb +1 -0
  32. data/lib/core/config.rb +194 -66
  33. data/lib/core/controlplane.rb +28 -7
  34. data/lib/core/controlplane_api.rb +13 -1
  35. data/lib/core/controlplane_api_direct.rb +18 -2
  36. data/lib/core/helpers.rb +16 -0
  37. data/lib/core/shell.rb +25 -3
  38. data/lib/cpl/version.rb +1 -1
  39. data/lib/cpl.rb +32 -3
  40. data/lib/generator_templates/Dockerfile +27 -0
  41. data/lib/generator_templates/controlplane.yml +57 -0
  42. data/lib/generator_templates/entrypoint.sh +8 -0
  43. data/lib/generator_templates/templates/gvc.yml +21 -0
  44. data/lib/generator_templates/templates/postgres.yml +176 -0
  45. data/lib/generator_templates/templates/rails.yml +36 -0
  46. data/script/check_cpln_links +45 -0
  47. metadata +14 -3
@@ -23,9 +23,10 @@ class Controlplane # rubocop:disable Metrics/ClassLength
23
23
  end
24
24
 
25
25
  def profile_create(profile, token)
26
+ sensitive_data_pattern = /(?<=--token )(\S+)/
26
27
  cmd = "cpln profile create #{profile} --token #{token}"
27
28
  cmd += " > /dev/null" if Shell.should_hide_output?
28
- perform!(cmd)
29
+ perform!(cmd, sensitive_data_pattern: sensitive_data_pattern)
29
30
  end
30
31
 
31
32
  def profile_delete(profile)
@@ -43,11 +44,13 @@ class Controlplane # rubocop:disable Metrics/ClassLength
43
44
  api.query_images(org: a_org, gvc: a_gvc, gvc_op_type: gvc_op)
44
45
  end
45
46
 
46
- def image_build(image, dockerfile:, build_args: [], push: true)
47
+ def image_build(image, dockerfile:, docker_args: [], build_args: [], push: true)
47
48
  # https://docs.controlplane.com/guides/push-image#step-2
48
49
  # Might need to use `docker buildx build` if compatiblitity issues arise
49
50
  cmd = "docker build --platform=linux/amd64 -t #{image} -f #{dockerfile}"
51
+ cmd += " --progress=plain" if ControlplaneApiDirect.trace
50
52
 
53
+ cmd += " #{docker_args.join(' ')}" if docker_args.any?
51
54
  build_args.each { |build_arg| cmd += " --build-arg #{build_arg}" }
52
55
  cmd += " #{config.app_dir}"
53
56
  perform!(cmd)
@@ -234,6 +237,16 @@ class Controlplane # rubocop:disable Metrics/ClassLength
234
237
  perform!(cmd)
235
238
  end
236
239
 
240
+ # volumeset
241
+
242
+ def fetch_volumesets(a_gvc = gvc)
243
+ api.list_volumesets(org: org, gvc: a_gvc)
244
+ end
245
+
246
+ def delete_volumeset(volumeset, a_gvc = gvc)
247
+ api.delete_volumeset(org: org, gvc: a_gvc, volumeset: volumeset)
248
+ end
249
+
237
250
  # domain
238
251
 
239
252
  def find_domain_route(data)
@@ -252,13 +265,21 @@ class Controlplane # rubocop:disable Metrics/ClassLength
252
265
  route = find_domain_route(domain_data)
253
266
  next false if route.nil?
254
267
 
255
- workloads.any? { |workload| route["workloadLink"].split("/").last == workload }
268
+ workloads.any? { |workload| route["workloadLink"].match?(%r{/org/#{org}/gvc/#{gvc}/workload/#{workload}}) }
256
269
  end
257
270
  end
258
271
 
259
- def get_domain_workload(data)
272
+ def fetch_domain(domain)
273
+ domain_data = api.fetch_domain(org: org, domain: domain)
274
+ route = find_domain_route(domain_data)
275
+ return nil if route.nil?
276
+
277
+ domain_data
278
+ end
279
+
280
+ def domain_workload_matches?(data, workload)
260
281
  route = find_domain_route(data)
261
- route["workloadLink"].split("/").last
282
+ route["workloadLink"].match?(%r{/org/#{org}/gvc/#{gvc}/workload/#{workload}})
262
283
  end
263
284
 
264
285
  def set_domain_workload(data, workload)
@@ -346,8 +367,8 @@ class Controlplane # rubocop:disable Metrics/ClassLength
346
367
  system(cmd)
347
368
  end
348
369
 
349
- def perform!(cmd)
350
- Shell.debug("CMD", cmd)
370
+ def perform!(cmd, sensitive_data_pattern: nil)
371
+ Shell.debug("CMD", cmd, sensitive_data_pattern: sensitive_data_pattern)
351
372
 
352
373
  system(cmd) || exit(false)
353
374
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class ControlplaneApi
3
+ class ControlplaneApi # rubocop:disable Metrics/ClassLength
4
4
  def gvc_list(org:)
5
5
  api_json("/org/#{org}/gvc", method: :get)
6
6
  end
@@ -86,6 +86,18 @@ class ControlplaneApi
86
86
  api_json("/org/#{org}/gvc/#{gvc}/workload/#{workload}", method: :delete)
87
87
  end
88
88
 
89
+ def list_volumesets(org:, gvc:)
90
+ api_json("/org/#{org}/gvc/#{gvc}/volumeset", method: :get)
91
+ end
92
+
93
+ def delete_volumeset(org:, gvc:, volumeset:)
94
+ api_json("/org/#{org}/gvc/#{gvc}/volumeset/#{volumeset}", method: :delete)
95
+ end
96
+
97
+ def fetch_domain(org:, domain:)
98
+ api_json("/org/#{org}/domain/#{domain}", method: :get)
99
+ end
100
+
89
101
  def list_domains(org:)
90
102
  api_json("/org/#{org}/domain", method: :get)
91
103
  end
@@ -17,7 +17,12 @@ class ControlplaneApiDirect
17
17
 
18
18
  API_TOKEN_REGEX = /^[\w\-._]+$/.freeze
19
19
 
20
- def call(url, method:, host: :api, body: nil) # rubocop:disable Metrics/MethodLength
20
+ class << self
21
+ attr_accessor :trace
22
+ end
23
+
24
+ def call(url, method:, host: :api, body: nil) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
25
+ trace = ControlplaneApiDirect.trace
21
26
  uri = URI("#{api_host(host)}#{url}")
22
27
  request = API_METHODS[method].new(uri)
23
28
  request["Content-Type"] = "application/json"
@@ -26,7 +31,11 @@ class ControlplaneApiDirect
26
31
 
27
32
  Shell.debug(method.upcase, "#{uri} #{body&.to_json}")
28
33
 
29
- response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) }
34
+ http = Net::HTTP.new(uri.hostname, uri.port)
35
+ http.use_ssl = uri.scheme == "https"
36
+ http.set_debug_output($stdout) if trace
37
+
38
+ response = http.start { |ht| ht.request(request) }
30
39
 
31
40
  case response
32
41
  when Net::HTTPOK
@@ -35,6 +44,9 @@ class ControlplaneApiDirect
35
44
  true
36
45
  when Net::HTTPNotFound
37
46
  nil
47
+ when Net::HTTPForbidden
48
+ org = self.class.parse_org(url)
49
+ raise("Double check your org #{org}. #{response} #{response.body}")
38
50
  else
39
51
  raise("#{response} #{response.body}")
40
52
  end
@@ -65,4 +77,8 @@ class ControlplaneApiDirect
65
77
  remove_class_variable(:@@api_token) if defined?(@@api_token)
66
78
  end
67
79
  # rubocop:enable Style/ClassVars
80
+
81
+ def self.parse_org(url)
82
+ url.match(%r{^/org/([^/]+)})[1]
83
+ end
68
84
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module Helpers
6
+ def strip_str_and_validate(str)
7
+ return str if str.nil?
8
+
9
+ str = str.strip
10
+ str.empty? ? nil : str
11
+ end
12
+
13
+ def random_four_digits
14
+ SecureRandom.random_number(1000..9999)
15
+ end
16
+ end
data/lib/core/shell.rb CHANGED
@@ -36,7 +36,7 @@ class Shell
36
36
  end
37
37
 
38
38
  def self.confirm(message)
39
- shell.yes?("#{message} (y/n)")
39
+ shell.yes?("#{message} (y/N)")
40
40
  end
41
41
 
42
42
  def self.warn(message)
@@ -55,11 +55,33 @@ class Shell
55
55
  @verbose = verbose
56
56
  end
57
57
 
58
- def self.debug(prefix, message)
59
- stderr.puts("\n[#{color(prefix, :red)}] #{message}") if verbose
58
+ def self.debug(prefix, message, sensitive_data_pattern: nil)
59
+ return unless verbose
60
+
61
+ filtered_message = hide_sensitive_data(message, sensitive_data_pattern)
62
+ stderr.puts("\n[#{color(prefix, :red)}] #{filtered_message}")
60
63
  end
61
64
 
62
65
  def self.should_hide_output?
63
66
  tmp_stderr && !verbose
64
67
  end
68
+
69
+ #
70
+ # Hide sensitive data based on the passed pattern
71
+ #
72
+ # @param [String] message
73
+ # The message to get processed.
74
+ # @param [Regexp, nil] pattern
75
+ # The regular expression to be used. If not provided, no filter gets applied.
76
+ #
77
+ # @return [String]
78
+ # Filtered message.
79
+ #
80
+ # @example
81
+ # hide_sensitive_data("--token abcd", /(?<=--token )(\S+)/)
82
+ def self.hide_sensitive_data(message, pattern = nil)
83
+ return message unless pattern.is_a?(Regexp)
84
+
85
+ message.gsub(pattern, "XXXXXXX")
86
+ end
65
87
  end
data/lib/cpl/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cpl
4
- VERSION = "1.1.2"
4
+ VERSION = "1.3.0"
5
5
  MIN_CPLN_VERSION = "0.0.71"
6
6
  end
data/lib/cpl.rb CHANGED
@@ -141,11 +141,13 @@ module Cpl
141
141
  usage = command_class::USAGE.empty? ? name : command_class::USAGE
142
142
  requires_args = command_class::REQUIRES_ARGS
143
143
  default_args = command_class::DEFAULT_ARGS
144
- command_options = command_class::OPTIONS + [::Command::Base.verbose_option]
144
+ command_options = command_class::OPTIONS + ::Command::Base.common_options
145
+ accepts_extra_options = command_class::ACCEPTS_EXTRA_OPTIONS
145
146
  description = command_class::DESCRIPTION
146
147
  long_description = command_class::LONG_DESCRIPTION
147
148
  examples = command_class::EXAMPLES
148
149
  hide = command_class::HIDE || deprecated
150
+ with_info_header = command_class::WITH_INFO_HEADER
149
151
 
150
152
  long_description += "\n#{examples}" if examples.length.positive?
151
153
 
@@ -160,6 +162,10 @@ module Cpl
160
162
  method_option(option[:name], **option[:params])
161
163
  end
162
164
 
165
+ # We'll handle required options manually in `Config`
166
+ required_options = command_options.select { |option| option[:params][:required] }.map { |option| option[:name] }
167
+ disable_required_check! name_for_method.to_sym if required_options.any?
168
+
163
169
  define_method(name_for_method) do |*provided_args| # rubocop:disable Metrics/MethodLength
164
170
  if deprecated
165
171
  ::Shell.warn_deprecated("Command '#{command_key}' is deprecated, " \
@@ -173,10 +179,14 @@ module Cpl
173
179
  default_args
174
180
  end
175
181
 
176
- raise_args_error.call(args, nil) if (args.empty? && requires_args) || (!args.empty? && !requires_args)
182
+ if (args.empty? && requires_args) || (!args.empty? && !requires_args && !accepts_extra_options)
183
+ raise_args_error.call(args, nil)
184
+ end
177
185
 
178
186
  begin
179
- config = Config.new(args, options)
187
+ config = Config.new(args, options, required_options)
188
+
189
+ Cpl::Cli.show_info_header(config) if with_info_header
180
190
 
181
191
  command_class.new(config).call
182
192
  rescue RuntimeError => e
@@ -186,6 +196,25 @@ module Cpl
186
196
  rescue StandardError => e
187
197
  ::Shell.abort("Unable to load command: #{e.message}")
188
198
  end
199
+
200
+ def self.show_info_header(config) # rubocop:disable Metrics/MethodLength
201
+ return if @showed_info_header
202
+
203
+ rows = {}
204
+ rows["ORG"] = config.org || "NOT PROVIDED!"
205
+ rows["ORG"] += " (comes from CPLN_ORG env var)" if config.org_comes_from_env
206
+ rows["APP"] = config.app || "NOT PROVIDED!"
207
+ rows["APP"] += " (comes from CPLN_APP env var)" if config.app_comes_from_env
208
+
209
+ rows.each do |key, value|
210
+ puts "#{key}: #{value}"
211
+ end
212
+
213
+ @showed_info_header = true
214
+
215
+ # Add a newline after the info header
216
+ puts
217
+ end
189
218
  end
190
219
  end
191
220
 
@@ -0,0 +1,27 @@
1
+ FROM ruby:3.1.2
2
+
3
+ RUN apt-get update
4
+
5
+ WORKDIR /app
6
+
7
+ # install ruby gems
8
+ COPY Gemfile* ./
9
+
10
+ RUN bundle config set without 'development test' && \
11
+ bundle config set with 'staging production' && \
12
+ bundle install --jobs=3 --retry=3
13
+
14
+ COPY . ./
15
+
16
+ ENV RAILS_ENV=production
17
+
18
+ # compiling assets requires any value for ENV of SECRET_KEY_BASE
19
+ ENV SECRET_KEY_BASE=NOT_USED_NON_BLANK
20
+
21
+ RUN rails assets:precompile
22
+
23
+ # add entrypoint
24
+ COPY .controlplane/entrypoint.sh ./
25
+ ENTRYPOINT ["/app/entrypoint.sh"]
26
+
27
+ CMD ["rails", "s"]
@@ -0,0 +1,57 @@
1
+ # Keys beginning with "cpln_" correspond to your settings in Control Plane.
2
+
3
+ # You can opt out of allowing the use of CPLN_ORG and CPLN_APP env vars
4
+ # to avoid any accidents with the wrong org / app.
5
+ allow_org_override_by_env: true
6
+ allow_app_override_by_env: true
7
+
8
+ aliases:
9
+ common: &common
10
+ # Organization name for staging (customize to your needs).
11
+ # Production apps will use a different organization, specified below, for security.
12
+ cpln_org: my-org-staging
13
+
14
+ # Example apps use only one location. Control Plane offers the ability to use multiple locations.
15
+ # TODO: Allow specification of multiple locations.
16
+ default_location: aws-us-east-2
17
+
18
+ # Configure the workload name used as a template for one-off scripts, like a Heroku one-off dyno.
19
+ one_off_workload: rails
20
+
21
+ # Workloads that are for the application itself and are using application Docker images.
22
+ app_workloads:
23
+ - rails
24
+
25
+ # Additional "service type" workloads, using non-application Docker images.
26
+ additional_workloads:
27
+ - postgres
28
+
29
+ # Configure the workload name used when maintenance mode is on (defaults to "maintenance")
30
+ maintenance_workload: maintenance
31
+
32
+ apps:
33
+ my-app-staging:
34
+ # Use the values from the common section above.
35
+ <<: *common
36
+ my-app-review:
37
+ <<: *common
38
+ # If `match_if_app_name_starts_with` is `true`, then use this config for app names starting with this name,
39
+ # e.g., "my-app-review-pr123", "my-app-review-anything-goes", etc.
40
+ match_if_app_name_starts_with: true
41
+ my-app-production:
42
+ <<: *common
43
+
44
+ # You can also opt out of allowing the use of CPLN_ORG and CPLN_APP env vars per app.
45
+ # It's recommended to leave this off for production, to avoid any accidents.
46
+ allow_org_override_by_env: false
47
+ allow_app_override_by_env: false
48
+
49
+ # Use a different organization for production.
50
+ cpln_org: my-org-production
51
+ # Allows running the command `cpl promote-app-from-upstream -a my-app-production`
52
+ # to promote the staging app to production.
53
+ upstream: my-app-staging
54
+ my-app-other:
55
+ <<: *common
56
+ # You can specify a different `Dockerfile` relative to the `.controlplane/` directory (defaults to "Dockerfile").
57
+ dockerfile: ../some_other/Dockerfile
@@ -0,0 +1,8 @@
1
+ #!/bin/sh
2
+ # Runs before the main command
3
+
4
+ echo " -- Preparing database"
5
+ rails db:prepare
6
+
7
+ echo " -- Finishing entrypoint.sh, executing '$@'"
8
+ exec "$@"
@@ -0,0 +1,21 @@
1
+ # Template setup of the GVC, roughly corresponding to a Heroku app
2
+ kind: gvc
3
+ name: APP_GVC
4
+ spec:
5
+ # For using templates for test apps, put ENV values here, stored in git repo.
6
+ # Production apps will have values configured manually after app creation.
7
+ env:
8
+ - name: DATABASE_URL
9
+ # Password does not matter because host postgres.APP_GVC.cpln.local can only be accessed
10
+ # locally within CPLN GVC, and postgres running on a CPLN workload is something only for a
11
+ # test app that lacks persistence.
12
+ value: 'postgres://the_user:the_password@postgres.APP_GVC.cpln.local:5432/APP_GVC'
13
+ - name: RAILS_ENV
14
+ value: production
15
+ - name: RAILS_SERVE_STATIC_FILES
16
+ value: 'true'
17
+
18
+ # Part of standard configuration
19
+ staticPlacement:
20
+ locationLinks:
21
+ - /org/APP_ORG/location/APP_LOCATION
@@ -0,0 +1,176 @@
1
+ # Comes from example at
2
+ # https://github.com/controlplane-com/examples/blob/main/examples/postgres/manifest.yaml
3
+
4
+ kind: volumeset
5
+ name: postgres-poc-vs
6
+ description: postgres-poc-vs
7
+ spec:
8
+ autoscaling:
9
+ maxCapacity: 1000
10
+ minFreePercentage: 1
11
+ scalingFactor: 1.1
12
+ fileSystemType: ext4
13
+ initialCapacity: 10
14
+ performanceClass: general-purpose-ssd
15
+ snapshots:
16
+ createFinalSnapshot: true
17
+ retentionDuration: 7d
18
+
19
+ ---
20
+ kind: secret
21
+ name: postgres-poc-credentials
22
+ description: ''
23
+ type: dictionary
24
+ data:
25
+ password: the_password #Replace this with a real password
26
+ username: the_user #Replace this with a real username
27
+
28
+ ---
29
+ kind: secret
30
+ name: postgres-poc-entrypoint-script
31
+ type: opaque
32
+ data:
33
+ encoding: base64
34
+ payload: >-
35
+ IyEvdXNyL2Jpbi9lbnYgYmFzaAoKc291cmNlIC91c3IvbG9jYWwvYmluL2RvY2tlci1lbnRyeXBvaW50LnNoCgppbnN0YWxsX2RlcHMoKSB7CiAgYXB0LWdldCB1cGRhdGUgLXkgPiAvZGV2L251bGwKICBhcHQtZ2V0IGluc3RhbGwgY3VybCAteSA+IC9kZXYvbnVsbAogIGFwdC1nZXQgaW5zdGFsbCB1bnppcCAteSA+IC9kZXYvbnVsbAogIGN1cmwgImh0dHBzOi8vYXdzY2xpLmFtYXpvbmF3cy5jb20vYXdzY2xpLWV4ZS1saW51eC14ODZfNjQuemlwIiAtbyAiYXdzY2xpdjIuemlwIiA+IC9kZXYvbnVsbAogIHVuemlwIGF3c2NsaXYyLnppcCA+IC9kZXYvbnVsbAogIC4vYXdzL2luc3RhbGwgPiAvZGV2L251bGwKfQoKZGJfaGFzX2JlZW5fcmVzdG9yZWQoKSB7CiAgaWYgWyAhIC1mICIkUEdEQVRBL0NQTE5fUkVTVE9SRUQiIF07IHRoZW4KICAgIHJldHVybiAxCiAgZmkKCiAgaWYgISBncmVwIC1xICJcLT4gJDEkIiAiJFBHREFUQS9DUExOX1JFU1RPUkVEIjsgdGhlbgogICAgcmV0dXJuIDEKICBlbHNlCiAgICByZXR1cm4gMAogIGZpCn0KCnJlc3RvcmVfZGIoKSB7Cgl3aGlsZSBbICEgLVMgL3Zhci9ydW4vcG9zdGdyZXNxbC8ucy5QR1NRTC41NDMyIF0KCWRvCiAgICBlY2hvICJXYWl0aW5nIDVzIGZvciBkYiBzb2NrZXQgdG8gYmUgYXZhaWxhYmxlIgogICAgc2xlZXAgNXMKICBkb25lCgoKCWlmICEgZGJfaGFzX2JlZW5fcmVzdG9yZWQgIiQxIjsgdGhlbgoJICBlY2hvICJJdCBhcHBlYXJzIGRiICckMScgaGFzIG5vdCB5ZXQgYmVlbiByZXN0b3JlZCBmcm9tIFMzLiBBdHRlbXB0aW5nIHRvIHJlc3RvcmUgJDEgZnJvbSAkMiIKCSAgaW5zdGFsbF9kZXBzCgkgIGRvY2tlcl9zZXR1cF9kYiAjRW5zdXJlcyAkUE9TVEdSRVNfREIgZXhpc3RzIChkZWZpbmVkIGluIHRoZSBlbnRyeXBvaW50IHNjcmlwdCBmcm9tIHRoZSBwb3N0Z3JlcyBkb2NrZXIgaW1hZ2UpCgkgIGF3cyBzMyBjcCAiJDIiIC0gfCBwZ19yZXN0b3JlIC0tY2xlYW4gLS1uby1hY2wgLS1uby1vd25lciAtZCAiJDEiIC1VICIkUE9TVEdSRVNfVVNFUiIKCSAgZWNobyAiJChkYXRlKTogJDIgLT4gJDEiIHwgY2F0ID4+ICIkUEdEQVRBL0NQTE5fUkVTVE9SRUQiCgllbHNlCgkgIGVjaG8gIkRiICckMScgYWxyZWFkeSBleGlzdHMuIFJlYWR5ISIKICBmaQp9CgpfbWFpbiAiJEAiICYKYmFja2dyb3VuZFByb2Nlc3M9JCEKCmlmIFsgLW4gIiRQT1NUR1JFU19BUkNISVZFX1VSSSIgXTsgdGhlbgogIHJlc3RvcmVfZGIgIiRQT1NUR1JFU19EQiIgIiRQT1NUR1JFU19BUkNISVZFX1VSSSIKZWxzZQogIGVjaG8gIkRlY2xpbmluZyB0byByZXN0b3JlIHRoZSBkYiBiZWNhdXNlIG5vIGFyY2hpdmUgdXJpIHdhcyBwcm92aWRlZCIKZmkKCndhaXQgJGJhY2tncm91bmRQcm9jZXNzCgoK
36
+
37
+ #Here is the ASCII-encoded version of the script in the secret above
38
+ #!/usr/bin/env bash
39
+ #
40
+ #source /usr/local/bin/docker-entrypoint.sh
41
+ #
42
+ #install_deps() {
43
+ # apt-get update -y > /dev/null
44
+ # apt-get install curl -y > /dev/null
45
+ # apt-get install unzip -y > /dev/null
46
+ # curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" > /dev/null
47
+ # unzip awscliv2.zip > /dev/null
48
+ # ./aws/install > /dev/null
49
+ #}
50
+ #
51
+ #db_has_been_restored() {
52
+ # if [ ! -f "$PGDATA/CPLN_RESTORED" ]; then
53
+ # return 1
54
+ # fi
55
+ #
56
+ # if ! grep -q "\-> $1$" "$PGDATA/CPLN_RESTORED"; then
57
+ # return 1
58
+ # else
59
+ # return 0
60
+ # fi
61
+ #}
62
+ #
63
+ #restore_db() {
64
+ # while [ ! -S /var/run/postgresql/.s.PGSQL.5432 ]
65
+ # do
66
+ # echo "Waiting 5s for db socket to be available"
67
+ # sleep 5s
68
+ # done
69
+ #
70
+ #
71
+ # if ! db_has_been_restored "$1"; then
72
+ # echo "It appears db '$1' has not yet been restored from S3. Attempting to restore $1 from $2"
73
+ # install_deps
74
+ # docker_setup_db #Ensures $POSTGRES_DB exists (defined in the entrypoint script from the postgres docker image)
75
+ # aws s3 cp "$2" - | pg_restore --clean --no-acl --no-owner -d "$1" -U "$POSTGRES_USER"
76
+ # echo "$(date): $2 -> $1" | cat >> "$PGDATA/CPLN_RESTORED"
77
+ # else
78
+ # echo "Db '$1' already exists. Ready!"
79
+ # fi
80
+ #}
81
+ #
82
+ #_main "$@" &
83
+ #backgroundProcess=$!
84
+ #
85
+ #if [ -n "$POSTGRES_ARCHIVE_URI" ]; then
86
+ # restore_db "$POSTGRES_DB" "$POSTGRES_ARCHIVE_URI"
87
+ #else
88
+ # echo "Declining to restore the db because no archive uri was provided"
89
+ #fi
90
+ #
91
+ #wait $backgroundProcess
92
+
93
+ ---
94
+ kind: identity
95
+ name: postgres-poc-identity
96
+ description: postgres-poc-identity
97
+
98
+ ---
99
+ kind: policy
100
+ name: postgres-poc-access
101
+ description: postgres-poc-access
102
+ bindings:
103
+ - permissions:
104
+ - reveal
105
+ # Uncomment these two
106
+ # - use
107
+ # - view
108
+ principalLinks:
109
+ - //gvc/APP_GVC/identity/postgres-poc-identity
110
+ targetKind: secret
111
+ targetLinks:
112
+ - //secret/postgres-poc-credentials
113
+ - //secret/postgres-poc-entrypoint-script
114
+
115
+ ---
116
+ kind: workload
117
+ name: postgres
118
+ description: postgres
119
+ spec:
120
+ type: stateful
121
+ containers:
122
+ - cpu: 1000m
123
+ memory: 512Mi
124
+ env:
125
+ # Uncomment next two envs will cause the db to be restored from the archive uri
126
+ # - name: POSTGRES_ARCHIVE_URI #Use this var to control the automatic restore behavior. If you leave it out, the db will start empty.
127
+ # value: s3://YOUR_BUCKET/PATH_TO_ARCHIVE_FILE
128
+ # - name: POSTGRES_DB #The name of the initial db in case of doing a restore
129
+ # value: test
130
+ - name: PGDATA #The location postgres stores the db. This can be anything other than /var/lib/postgresql/data, but it must be inside the mount point for the volume set
131
+ value: "/var/lib/postgresql/data/pg_data"
132
+ - name: POSTGRES_PASSWORD #The password for the default user
133
+ value: cpln://secret/postgres-poc-credentials.password
134
+ - name: POSTGRES_USER #The name of the default user
135
+ value: cpln://secret/postgres-poc-credentials.username
136
+ name: stateful
137
+ image: postgres:15
138
+ command: /bin/bash
139
+ args:
140
+ - "-c"
141
+ - "cat /usr/local/bin/cpln-entrypoint.sh >> ./cpln-entrypoint.sh && chmod u+x ./cpln-entrypoint.sh && ./cpln-entrypoint.sh postgres"
142
+ #command: "cpln-entrypoint.sh"
143
+ #args:
144
+ # - "postgres"
145
+ ports:
146
+ - number: 5432
147
+ protocol: tcp
148
+ volumes:
149
+ - uri: cpln://volumeset/postgres-poc-vs
150
+ path: "/var/lib/postgresql/data"
151
+ # Make the ENV value for the entry script a file
152
+ - uri: cpln://secret/postgres-poc-entrypoint-script
153
+ path: "/usr/local/bin/cpln-entrypoint.sh"
154
+ inheritEnv: false
155
+ livenessProbe:
156
+ tcpSocket:
157
+ port: 5432
158
+ failureThreshold: 1
159
+ readinessProbe:
160
+ tcpSocket:
161
+ port: 5432
162
+ failureThreshold: 1
163
+ identityLink: //identity/postgres-poc-identity
164
+ defaultOptions:
165
+ capacityAI: false
166
+ autoscaling:
167
+ metric: cpu
168
+ target: 95
169
+ maxScale: 1
170
+ firewallConfig:
171
+ external:
172
+ inboundAllowCIDR: []
173
+ outboundAllowCIDR:
174
+ - 0.0.0.0/0
175
+ internal:
176
+ inboundAllowType: same-gvc
@@ -0,0 +1,36 @@
1
+ # Template setup of Rails server workload, roughly corresponding to Heroku dyno
2
+ # type within Procfile.
3
+ kind: workload
4
+ name: rails
5
+ spec:
6
+ type: standard
7
+ containers:
8
+ - name: rails
9
+ # 300m is a good starting place for a test app. You can experiment with CPU configuration
10
+ # once your app is running.
11
+ cpu: 300m
12
+ env:
13
+ - name: LOG_LEVEL
14
+ value: debug
15
+ # Inherit other ENV values from GVC
16
+ inheritEnv: true
17
+ image: '/org/APP_ORG/image/APP_IMAGE'
18
+ # 512 corresponds to a standard 1x dyno type
19
+ memory: 512Mi
20
+ ports:
21
+ - number: 3000
22
+ protocol: http
23
+ defaultOptions:
24
+ # Start out like this for "test apps"
25
+ autoscaling:
26
+ # Max of 1 effectively disables autoscaling, so a like a Heroku dyno count of 1
27
+ maxScale: 1
28
+ capacityAI: false
29
+ firewallConfig:
30
+ external:
31
+ # Default to allow public access to Rails server
32
+ inboundAllowCIDR:
33
+ - 0.0.0.0/0
34
+ # Could configure outbound for more security
35
+ outboundAllowCIDR:
36
+ - 0.0.0.0/0
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bad_links=("controlplane.com/shakacode")
4
+ proper_links=("shakacode.controlplane.com")
5
+
6
+ bold=$(tput bold)
7
+ normal=$(tput sgr0)
8
+
9
+ exit_status=0
10
+ accumulated_results=""
11
+ seen_bad_links_indexes=()
12
+
13
+ for ((idx = 0; idx < ${#bad_links[@]}; idx++)); do
14
+ results=$(git grep \
15
+ --recursive \
16
+ --line-number \
17
+ --fixed-strings \
18
+ --break \
19
+ --heading \
20
+ --color=always -- \
21
+ "${bad_links[idx]}" \
22
+ ':!script/check_cpln_links')
23
+
24
+ # Line would become really unwieldly if everything was mushed into the
25
+ # conditional, so let's ignore this check here.
26
+ # shellcheck disable=SC2181
27
+ if [ $? -eq 0 ]; then
28
+ accumulated_results+="$results"
29
+ seen_bad_links_indexes+=("$idx")
30
+ exit_status=1
31
+ fi
32
+ done
33
+
34
+ if [ "$exit_status" -eq 1 ]; then
35
+ echo "${bold}[!] Found the following bad links:${normal}"
36
+ echo ""
37
+ echo "$accumulated_results"
38
+ echo ""
39
+ echo "${bold}[*] Please update accordingly:${normal}"
40
+ for bad_link_index in "${seen_bad_links_indexes[@]}"; do
41
+ echo " ${bad_links[bad_link_index]} -> ${proper_links[bad_link_index]}"
42
+ done
43
+ fi
44
+
45
+ exit "$exit_status"