cpl 0.6.0 → 0.7.0

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