cpl 1.1.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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"