cpl 2.0.0.rc.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -3
- data/Gemfile.lock +2 -2
- data/docs/commands.md +1 -0
- data/docs/redis.md +25 -9
- data/lib/command/delete.rb +19 -1
- data/lib/core/controlplane.rb +19 -0
- data/lib/core/controlplane_api.rb +4 -0
- data/lib/cpl/version.rb +2 -2
- data/lib/cpl.rb +18 -10
- data/templates/memcached.yml +3 -3
- data/templates/postgres.yml +1 -1
- data/templates/redis.yml +3 -3
- data/templates/redis2.yml +37 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c304577e2c02b5778a463b82ec9a72792bd10b727687402d66a504d390673fae
|
4
|
+
data.tar.gz: dc28bb00740914362abba26bc61cee999f7ac2d955218dca0ea6dbeef58d465e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4812e651d14114d8d7bccf893cf50107dc9ba24b35679d633fc36d37589dfbae9d93eb8e8dc172bc66e4feb6039d6ab7c2093c0f35b1a544acab01b55c722c68
|
7
|
+
data.tar.gz: 53013a61c2bcedc3ad10664f8d4a8874731013bb740abdb42fdac34dd82c3dc960b2643e9dea8227335040d2c2730eff6ed0cf47973d9344ddf5c5fc1bba7a99
|
data/CHANGELOG.md
CHANGED
@@ -14,14 +14,19 @@ Changes since the last non-beta release.
|
|
14
14
|
|
15
15
|
_Please add entries here for your pull requests that are not yet released._
|
16
16
|
|
17
|
-
## [2.0.0.rc.
|
17
|
+
## [2.0.0.rc.1] - 2024-05-11
|
18
18
|
|
19
19
|
### BREAKING CHANGES
|
20
20
|
|
21
21
|
- Commands that finished with a failure now exit with code `64` instead of `1`. [PR 132](https://github.com/shakacode/heroku-to-control-plane/pull/132) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
22
|
+
- Bumped minimum `cpln` version to `2.0.1` (`cpln workload cron get` is required). [PR 171](https://github.com/shakacode/heroku-to-control-plane/pull/171) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
22
23
|
- `run:cleanup` command has been removed. [PR 151](https://github.com/shakacode/heroku-to-control-plane/pull/151) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
23
24
|
- `deploy-image` command now runs the release script in the context of the `run` command. [PR 151](https://github.com/shakacode/heroku-to-control-plane/pull/151) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
24
25
|
|
26
|
+
### Fixed
|
27
|
+
|
28
|
+
- Fixed race conditions when using latest image in `run` command. [PR 163](https://github.com/shakacode/heroku-to-control-plane/pull/163) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
29
|
+
|
25
30
|
### Added
|
26
31
|
|
27
32
|
- Added options to `run` command to override the workload container's `--cpu`, `--memory`, and `--entrypoint`. [PR 151](https://github.com/shakacode/heroku-to-control-plane/pull/151) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
@@ -32,9 +37,12 @@ _Please add entries here for your pull requests that are not yet released._
|
|
32
37
|
|
33
38
|
### Changed
|
34
39
|
|
40
|
+
- An error is now raised if the org does not exist. [PR 167](https://github.com/shakacode/heroku-to-control-plane/pull/167) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
41
|
+
- Common options are now shown in help. [PR 169](https://github.com/shakacode/heroku-to-control-plane/pull/169) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
35
42
|
- `run` command now uses a single reusable cron workload and works for both interactive and non-interactive jobs. [PR 151](https://github.com/shakacode/heroku-to-control-plane/pull/151) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
36
43
|
- `run:detached` command has been deprecated in favor of `run`. [PR 151](https://github.com/shakacode/heroku-to-control-plane/pull/151) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
37
44
|
- `deploy-image` command now raises an error if image does not exist. [PR 153](https://github.com/shakacode/heroku-to-control-plane/pull/153) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
45
|
+
- `delete` command now unbinds identity from policy (if bound) when deleting app. [PR 170](https://github.com/shakacode/heroku-to-control-plane/pull/170) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
38
46
|
|
39
47
|
## [1.4.0] - 2024-03-20
|
40
48
|
|
@@ -178,8 +186,8 @@ _Please add entries here for your pull requests that are not yet released._
|
|
178
186
|
|
179
187
|
- Initial release
|
180
188
|
|
181
|
-
[Unreleased]: https://github.com/shakacode/heroku-to-control-plane/compare/v2.0.0.rc.
|
182
|
-
[2.0.0.rc.
|
189
|
+
[Unreleased]: https://github.com/shakacode/heroku-to-control-plane/compare/v2.0.0.rc.1...HEAD
|
190
|
+
[2.0.0.rc.1]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.4.0...v2.0.0.rc.1
|
183
191
|
[1.4.0]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.3.0...v1.4.0
|
184
192
|
[1.3.0]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.2.0...v1.3.0
|
185
193
|
[1.2.0]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.1.2...v1.2.0
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cpl (2.0.0
|
4
|
+
cpl (2.0.0)
|
5
5
|
debug (~> 1.7.1)
|
6
6
|
dotenv (~> 2.8.1)
|
7
7
|
jwt (~> 2.8.1)
|
@@ -52,7 +52,7 @@ GEM
|
|
52
52
|
rdoc (6.6.3.1)
|
53
53
|
psych (>= 4.0.0)
|
54
54
|
regexp_parser (2.9.0)
|
55
|
-
reline (0.5.
|
55
|
+
reline (0.5.7)
|
56
56
|
io-console (~> 0.5)
|
57
57
|
rexml (3.2.6)
|
58
58
|
rspec (3.12.0)
|
data/docs/commands.md
CHANGED
@@ -106,6 +106,7 @@ cpl copy-image-from-upstream -a $APP_NAME --upstream-token $UPSTREAM_TOKEN --ima
|
|
106
106
|
### `delete`
|
107
107
|
|
108
108
|
- Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload
|
109
|
+
- Also unbinds the app from the secrets policy, as long as both the identity and the policy exist (and are bound)
|
109
110
|
- Will ask for explicit user confirmation
|
110
111
|
|
111
112
|
```sh
|
data/docs/redis.md
CHANGED
@@ -1,15 +1,31 @@
|
|
1
|
-
# Migrating Redis
|
1
|
+
# Migrating Redis databases
|
2
2
|
|
3
|
-
|
3
|
+
There are two templates examples in this repo:
|
4
|
+
- `redis` - basic non-persistent template. It is good for review-apps or staging or where no persistence is required
|
5
|
+
- `redis2` - basic persistent template. Good for production where persistence is needed, but cluster is overkill.
|
6
|
+
|
7
|
+
## Option 1: use SLAVEOF (easier way)
|
8
|
+
|
9
|
+
1. create a redis workload that will accept data
|
10
|
+
2. execute `SLAVEOF source_host source_port`, if needed use `masterauth` to provide auth details
|
11
|
+
3. wait for replication to pick up all changes (usually quickly), use `INFO` or `DBSIZE` to check progress
|
12
|
+
4. stop app completely and ensure nothing is writing to any of redises
|
13
|
+
5. execute `SLAVEOF no one` to disconnect replication
|
14
|
+
6. switch `REDIS_URL` in the app to point to new server
|
15
|
+
7. start the app
|
16
|
+
|
17
|
+
## Option 2: use Redis-RIOT (harder way, where option 1 is not possible)
|
18
|
+
|
19
|
+
### General considerations:
|
4
20
|
|
5
21
|
1. Heroku uses self-signed TLS certificates, which are not verifiable. It needs special handling by setting
|
6
|
-
|
22
|
+
The tool that satisfies those criteria is [Redis-RIOT](https://developer.redis.com/riot/riot-redis/index.html)
|
7
23
|
|
8
24
|
2. We are moving to private Redis that don't have a public URL, so have to do it from a Control Plane GVC container.
|
9
25
|
|
10
26
|
The tool that satisfies those criteria is [Redis-RIOT](https://developer.redis.com/riot/riot-redis/index.html)
|
11
27
|
|
12
|
-
|
28
|
+
### Heroku Redis:
|
13
29
|
|
14
30
|
As Redis-RIOT says, master redis should have keyspace-notifications set to `KA` to be able to do live replication.
|
15
31
|
To do that:
|
@@ -23,7 +39,7 @@ Connect to heroku Redis CLI:
|
|
23
39
|
heroku redis:cli -a my-app
|
24
40
|
```
|
25
41
|
|
26
|
-
|
42
|
+
### Control Plane Redis:
|
27
43
|
|
28
44
|
Connect to Control Plane Redis CLI:
|
29
45
|
|
@@ -36,10 +52,10 @@ apt-get update
|
|
36
52
|
apt-get install redis -y
|
37
53
|
|
38
54
|
# connect to local cloud Redis
|
39
|
-
redis-cli -u MY_CONTROL_PLANE_REDIS_URL
|
55
|
+
redis-cli -u MY_CONTROL_PLANE_REDIS_URL -p 6379
|
40
56
|
```
|
41
57
|
|
42
|
-
|
58
|
+
### Useful Redis CLI commands:
|
43
59
|
|
44
60
|
Quick-check keys qty:
|
45
61
|
```
|
@@ -49,7 +65,7 @@ info keyspace
|
|
49
65
|
db0:keys=9496,expires=2941,avg_ttl=77670114535
|
50
66
|
```
|
51
67
|
|
52
|
-
|
68
|
+
### Create a Control Plane sync workload
|
53
69
|
|
54
70
|
```
|
55
71
|
name: riot-redis
|
@@ -76,7 +92,7 @@ command args:
|
|
76
92
|
live
|
77
93
|
```
|
78
94
|
|
79
|
-
|
95
|
+
### Sync process
|
80
96
|
|
81
97
|
1. open 1st terminal window with heroku redis CLI, check keys qty
|
82
98
|
2. open 2nd terminal window with controlplane redis CLI, check keys qty
|
data/lib/command/delete.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Command
|
4
|
-
class Delete < Base
|
4
|
+
class Delete < Base # rubocop:disable Metrics/ClassLength
|
5
5
|
NAME = "delete"
|
6
6
|
OPTIONS = [
|
7
7
|
app_option(required: true),
|
@@ -11,6 +11,7 @@ module Command
|
|
11
11
|
DESCRIPTION = "Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload"
|
12
12
|
LONG_DESCRIPTION = <<~DESC
|
13
13
|
- Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload
|
14
|
+
- Also unbinds the app from the secrets policy, as long as both the identity and the policy exist (and are bound)
|
14
15
|
- Will ask for explicit user confirmation
|
15
16
|
DESC
|
16
17
|
EXAMPLES = <<~EX
|
@@ -48,6 +49,7 @@ module Command
|
|
48
49
|
check_images
|
49
50
|
return unless confirm_delete(config.app)
|
50
51
|
|
52
|
+
unbind_identity_from_policy
|
51
53
|
delete_volumesets
|
52
54
|
delete_gvc
|
53
55
|
delete_images
|
@@ -113,5 +115,21 @@ module Command
|
|
113
115
|
end
|
114
116
|
end
|
115
117
|
end
|
118
|
+
|
119
|
+
def unbind_identity_from_policy
|
120
|
+
return if cp.fetch_identity(app_identity).nil?
|
121
|
+
|
122
|
+
policy = cp.fetch_policy(app_secrets_policy)
|
123
|
+
return if policy.nil?
|
124
|
+
|
125
|
+
is_bound = policy["bindings"].any? do |binding|
|
126
|
+
binding["principalLinks"].any? { |link| link == app_identity_link }
|
127
|
+
end
|
128
|
+
return unless is_bound
|
129
|
+
|
130
|
+
step("Unbinding identity from policy") do
|
131
|
+
cp.unbind_identity_from_policy(app_identity_link, app_secrets_policy)
|
132
|
+
end
|
133
|
+
end
|
116
134
|
end
|
117
135
|
end
|
data/lib/core/controlplane.rb
CHANGED
@@ -8,6 +8,8 @@ class Controlplane # rubocop:disable Metrics/ClassLength
|
|
8
8
|
@api = ControlplaneApi.new
|
9
9
|
@gvc = config.app
|
10
10
|
@org = config.org
|
11
|
+
|
12
|
+
ensure_org_exists! if org
|
11
13
|
end
|
12
14
|
|
13
15
|
# profile
|
@@ -339,6 +341,11 @@ class Controlplane # rubocop:disable Metrics/ClassLength
|
|
339
341
|
perform!(cmd)
|
340
342
|
end
|
341
343
|
|
344
|
+
def unbind_identity_from_policy(identity_link, policy)
|
345
|
+
cmd = "cpln policy remove-binding #{policy} --org #{org} --identity #{identity_link} --permission reveal"
|
346
|
+
perform!(cmd)
|
347
|
+
end
|
348
|
+
|
342
349
|
# apply
|
343
350
|
def apply_template(data) # rubocop:disable Metrics/MethodLength
|
344
351
|
Tempfile.create do |f|
|
@@ -404,6 +411,18 @@ class Controlplane # rubocop:disable Metrics/ClassLength
|
|
404
411
|
|
405
412
|
private
|
406
413
|
|
414
|
+
def org_exists?
|
415
|
+
items = api.list_orgs["items"]
|
416
|
+
items.any? { |item| item["name"] == org }
|
417
|
+
end
|
418
|
+
|
419
|
+
def ensure_org_exists!
|
420
|
+
return if org_exists?
|
421
|
+
|
422
|
+
raise "Can't find org '#{org}', please create it in the Control Plane dashboard " \
|
423
|
+
"or ensure that the name is correct."
|
424
|
+
end
|
425
|
+
|
407
426
|
# `output_mode` can be :all, :errors_only or :none.
|
408
427
|
# If not provided, it will be determined based on the `HIDE_COMMAND_OUTPUT` env var
|
409
428
|
# or the return value of `Shell.should_hide_output?`.
|
data/lib/cpl/version.rb
CHANGED
data/lib/cpl.rb
CHANGED
@@ -146,9 +146,22 @@ module Cpl
|
|
146
146
|
::Command::Base.all_commands.merge(deprecated_commands)
|
147
147
|
end
|
148
148
|
|
149
|
+
def self.process_option_params(params)
|
150
|
+
# Ensures that if no value is provided for a non-boolean option (e.g., `cpl command --option`),
|
151
|
+
# it defaults to an empty string instead of the option name (which is the default Thor behavior)
|
152
|
+
params[:lazy_default] ||= "" if params[:type] != :boolean
|
153
|
+
|
154
|
+
params
|
155
|
+
end
|
156
|
+
|
149
157
|
@commands_with_required_options = []
|
150
158
|
@commands_with_extra_options = []
|
151
159
|
|
160
|
+
::Command::Base.common_options.each do |option|
|
161
|
+
params = process_option_params(option[:params])
|
162
|
+
class_option(option[:name], **params)
|
163
|
+
end
|
164
|
+
|
152
165
|
all_base_commands.each do |command_key, command_class| # rubocop:disable Metrics/BlockLength
|
153
166
|
deprecated = deprecated_commands[command_key]
|
154
167
|
|
@@ -157,7 +170,7 @@ module Cpl
|
|
157
170
|
usage = command_class::USAGE.empty? ? name : command_class::USAGE
|
158
171
|
requires_args = command_class::REQUIRES_ARGS
|
159
172
|
default_args = command_class::DEFAULT_ARGS
|
160
|
-
command_options = command_class::OPTIONS
|
173
|
+
command_options = command_class::OPTIONS
|
161
174
|
accepts_extra_options = command_class::ACCEPTS_EXTRA_OPTIONS
|
162
175
|
description = command_class::DESCRIPTION
|
163
176
|
long_description = command_class::LONG_DESCRIPTION
|
@@ -175,12 +188,7 @@ module Cpl
|
|
175
188
|
long_desc(long_description)
|
176
189
|
|
177
190
|
command_options.each do |option|
|
178
|
-
params = option[:params]
|
179
|
-
|
180
|
-
# Ensures that if no value is provided for a non-boolean option (e.g., `cpl command --option`),
|
181
|
-
# it defaults to an empty string instead of the option name (which is the default Thor behavior)
|
182
|
-
params[:lazy_default] ||= "" if params[:type] != :boolean
|
183
|
-
|
191
|
+
params = process_option_params(option[:params])
|
184
192
|
method_option(option[:name], **params)
|
185
193
|
end
|
186
194
|
|
@@ -208,7 +216,7 @@ module Cpl
|
|
208
216
|
end
|
209
217
|
|
210
218
|
begin
|
211
|
-
Cpl::Cli.validate_options!(options
|
219
|
+
Cpl::Cli.validate_options!(options)
|
212
220
|
|
213
221
|
config = Config.new(args, options, required_options)
|
214
222
|
|
@@ -227,11 +235,11 @@ module Cpl
|
|
227
235
|
check_unknown_options!(except: @commands_with_extra_options)
|
228
236
|
stop_on_unknown_option!
|
229
237
|
|
230
|
-
def self.validate_options!(options
|
238
|
+
def self.validate_options!(options)
|
231
239
|
options.each do |name, value|
|
232
240
|
raise "No value provided for option '#{name}'." if value.to_s.strip.empty?
|
233
241
|
|
234
|
-
params =
|
242
|
+
params = ::Command::Base.all_options.find { |option| option[:name].to_s == name }[:params]
|
235
243
|
next unless params[:valid_regex]
|
236
244
|
|
237
245
|
raise "Invalid value provided for option '#{name}'." unless value.match?(params[:valid_regex])
|
data/templates/memcached.yml
CHANGED
@@ -4,8 +4,8 @@ spec:
|
|
4
4
|
type: standard
|
5
5
|
containers:
|
6
6
|
- name: memcached
|
7
|
-
cpu:
|
8
|
-
memory:
|
7
|
+
cpu: 25m
|
8
|
+
memory: 32Mi
|
9
9
|
args:
|
10
10
|
- "-l"
|
11
11
|
- 0.0.0.0
|
@@ -15,7 +15,7 @@ spec:
|
|
15
15
|
protocol: tcp
|
16
16
|
defaultOptions:
|
17
17
|
autoscaling:
|
18
|
-
metric:
|
18
|
+
metric: disabled
|
19
19
|
minScale: 1
|
20
20
|
maxScale: 1
|
21
21
|
capacityAI: false
|
data/templates/postgres.yml
CHANGED
data/templates/redis.yml
CHANGED
@@ -4,15 +4,15 @@ spec:
|
|
4
4
|
type: standard
|
5
5
|
containers:
|
6
6
|
- name: redis
|
7
|
-
cpu:
|
8
|
-
memory:
|
7
|
+
cpu: 25m
|
8
|
+
memory: 32Mi
|
9
9
|
image: "redis:latest"
|
10
10
|
ports:
|
11
11
|
- number: 6379
|
12
12
|
protocol: tcp
|
13
13
|
defaultOptions:
|
14
14
|
autoscaling:
|
15
|
-
metric:
|
15
|
+
metric: disabled
|
16
16
|
minScale: 1
|
17
17
|
maxScale: 1
|
18
18
|
capacityAI: false
|
@@ -0,0 +1,37 @@
|
|
1
|
+
kind: volumeset
|
2
|
+
name: redis-data
|
3
|
+
spec:
|
4
|
+
fileSystemType: ext4
|
5
|
+
initialCapacity: 10
|
6
|
+
performanceClass: general-purpose-ssd
|
7
|
+
---
|
8
|
+
kind: workload
|
9
|
+
name: redis2
|
10
|
+
spec:
|
11
|
+
type: stateful
|
12
|
+
containers:
|
13
|
+
- name: redis
|
14
|
+
args:
|
15
|
+
- '--appendonly'
|
16
|
+
- 'yes'
|
17
|
+
- '--maxmemory'
|
18
|
+
- 25mb
|
19
|
+
cpu: 25m
|
20
|
+
memory: 32Mi
|
21
|
+
image: "redis:latest"
|
22
|
+
ports:
|
23
|
+
- number: 6379
|
24
|
+
protocol: tcp
|
25
|
+
volumes:
|
26
|
+
- path: /data
|
27
|
+
recoveryPolicy: retain
|
28
|
+
uri: cpln://volumeset/redis-data
|
29
|
+
defaultOptions:
|
30
|
+
autoscaling:
|
31
|
+
metric: disabled
|
32
|
+
minScale: 1
|
33
|
+
maxScale: 1
|
34
|
+
capacityAI: false
|
35
|
+
firewallConfig:
|
36
|
+
internal:
|
37
|
+
inboundAllowType: same-gvc
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cpl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Gordon
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-05-
|
12
|
+
date: 2024-05-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debug
|
@@ -310,6 +310,7 @@ files:
|
|
310
310
|
- templates/postgres.yml
|
311
311
|
- templates/rails.yml
|
312
312
|
- templates/redis.yml
|
313
|
+
- templates/redis2.yml
|
313
314
|
- templates/secrets.yml
|
314
315
|
- templates/sidekiq.yml
|
315
316
|
homepage: https://github.com/shakacode/heroku-to-control-plane
|
@@ -328,9 +329,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
328
329
|
version: 2.7.0
|
329
330
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
330
331
|
requirements:
|
331
|
-
- - "
|
332
|
+
- - ">="
|
332
333
|
- !ruby/object:Gem::Version
|
333
|
-
version:
|
334
|
+
version: '0'
|
334
335
|
requirements: []
|
335
336
|
rubygems_version: 3.4.21
|
336
337
|
signing_key:
|