cpl 0.6.0 → 0.7.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.
@@ -35,10 +35,13 @@ class Controlplane # rubocop:disable Metrics/ClassLength
35
35
 
36
36
  # image
37
37
 
38
- def image_build(image, dockerfile:, push: true)
39
- cmd = "cpln image build --org #{org} --name #{image} --dir #{config.app_dir} --dockerfile #{dockerfile}"
40
- cmd += " --push" if push
38
+ def image_build(image, dockerfile:, build_args: [], push: true)
39
+ cmd = "docker build -t #{image} -f #{dockerfile}"
40
+ build_args.each { |build_arg| cmd += " --build-arg #{build_arg}" }
41
+ cmd += " #{config.app_dir}"
41
42
  perform!(cmd)
43
+
44
+ image_push(image) if push
42
45
  end
43
46
 
44
47
  def image_query(app_name = config.app, org_name = config.org)
@@ -97,7 +100,7 @@ class Controlplane # rubocop:disable Metrics/ClassLength
97
100
  gvc_data = fetch_gvc(a_gvc)
98
101
  return gvc_data if gvc_data
99
102
 
100
- raise "Can't find GVC '#{gvc}', please create it with 'cpl setup gvc -a #{config.app}'."
103
+ raise "Can't find app '#{gvc}', please create it with 'cpl setup-app -a #{config.app}'."
101
104
  end
102
105
 
103
106
  def gvc_delete(a_gvc = gvc)
@@ -122,7 +125,13 @@ class Controlplane # rubocop:disable Metrics/ClassLength
122
125
  workload_data = fetch_workload(workload)
123
126
  return workload_data if workload_data
124
127
 
125
- raise "Can't find workload '#{workload}', please create it with 'cpl setup #{workload} -a #{config.app}'."
128
+ raise "Can't find workload '#{workload}', please create it with 'cpl apply-template #{workload} -a #{config.app}'."
129
+ end
130
+
131
+ def query_workloads(workload, partial_match: false)
132
+ op = partial_match ? "~" : "="
133
+
134
+ api.query_workloads(org: org, gvc: gvc, workload: workload, op_type: op)
126
135
  end
127
136
 
128
137
  def workload_get_replicas(workload, location:)
@@ -136,6 +145,10 @@ class Controlplane # rubocop:disable Metrics/ClassLength
136
145
  $CHILD_STATUS.success? ? YAML.safe_load(result) : nil
137
146
  end
138
147
 
148
+ def fetch_workload_deployments(workload)
149
+ api.workload_deployments(workload: workload, gvc: gvc, org: org)
150
+ end
151
+
139
152
  def workload_set_image_ref(workload, container:, image:)
140
153
  cmd = "cpln workload update #{workload} #{gvc_org}"
141
154
  cmd += " --set spec.containers.#{container}.image=/org/#{config.org}/image/#{image}"
@@ -143,10 +156,26 @@ class Controlplane # rubocop:disable Metrics/ClassLength
143
156
  perform!(cmd)
144
157
  end
145
158
 
146
- def workload_set_suspend(workload, value)
159
+ def set_workload_env_var(workload, container:, name:, value:)
160
+ data = fetch_workload!(workload)
161
+ data["spec"]["containers"].each do |container_data|
162
+ next unless container_data["name"] == container
163
+
164
+ container_data["env"].each do |env_data|
165
+ next unless env_data["name"] == name
166
+
167
+ env_data["value"] = value
168
+ end
169
+ end
170
+
171
+ api.update_workload(org: org, gvc: gvc, workload: workload, data: data)
172
+ end
173
+
174
+ def set_workload_suspend(workload, value)
147
175
  data = fetch_workload!(workload)
148
176
  data["spec"]["defaultOptions"]["suspend"] = value
149
- apply(data)
177
+
178
+ api.update_workload(org: org, gvc: gvc, workload: workload, data: data)
150
179
  end
151
180
 
152
181
  def workload_force_redeployment(workload)
@@ -155,15 +184,8 @@ class Controlplane # rubocop:disable Metrics/ClassLength
155
184
  perform!(cmd)
156
185
  end
157
186
 
158
- def workload_delete(workload)
159
- cmd = "cpln workload delete #{workload} #{gvc_org}"
160
- cmd += " 2> /dev/null"
161
- perform(cmd)
162
- end
163
-
164
- def workload_delete!(workload)
165
- cmd = "cpln workload delete #{workload} #{gvc_org}"
166
- perform!(cmd)
187
+ def delete_workload(workload)
188
+ api.delete_workload(org: org, gvc: gvc, workload: workload)
167
189
  end
168
190
 
169
191
  def workload_connect(workload, location:, container: nil, shell: nil)
@@ -180,6 +202,40 @@ class Controlplane # rubocop:disable Metrics/ClassLength
180
202
  perform!(cmd)
181
203
  end
182
204
 
205
+ # domain
206
+
207
+ def find_domain_route(data)
208
+ port = data["spec"]["ports"].find { |current_port| current_port["number"] == 80 || current_port["number"] == 443 }
209
+ return nil if port.nil? || port["routes"].nil?
210
+
211
+ route = port["routes"].find { |current_route| current_route["prefix"] == "/" }
212
+ return nil if route.nil?
213
+
214
+ route
215
+ end
216
+
217
+ def find_domain_for(workloads)
218
+ domains = api.list_domains(org: org)["items"]
219
+ domains.find do |domain_data|
220
+ route = find_domain_route(domain_data)
221
+ next false if route.nil?
222
+
223
+ workloads.any? { |workload| route["workloadLink"].split("/").last == workload }
224
+ end
225
+ end
226
+
227
+ def get_domain_workload(data)
228
+ route = find_domain_route(data)
229
+ route["workloadLink"].split("/").last
230
+ end
231
+
232
+ def set_domain_workload(data, workload)
233
+ route = find_domain_route(data)
234
+ route["workloadLink"] = "/org/#{org}/gvc/#{gvc}/workload/#{workload}"
235
+
236
+ api.update_domain(org: org, domain: data["name"], data: data)
237
+ end
238
+
183
239
  # logs
184
240
 
185
241
  def logs(workload:)
@@ -33,6 +33,29 @@ class ControlplaneApi
33
33
  api_json_direct("/logs/org/#{org}/loki/api/v1/query_range?#{params}", method: :get, host: :logs)
34
34
  end
35
35
 
36
+ def query_workloads(org:, gvc:, workload:, op_type:) # rubocop:disable Metrics/MethodLength
37
+ body = {
38
+ kind: "string",
39
+ spec: {
40
+ match: "all",
41
+ terms: [
42
+ {
43
+ rel: "gvc",
44
+ op: "=",
45
+ value: gvc
46
+ },
47
+ {
48
+ property: "name",
49
+ op: op_type,
50
+ value: workload
51
+ }
52
+ ]
53
+ }
54
+ }
55
+
56
+ api_json("/org/#{org}/workload/-query", method: :post, body: body)
57
+ end
58
+
36
59
  def workload_list(org:, gvc:)
37
60
  api_json("/org/#{org}/gvc/#{gvc}/workload", method: :get)
38
61
  end
@@ -45,10 +68,26 @@ class ControlplaneApi
45
68
  api_json("/org/#{org}/gvc/#{gvc}/workload/#{workload}", method: :get)
46
69
  end
47
70
 
71
+ def update_workload(org:, gvc:, workload:, data:)
72
+ api_json("/org/#{org}/gvc/#{gvc}/workload/#{workload}", method: :patch, body: data)
73
+ end
74
+
48
75
  def workload_deployments(org:, gvc:, workload:)
49
76
  api_json("/org/#{org}/gvc/#{gvc}/workload/#{workload}/deployment", method: :get)
50
77
  end
51
78
 
79
+ def delete_workload(org:, gvc:, workload:)
80
+ api_json("/org/#{org}/gvc/#{gvc}/workload/#{workload}", method: :delete)
81
+ end
82
+
83
+ def list_domains(org:)
84
+ api_json("/org/#{org}/domain", method: :get)
85
+ end
86
+
87
+ def update_domain(org:, domain:, data:)
88
+ api_json("/org/#{org}/domain/#{domain}", method: :patch, body: data)
89
+ end
90
+
52
91
  private
53
92
 
54
93
  # switch between cpln rest and api
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ControlplaneApiDirect
4
- API_METHODS = { get: Net::HTTP::Get, post: Net::HTTP::Post, put: Net::HTTP::Put, delete: Net::HTTP::Delete }.freeze
4
+ API_METHODS = {
5
+ get: Net::HTTP::Get,
6
+ patch: Net::HTTP::Patch,
7
+ post: Net::HTTP::Post,
8
+ put: Net::HTTP::Put,
9
+ delete: Net::HTTP::Delete
10
+ }.freeze
5
11
  API_HOSTS = { api: "https://api.cpln.io", logs: "https://logs.cpln.io" }.freeze
6
12
 
7
13
  # API_TOKEN_REGEX = Regexp.union(
@@ -11,11 +17,12 @@ class ControlplaneApiDirect
11
17
 
12
18
  API_TOKEN_REGEX = /^[\w\-._]+$/.freeze
13
19
 
14
- def call(url, method:, host: :api) # rubocop:disable Metrics/MethodLength
20
+ def call(url, method:, host: :api, body: nil) # rubocop:disable Metrics/MethodLength
15
21
  uri = URI("#{API_HOSTS[host]}#{url}")
16
22
  request = API_METHODS[method].new(uri)
17
23
  request["Content-Type"] = "application/json"
18
24
  request["Authorization"] = api_token
25
+ request.body = body.to_json if body
19
26
 
20
27
  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
21
28
 
@@ -31,13 +38,16 @@ class ControlplaneApiDirect
31
38
  end
32
39
  end
33
40
 
41
+ # rubocop:disable Style/ClassVars
34
42
  def api_token
35
43
  return @@api_token if defined?(@@api_token)
36
44
 
37
- @@api_token = ENV.fetch("CPLN_TOKEN", `cpln profile token`.chomp) # rubocop:disable Style/ClassVars
45
+ @@api_token = ENV.fetch("CPLN_TOKEN", nil)
46
+ @@api_token = `cpln profile token`.chomp if @@api_token.nil?
38
47
  return @@api_token if @@api_token.match?(API_TOKEN_REGEX)
39
48
 
40
49
  raise "Unknown API token format. " \
41
50
  "Please re-run 'cpln profile login' or set the correct CPLN_TOKEN env variable."
42
51
  end
52
+ # rubocop:enable Style/ClassVars
43
53
  end
data/lib/cpl/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cpl
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -0,0 +1,30 @@
1
+ kind: workload
2
+ name: daily-task
3
+ spec:
4
+ # https://docs.controlplane.com/reference/workload#cron-configuration
5
+ type: cron
6
+ job:
7
+ # Run daily job at 2am, see cron docs
8
+ schedule: 0 2 * * *
9
+ # Never or OnFailure
10
+ restartPolicy: Never
11
+ containers:
12
+ - name: daily-task
13
+ args:
14
+ - bundle
15
+ - exec
16
+ - rails
17
+ - db:prepare
18
+ cpu: 50m
19
+ inheritEnv: true
20
+ image: '/org/APP_ORG/image/APP_IMAGE'
21
+ memory: 256Mi
22
+ defaultOptions:
23
+ autoscaling:
24
+ maxScale: 1
25
+ capacityAI: false
26
+ firewallConfig:
27
+ external:
28
+ outboundAllowCIDR:
29
+ - 0.0.0.0/0
30
+ identityLink: /org/APP_ORG/gvc/APP_GVC/identity/APP_GVC-identity
@@ -0,0 +1,24 @@
1
+ kind: workload
2
+ name: maintenance
3
+ spec:
4
+ type: standard
5
+ containers:
6
+ - name: maintenance
7
+ env:
8
+ - name: PORT
9
+ value: '3000'
10
+ - name: PAGE_URL
11
+ value: ''
12
+ image: 'shakacode/maintenance-mode'
13
+ ports:
14
+ - number: 3000
15
+ protocol: http
16
+ defaultOptions:
17
+ autoscaling:
18
+ maxScale: 1
19
+ capacityAI: false
20
+ timeoutSeconds: 60
21
+ firewallConfig:
22
+ external:
23
+ inboundAllowCIDR:
24
+ - 0.0.0.0/0
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: 0.6.0
4
+ version: 0.7.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: 2023-04-27 00:00:00.000000000 Z
12
+ date: 2023-05-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debug
@@ -151,6 +151,48 @@ dependencies:
151
151
  - - "~>"
152
152
  - !ruby/object:Gem::Version
153
153
  version: 0.22.0
154
+ - !ruby/object:Gem::Dependency
155
+ name: timecop
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: 0.9.6
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: 0.9.6
168
+ - !ruby/object:Gem::Dependency
169
+ name: vcr
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - "~>"
173
+ - !ruby/object:Gem::Version
174
+ version: 6.1.0
175
+ type: :development
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - "~>"
180
+ - !ruby/object:Gem::Version
181
+ version: 6.1.0
182
+ - !ruby/object:Gem::Dependency
183
+ name: webmock
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - "~>"
187
+ - !ruby/object:Gem::Version
188
+ version: 3.18.1
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - "~>"
194
+ - !ruby/object:Gem::Version
195
+ version: 3.18.1
154
196
  description: CLI for providing Heroku-like platform-as-a-service on Control Plane
155
197
  email:
156
198
  - justin@shakacode.com
@@ -197,6 +239,10 @@ files:
197
239
  - lib/command/info.rb
198
240
  - lib/command/latest_image.rb
199
241
  - lib/command/logs.rb
242
+ - lib/command/maintenance.rb
243
+ - lib/command/maintenance_off.rb
244
+ - lib/command/maintenance_on.rb
245
+ - lib/command/maintenance_set_page.rb
200
246
  - lib/command/no_command.rb
201
247
  - lib/command/open.rb
202
248
  - lib/command/promote_app_from_upstream.rb
@@ -205,6 +251,7 @@ files:
205
251
  - lib/command/ps_start.rb
206
252
  - lib/command/ps_stop.rb
207
253
  - lib/command/run.rb
254
+ - lib/command/run_cleanup.rb
208
255
  - lib/command/run_detached.rb
209
256
  - lib/command/setup_app.rb
210
257
  - lib/command/test.rb
@@ -224,8 +271,10 @@ files:
224
271
  - script/add_command
225
272
  - script/generate_commands_docs
226
273
  - script/rename_command
274
+ - templates/daily-task.yml
227
275
  - templates/gvc.yml
228
276
  - templates/identity.yml
277
+ - templates/maintenance.yml
229
278
  - templates/memcached.yml
230
279
  - templates/postgres.yml
231
280
  - templates/rails.yml