cloudmunda 0.1.0 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0224d338965547c5fb715c3e3b3f6443606fe3688ecf3bef13c7fedd10ded234
4
- data.tar.gz: ba347d1a7aa1624624d30d3459110c81e0a6ff98e9e4d06dfb9c9c08e7d75dd3
3
+ metadata.gz: '0882dcb50d23ad283984404e67f589a28d39a08c19ec44b9c2ca00659386962e'
4
+ data.tar.gz: 7d03f8ddd3c6cc8ba8a464e64e84a14234a791540f947a25cb94dd36fd5bc8c1
5
5
  SHA512:
6
- metadata.gz: 72ce642c5be6dc2a8d12585c88aaa8c89f9ac6a8d89ee7ae83f0dae71788689b6f09cbbce4543582c1f1af734045dc230b44bb33041d7a57cd7e705611df9625
7
- data.tar.gz: 49d5cf58b015e80c233eebb989a0c855fcd59b91a252aaf91e7bf127c068ad027eb119a491284e769b1be04518234c7506f353ddd6e6fb093f84a79c0195a04b
6
+ metadata.gz: 1aa60b038071944496032564eb73a21c3344211ab4339cc77d9d74de6ecaf7814e31eb69fafada0cd6f25432f9e4a85f2cf9003edf209735605986f9c5c26f9b
7
+ data.tar.gz: 5e5d47130dc95f8d98a12facaf4dc8830cded1f3420e3b96df838d5730c01339dd0187177d9f5d92c6c1ac175b67d647530dc497383686eda2d46a16cba57355
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.1] - 2021-12-16
4
+
5
+ - Camunda Cloud Access Token Creation
6
+ - Zeebe task workers
7
+ - Camunda Cloud Usertasks graphQL connection
8
+
3
9
  ## [0.1.0] - 2021-12-16
4
10
 
5
11
  - Initial release
12
+ _
data/Gemfile CHANGED
@@ -5,8 +5,7 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in cloudmunda.gemspec
6
6
  gemspec
7
7
 
8
+ gem "rails", ">= 6"
8
9
  gem "rake", "~> 13.0"
9
-
10
10
  gem "rspec", "~> 3.0"
11
-
12
11
  gem "rubocop", "~> 1.21"
data/Gemfile.lock CHANGED
@@ -1,19 +1,151 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cloudmunda (0.1.0)
4
+ cloudmunda (0.1.1)
5
+ concurrent-ruby (~> 1.0)
6
+ rest-client (~> 2.0)
7
+ zeebe-client (~> 0.16)
5
8
 
6
9
  GEM
7
10
  remote: https://rubygems.org/
8
11
  specs:
12
+ actioncable (6.1.4.1)
13
+ actionpack (= 6.1.4.1)
14
+ activesupport (= 6.1.4.1)
15
+ nio4r (~> 2.0)
16
+ websocket-driver (>= 0.6.1)
17
+ actionmailbox (6.1.4.1)
18
+ actionpack (= 6.1.4.1)
19
+ activejob (= 6.1.4.1)
20
+ activerecord (= 6.1.4.1)
21
+ activestorage (= 6.1.4.1)
22
+ activesupport (= 6.1.4.1)
23
+ mail (>= 2.7.1)
24
+ actionmailer (6.1.4.1)
25
+ actionpack (= 6.1.4.1)
26
+ actionview (= 6.1.4.1)
27
+ activejob (= 6.1.4.1)
28
+ activesupport (= 6.1.4.1)
29
+ mail (~> 2.5, >= 2.5.4)
30
+ rails-dom-testing (~> 2.0)
31
+ actionpack (6.1.4.1)
32
+ actionview (= 6.1.4.1)
33
+ activesupport (= 6.1.4.1)
34
+ rack (~> 2.0, >= 2.0.9)
35
+ rack-test (>= 0.6.3)
36
+ rails-dom-testing (~> 2.0)
37
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
38
+ actiontext (6.1.4.1)
39
+ actionpack (= 6.1.4.1)
40
+ activerecord (= 6.1.4.1)
41
+ activestorage (= 6.1.4.1)
42
+ activesupport (= 6.1.4.1)
43
+ nokogiri (>= 1.8.5)
44
+ actionview (6.1.4.1)
45
+ activesupport (= 6.1.4.1)
46
+ builder (~> 3.1)
47
+ erubi (~> 1.4)
48
+ rails-dom-testing (~> 2.0)
49
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
50
+ activejob (6.1.4.1)
51
+ activesupport (= 6.1.4.1)
52
+ globalid (>= 0.3.6)
53
+ activemodel (6.1.4.1)
54
+ activesupport (= 6.1.4.1)
55
+ activerecord (6.1.4.1)
56
+ activemodel (= 6.1.4.1)
57
+ activesupport (= 6.1.4.1)
58
+ activestorage (6.1.4.1)
59
+ actionpack (= 6.1.4.1)
60
+ activejob (= 6.1.4.1)
61
+ activerecord (= 6.1.4.1)
62
+ activesupport (= 6.1.4.1)
63
+ marcel (~> 1.0.0)
64
+ mini_mime (>= 1.1.0)
65
+ activesupport (6.1.4.1)
66
+ concurrent-ruby (~> 1.0, >= 1.0.2)
67
+ i18n (>= 1.6, < 2)
68
+ minitest (>= 5.1)
69
+ tzinfo (~> 2.0)
70
+ zeitwerk (~> 2.3)
9
71
  ast (2.4.2)
72
+ builder (3.2.4)
73
+ concurrent-ruby (1.1.9)
74
+ crass (1.0.6)
10
75
  diff-lcs (1.4.4)
76
+ domain_name (0.5.20190701)
77
+ unf (>= 0.0.5, < 1.0.0)
78
+ erubi (1.10.0)
79
+ globalid (1.0.0)
80
+ activesupport (>= 5.0)
81
+ google-protobuf (3.19.1-x86_64-darwin)
82
+ googleapis-common-protos-types (1.3.0)
83
+ google-protobuf (~> 3.14)
84
+ grpc (1.42.0-x86_64-darwin)
85
+ google-protobuf (~> 3.18)
86
+ googleapis-common-protos-types (~> 1.0)
87
+ http-accept (1.7.0)
88
+ http-cookie (1.0.4)
89
+ domain_name (~> 0.5)
90
+ i18n (1.8.11)
91
+ concurrent-ruby (~> 1.0)
92
+ loofah (2.13.0)
93
+ crass (~> 1.0.2)
94
+ nokogiri (>= 1.5.9)
95
+ mail (2.7.1)
96
+ mini_mime (>= 0.1.1)
97
+ marcel (1.0.2)
98
+ method_source (1.0.0)
99
+ mime-types (3.4.1)
100
+ mime-types-data (~> 3.2015)
101
+ mime-types-data (3.2021.1115)
102
+ mini_mime (1.1.2)
103
+ minitest (5.14.4)
104
+ netrc (0.11.0)
105
+ nio4r (2.5.8)
106
+ nokogiri (1.12.5-x86_64-darwin)
107
+ racc (~> 1.4)
11
108
  parallel (1.21.0)
12
109
  parser (3.0.3.2)
13
110
  ast (~> 2.4.1)
111
+ racc (1.6.0)
112
+ rack (2.2.3)
113
+ rack-test (1.1.0)
114
+ rack (>= 1.0, < 3)
115
+ rails (6.1.4.1)
116
+ actioncable (= 6.1.4.1)
117
+ actionmailbox (= 6.1.4.1)
118
+ actionmailer (= 6.1.4.1)
119
+ actionpack (= 6.1.4.1)
120
+ actiontext (= 6.1.4.1)
121
+ actionview (= 6.1.4.1)
122
+ activejob (= 6.1.4.1)
123
+ activemodel (= 6.1.4.1)
124
+ activerecord (= 6.1.4.1)
125
+ activestorage (= 6.1.4.1)
126
+ activesupport (= 6.1.4.1)
127
+ bundler (>= 1.15.0)
128
+ railties (= 6.1.4.1)
129
+ sprockets-rails (>= 2.0.0)
130
+ rails-dom-testing (2.0.3)
131
+ activesupport (>= 4.2.0)
132
+ nokogiri (>= 1.6)
133
+ rails-html-sanitizer (1.4.2)
134
+ loofah (~> 2.3)
135
+ railties (6.1.4.1)
136
+ actionpack (= 6.1.4.1)
137
+ activesupport (= 6.1.4.1)
138
+ method_source
139
+ rake (>= 0.13)
140
+ thor (~> 1.0)
14
141
  rainbow (3.0.0)
15
142
  rake (13.0.6)
16
143
  regexp_parser (2.2.0)
144
+ rest-client (2.1.0)
145
+ http-accept (>= 1.7.0, < 2.0)
146
+ http-cookie (>= 1.0.2, < 2.0)
147
+ mime-types (>= 1.16, < 4.0)
148
+ netrc (~> 0.8)
17
149
  rexml (3.2.5)
18
150
  rspec (3.10.0)
19
151
  rspec-core (~> 3.10.0)
@@ -40,13 +172,33 @@ GEM
40
172
  rubocop-ast (1.15.0)
41
173
  parser (>= 3.0.1.1)
42
174
  ruby-progressbar (1.11.0)
175
+ sprockets (4.0.2)
176
+ concurrent-ruby (~> 1.0)
177
+ rack (> 1, < 3)
178
+ sprockets-rails (3.4.1)
179
+ actionpack (>= 5.2)
180
+ activesupport (>= 5.2)
181
+ sprockets (>= 3.0.0)
182
+ thor (1.1.0)
183
+ tzinfo (2.0.4)
184
+ concurrent-ruby (~> 1.0)
185
+ unf (0.1.4)
186
+ unf_ext
187
+ unf_ext (0.0.8)
43
188
  unicode-display_width (2.1.0)
189
+ websocket-driver (0.7.5)
190
+ websocket-extensions (>= 0.1.0)
191
+ websocket-extensions (0.1.5)
192
+ zeebe-client (0.16.0)
193
+ grpc (~> 1.32)
194
+ zeitwerk (2.5.1)
44
195
 
45
196
  PLATFORMS
46
197
  x86_64-darwin-20
47
198
 
48
199
  DEPENDENCIES
49
200
  cloudmunda!
201
+ rails (>= 6)
50
202
  rake (~> 13.0)
51
203
  rspec (~> 3.0)
52
204
  rubocop (~> 1.21)
data/README.md CHANGED
@@ -22,7 +22,16 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ ```ruby
26
+ Cloudmunda.configure do |config|
27
+ config.env = ENV['APP_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
28
+ config.require = '.'
29
+ config.timeout = 30
30
+ config.zeebe_url = ENV['ZEEBE_URL']
31
+ config.auth_url = ENV['ZEEBE_AUTHORIZATION_SERVER_URL']
32
+ end
33
+ ```
34
+
26
35
 
27
36
  ## Development
28
37
 
data/exe/cloudmunda ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require "bundler/setup"
3
+ require "cloudmunda/cli"
4
+
5
+ begin
6
+ cli = ::Cloudmunda::CLI.instance
7
+ cli.parse
8
+ cli.run
9
+ rescue => e
10
+ raise e if $DEBUG
11
+ STDERR.puts e.message
12
+ STDERR.puts e.backtrace.join("\n")
13
+ exit 1
14
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudmunda
4
+ module API
5
+ class AccessToken < Cloudmunda::API::OAuthResource
6
+ def self.create(audience_url: Cloudmunda.audience)
7
+ uri = Cloudmunda.auth_url
8
+ payload = {
9
+ "grant_type":"client_credentials",
10
+ "audience": audience_url,
11
+ "client_id": Cloudmunda.client_id,
12
+ "client_secret": Cloudmunda.client_secret
13
+ }
14
+
15
+ create_by_uri(uri: uri, payload: payload)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rest-client'
4
+ require 'json'
5
+ require 'uri'
6
+ require 'base64'
7
+
8
+ module Cloudmunda
9
+ module API
10
+ class Client
11
+ def self.post(url, params = {})
12
+ response = RestClient.post(url, params.to_json, headers.merge(content_headers))
13
+ JSON.parse(response.body)
14
+ end
15
+
16
+ def self.headers
17
+ {
18
+ authorization: "Basic " + Base64.strict_encode64("#{Cloudmunda.client_id}:#{Cloudmunda.client_secret}"),
19
+ }
20
+ end
21
+
22
+ def self.content_headers
23
+ {
24
+ 'Content-Type': 'application/json'
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+
5
+ module Cloudmunda
6
+ module API
7
+ class OAuthResource < OpenStruct
8
+ def self.create_by_uri(uri:, payload:)
9
+ raw_item = Cloudmunda::API::Client.post(uri, payload)
10
+ raw_item = {} if raw_item == ""
11
+ new(raw_item)
12
+ end
13
+
14
+ def initialize(raw)
15
+ super(raw)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'api/o_auth_resource'
2
+ require_relative 'api/access_token'
3
+ require_relative 'api/client'
4
+
@@ -0,0 +1,35 @@
1
+ require_relative 'supervisor'
2
+
3
+ module Cloudmunda
4
+ class Launcher
5
+
6
+ attr_reader :supervisor
7
+
8
+ def initialize
9
+ @supervisor = ::Cloudmunda::Supervisor.new
10
+ end
11
+
12
+ # Starts the supervisor and job processors.
13
+ def start
14
+ supervisor.start
15
+ end
16
+
17
+ # Tells the supervisor to stop processing any more jobs.
18
+ def quiet
19
+ supervisor.quiet
20
+ end
21
+
22
+ # Tells the supervisor to stop job processors. This method blocks until
23
+ # all processors are complete and stopped. It can take up to configurable
24
+ # timeout.
25
+ def stop
26
+ supervisor.stop
27
+ end
28
+
29
+ private
30
+
31
+ def client
32
+ ::Cloudmunda.client
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,109 @@
1
+ module Cloudmunda
2
+ class Processor
3
+
4
+ attr_reader :client, :worker_class, :busy_count, :timer
5
+
6
+ def initialize(client: ::Cloudmunda.client, worker_class:)
7
+ @client = client
8
+ @worker_class = worker_class
9
+ @busy_count = ::Concurrent::AtomicFixnum.new(0)
10
+ @timer = ::Concurrent::TimerTask.new(
11
+ run_now: true,
12
+ execution_interval: worker_poll_interval,
13
+ timeout_interval: worker_timeout
14
+ ) { run }
15
+ end
16
+
17
+ def start
18
+ timer.execute
19
+ self
20
+ end
21
+
22
+ def stop
23
+ timer.shutdown
24
+ self
25
+ end
26
+
27
+ def should_activate_jobs?
28
+ busy_count.value <= worker_max_jobs_to_activate
29
+ end
30
+
31
+ private
32
+
33
+ def run
34
+ fetch if should_activate_jobs?
35
+ end
36
+
37
+ def fetch
38
+ activate_jobs_request.each do |response|
39
+ busy_count.increment(response.jobs.count)
40
+ response.jobs.each do |job|
41
+ ::Concurrent::Future.execute do
42
+ process(job)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def process(job)
49
+ worker = worker_class.new(client)
50
+ begin
51
+ logger.info "class=#{worker_class} jid=#{job.key} Start processing #{job.type}"
52
+
53
+ worker.process(job)
54
+ worker.complete_job(job)
55
+
56
+ logger.info "class=#{worker_class} jid=#{job.key} Done processing #{job.type}"
57
+ rescue => exception
58
+ logger.info "class=#{worker_class} jid=#{job.key} Failed processing #{job.type}: #{exception.message}"
59
+
60
+ worker.fail_job(job, reason: exception.message)
61
+ raise exception
62
+ ensure
63
+ busy_count.decrement
64
+ end
65
+ end
66
+
67
+ def activate_jobs_request
68
+ client.activate_jobs(
69
+ type: worker_type,
70
+ worker: worker_name,
71
+ timeout: worker_timeout * 1000,
72
+ maxJobsToActivate: max_jobs_to_activate,
73
+ fetchVariable: worker_variables_to_fetch,
74
+ )
75
+ end
76
+
77
+ def worker_type
78
+ worker_class.get_type
79
+ end
80
+
81
+ def worker_name
82
+ worker_class.get_name
83
+ end
84
+
85
+ def worker_max_jobs_to_activate
86
+ worker_class.get_max_jobs_to_activate
87
+ end
88
+
89
+ def worker_timeout
90
+ worker_class.get_timeout
91
+ end
92
+
93
+ def worker_variables_to_fetch
94
+ worker_class.get_variables_to_fetch
95
+ end
96
+
97
+ def worker_poll_interval
98
+ worker_class.get_poll_interval
99
+ end
100
+
101
+ def max_jobs_to_activate
102
+ worker_max_jobs_to_activate - busy_count.value
103
+ end
104
+
105
+ def logger
106
+ ::Cloudmunda.logger
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,37 @@
1
+ require_relative 'processor'
2
+
3
+ module Cloudmunda
4
+ class Supervisor
5
+ def initialize
6
+ @processors = []
7
+ end
8
+
9
+ def start
10
+ @processors = workers.map do |worker_class|
11
+ processor = ::Cloudmunda::Processor.new(worker_class: worker_class)
12
+ processor.start
13
+ end
14
+ end
15
+
16
+ def quiet
17
+ logger.info "Terminating workers"
18
+ @processors.each(&:stop)
19
+ end
20
+
21
+ def stop(timeout: ::Cloudmunda.timeout)
22
+ quiet
23
+ logger.info "Pausing #{timeout}s to allow workers to finish..."
24
+ sleep timeout
25
+ end
26
+
27
+ private
28
+
29
+ def workers
30
+ ::Cloudmunda.workers.to_a
31
+ end
32
+
33
+ def logger
34
+ ::Cloudmunda.logger
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,163 @@
1
+ require 'json'
2
+
3
+ module Cloudmunda
4
+ module Worker
5
+ attr_accessor :client, :type, :max_jobs_to_activate, :poll_interval, :timeout, :variables
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ Cloudmunda.register_worker(base)
10
+ end
11
+
12
+ def initialize(client)
13
+ @client = client
14
+ end
15
+
16
+ def complete_job(job, variables: {})
17
+ logger.info "Completed processing job #{job.type} #{job.key}"
18
+ client.complete_job(
19
+ jobKey: job.key,
20
+ variables: Hash(variables).to_json,
21
+ )
22
+ end
23
+
24
+ def fail_job(job, reason: "")
25
+ logger.error "Failed processing job #{job.type} #{job.key}: #{reason}"
26
+ client.fail_job(
27
+ jobKey: job.key,
28
+ retries: job.retries - 1,
29
+ errorMessage: reason,
30
+ )
31
+ rescue => e
32
+ logger.error e.message
33
+ end
34
+
35
+ def logger
36
+ ::Cloudmunda.logger
37
+ end
38
+
39
+ module ClassMethods
40
+ # Sets the type of service task the worker should subscribe to.
41
+ #
42
+ # @example
43
+ # class MyWorker
44
+ # include ::Cloudmunda::Worker
45
+ # type "some-service-task-type"
46
+ # end
47
+ #
48
+ # @param [String] type
49
+ # @return [String]
50
+ def type(type)
51
+ @type = type
52
+ end
53
+
54
+ # Returns the type of service task the worker should subscribe to.
55
+ #
56
+ # @return [String]
57
+ def get_type
58
+ @type
59
+ end
60
+
61
+ # Sets the maximum number of jobs to send to the worker for processing at once.
62
+ # As jobs get completed by the worker, more jobs will be sent to the worker
63
+ # but always within this limit.
64
+ #
65
+ # @example
66
+ # class MyWorker
67
+ # include ::Cloudmunda::Worker
68
+ # max_jobs_to_activate 5
69
+ # end
70
+ #
71
+ # @param [Integer] max_jobs_to_activate
72
+ # @return [Integer]
73
+ def max_jobs_to_activate(max_jobs_to_activate)
74
+ @max_jobs_to_activate = max_jobs_to_activate
75
+ end
76
+
77
+ # Returns the maximum number of jobs to send to the worker for processing at once.
78
+ # As jobs get completed by the worker, more jobs will be sent to the worker
79
+ # but always within this limit.
80
+ #
81
+ # @return [Integer]
82
+ def get_max_jobs_to_activate
83
+ @max_jobs_to_activate || 1
84
+ end
85
+
86
+ # Sets the interval duration in seconds between polls to the broker.
87
+ #
88
+ # @example
89
+ # class MyWorker
90
+ # include ::Cloudmunda::Worker
91
+ # poll_interval 5
92
+ # end
93
+ #
94
+ # @param [Integer] poll_interval
95
+ # @return [Integer]
96
+ def poll_interval(poll_interval)
97
+ @poll_interval = poll_interval
98
+ end
99
+
100
+ # Returns the interval duration in seconds between polls to the broker.
101
+ #
102
+ # @return [Integer]
103
+ def get_poll_interval
104
+ @poll_interval || 5
105
+ end
106
+
107
+ # Sets the time in seconds the worker has to process the job before
108
+ # the broker consider it as expired and can schedule it to another worker.
109
+ #
110
+ # @example
111
+ # class MyWorker
112
+ # include ::Cloudmunda::Worker
113
+ # timeout 30
114
+ # end
115
+ #
116
+ # @param [Integer] timeout
117
+ # @return [Integer]
118
+ def timeout(timeout)
119
+ @timeout = timeout
120
+ end
121
+
122
+ # Returns the time in seconds the worker has to process the job before
123
+ # the broker consider it as expired and can schedule it to another worker.
124
+ #
125
+ # @return [Integer]
126
+ def get_timeout
127
+ @timeout || 30
128
+ end
129
+
130
+ # Sets the worker's variables to fetch from the broker when polling for new
131
+ # jobs.
132
+ #
133
+ # @example
134
+ # class MyWorker
135
+ # include ::Cloudmunda::Worker
136
+ # variables [:foo, :bar]
137
+ # end
138
+ #
139
+ # @param [Array<String, Symbol>] variables
140
+ # @return [Array<String, Symbol>]
141
+ def variables(variables)
142
+ @variables = variables
143
+ end
144
+
145
+ # Returns the worker's variables to fetch from the broker when polling for new
146
+ # jobs.
147
+ #
148
+ # @return [Array<String, Symbol>]
149
+ def get_variables_to_fetch
150
+ @variables.to_a
151
+ end
152
+
153
+ # Returns the worker's name.
154
+ #
155
+ # @return [String]
156
+ def get_name
157
+ name = self.name.gsub(/::/, ':')
158
+ name.gsub!(/([^A-Z:])([A-Z])/) { "#{$1}_#{$2}" }
159
+ name.downcase
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,169 @@
1
+ require 'singleton'
2
+ require 'optparse'
3
+ require 'fileutils'
4
+ require 'cloudmunda'
5
+ require 'cloudmunda/cli/launcher'
6
+
7
+ $stdout.sync = true
8
+
9
+ module Cloudmunda
10
+ class CLI
11
+ include Singleton
12
+
13
+ attr_accessor :launcher
14
+
15
+ def parse(argv = ARGV)
16
+ parse_options(argv)
17
+ end
18
+
19
+ def run
20
+ boot
21
+
22
+ self_read, self_write = IO.pipe
23
+ sigs = %w[INT TERM]
24
+ sigs.each do |sig|
25
+ trap sig do
26
+ self_write.write("#{sig}\n")
27
+ end
28
+ rescue ArgumentError
29
+ logger.warn "Signal #{sig} not supported"
30
+ end
31
+
32
+ launch(self_read)
33
+ end
34
+
35
+ private
36
+
37
+ def parse_options(argv)
38
+ option_parser.parse!(argv)
39
+ end
40
+
41
+ def option_parser
42
+ OptionParser.new.tap do |p|
43
+ p.on "-e", "--env ENV", "Application environment" do |arg|
44
+ config.env = arg
45
+ end
46
+
47
+ p.on "-i", "--client-id CLIENT_ID", "Client ID" do |arg|
48
+ config.client_id = arg
49
+ end
50
+
51
+ p.on "-r", "--require [PATH|DIR]", "Location of Rails application with workers or file to require" do |arg|
52
+ if !File.exist?(arg) ||
53
+ (File.directory?(arg) && !File.exist?("#{arg}/config/application.rb"))
54
+ raise ArgumentError, "#{arg} is not a ruby file nor a rails application"
55
+ else
56
+ config.require = arg
57
+ end
58
+ end
59
+
60
+ p.on "-s", "--client-secret CLIENT_SECRET", "Client Secret" do |arg|
61
+ config.client_secret = arg
62
+ end
63
+
64
+ p.on "-u", "--zeebe-url ZEEBE_URL", "Zeebe URL" do |arg|
65
+ config.zeebe_url = arg
66
+ end
67
+
68
+ p.on "-U", "--zeebe-auth-url ZEEBE_AUTH_URL", "Zeebe Authorization Server URL" do |arg|
69
+ config.auth_url = arg
70
+ end
71
+
72
+ p.on "-a", "--audience URL", "Zeebe Audience" do |arg|
73
+ config.audience = arg
74
+ end
75
+
76
+ p.on "-T", "--use-access-token STRING", "Zeebe Audience" do |arg|
77
+ config.use_access_token = arg.to_s.downcase == 'true'
78
+ end
79
+
80
+ p.on "-t", "--timeout NUM", "Shutdown timeout" do |arg|
81
+ timeout = Integer(arg)
82
+ raise ArgumentError, "timeout must be a positive integer" if timeout <= 0
83
+ config.timeout = timeout
84
+ end
85
+
86
+ # p.on "-v", "--verbose", "Print more verbose output" do |arg|
87
+ # ::Cloudmuna.logger.level = ::Logger::DEBUG
88
+ # end
89
+
90
+ p.on "-V", "--version", "Print version and exit" do |arg|
91
+ puts "Cloudmunda #{::Cloudmunda::VERSION}"
92
+ exit(0)
93
+ end
94
+
95
+ p.banner = "Usage: cloudmunda [options]"
96
+ p.on_tail "-h", "--help", "Show help" do
97
+ puts p
98
+
99
+ exit(1)
100
+ end
101
+ end
102
+ end
103
+
104
+ def boot
105
+ ENV["RACK_ENV"] = ENV["RAILS_ENV"] = config.env
106
+
107
+ if File.directory?(config.require)
108
+ require 'rails'
109
+ if ::Rails::VERSION::MAJOR < 6
110
+ raise "Cloudmunda does not supports this version of Rails"
111
+ else
112
+ require File.expand_path("#{config.require}/config/environment.rb")
113
+ Dir[Rails.root.join('app/jobs/**/*.rb')].each { |f| require f }
114
+
115
+ logger.info "Booted Rails #{::Rails.version} application in #{config.env} environment"
116
+ end
117
+ else
118
+ require config.require
119
+ end
120
+ end
121
+
122
+ def launch(self_read)
123
+ @launcher = ::Cloudmunda::Launcher.new
124
+
125
+ if config.env == "development" && $stdout.tty?
126
+ logger.info "Starting processing, hit Ctrl-C to stop"
127
+ end
128
+
129
+ begin
130
+ launcher.start
131
+
132
+ while readable_io = IO.select([self_read])
133
+ signal = readable_io.first[0].gets.strip
134
+ handle_signal(signal)
135
+ end
136
+ rescue Interrupt
137
+ logger.info "Shutting down"
138
+ launcher.stop
139
+ logger.info "Bye!"
140
+
141
+ exit(0)
142
+ end
143
+ end
144
+
145
+ def handle_signal(signal)
146
+ handler = signal_handlers[signal]
147
+ if handler
148
+ handler.call(self)
149
+ else
150
+ logger.warn "No signal handler for #{signal}"
151
+ end
152
+ end
153
+
154
+ def signal_handlers
155
+ {
156
+ "INT" => ->(cli) { raise Interrupt },
157
+ "TERM" => ->(cli) { raise Interrupt },
158
+ }
159
+ end
160
+
161
+ def config
162
+ ::Cloudmunda
163
+ end
164
+
165
+ def logger
166
+ ::Cloudmunda.logger
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,35 @@
1
+ module Cloudmunda
2
+ module Configuration
3
+ VALID_OPTIONS_KEYS = %i[env require logger timeout zeebe_url auth_url client_id client_secret audience graphql_url].freeze
4
+ attr_accessor(*VALID_OPTIONS_KEYS)
5
+
6
+ # Sets all configuration options to their default values when this module is extended.
7
+ def self.extended(base)
8
+ base.reset
9
+ end
10
+
11
+ def configure
12
+ yield self
13
+ end
14
+
15
+ def config
16
+ VALID_OPTIONS_KEYS.inject({}) do |option, key|
17
+ option.merge!(key => send(key))
18
+ end
19
+ end
20
+
21
+ # Resets all configuration options to the defaults.
22
+ def reset
23
+ @env = ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
24
+ @logger = Logger.new($stdout)
25
+ @require = "."
26
+ @timeout = 30
27
+ @zeebe_url = ENV['ZEEBE_URL']
28
+ @auth_url = ENV['ZEEBE_AUTHORIZATION_SERVER_URL']
29
+ @client_id = ENV['ZEEBE_CLIENT_ID']
30
+ @client_secret = ENV['ZEEBE_CLIENT_SECRET']
31
+ @audience = ENV['ZEEBE_AUDIENCE']
32
+ @graphql_url = ENV['GRAPHQL_URL']
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rest-client'
4
+ require 'json'
5
+ require 'uri'
6
+ require 'base64'
7
+
8
+ module Cloudmunda
9
+ module Graphql
10
+ class Client
11
+ def self.post(params = {})
12
+ response = RestClient.post(Cloudmunda.graphql_url, params.to_json, headers.merge(content_headers))
13
+ JSON.parse(response.body)
14
+ end
15
+
16
+ def self.headers
17
+ {
18
+ authorization: "Bearer " + Cloudmunda::API::AccessToken.create(audience_url: 'tasklist.camunda.io').access_token
19
+ }
20
+ end
21
+
22
+ def self.content_headers
23
+ {
24
+ 'Content-Type': 'application/json'
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudmunda
4
+ module Graphql
5
+ class UserTasks
6
+ def self.all
7
+ query = "{
8
+ tasks(query: { state: CREATED })
9
+ {
10
+ id
11
+ taskDefinitionId
12
+ name
13
+ taskState
14
+ assignee
15
+ taskState
16
+ isFirst
17
+ formKey
18
+ processDefinitionId
19
+ completionTime
20
+ processName
21
+ variables {
22
+ name
23
+ value
24
+ }
25
+ }
26
+ }"
27
+ Cloudmunda::Graphql::Client.post(query: query)['data']['tasks']
28
+ end
29
+
30
+ def self.run_mutation(mutation)
31
+ Cloudmunda::Graphql::Client.post(query: mutation)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'graphql/client'
2
+ require_relative 'graphql/user_tasks'
@@ -0,0 +1,15 @@
1
+ module Cloudmunda
2
+ module Loggable
3
+ def logger
4
+ @logger || setup_logger
5
+ end
6
+
7
+ def logger=(logger)
8
+ @logger = logger
9
+ end
10
+
11
+ def setup_logger
12
+ @logger = Beez.config.logger
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cloudmunda
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
@@ -0,0 +1,107 @@
1
+ require 'zeebe/client'
2
+
3
+ module Cloudmunda
4
+ module Zeebe
5
+ class Client
6
+
7
+ attr_reader :client
8
+
9
+ def initialize(url: ::Cloudmunda.zeebe_url)
10
+ @client = ::Zeebe::Client::GatewayProtocol::Gateway::Stub.new(url, authentication_headers)
11
+ end
12
+
13
+ def activate_jobs(params = {})
14
+ run(:activate_jobs,
15
+ ::Zeebe::Client::GatewayProtocol::ActivateJobsRequest.new(params)
16
+ )
17
+ end
18
+
19
+ def cancel_workflow_instance(params = {})
20
+ run(:cancel_workflow_instance,
21
+ ::Zeebe::Client::GatewayProtocol::CancelWorkflowInstanceRequest.new(params)
22
+ )
23
+ end
24
+
25
+ def complete_job(params = {})
26
+ run(:complete_job,
27
+ ::Zeebe::Client::GatewayProtocol::CompleteJobRequest.new(params)
28
+ )
29
+ end
30
+
31
+ def create_process_instance(params = {})
32
+ run(:create_process_instance,
33
+ ::Zeebe::Client::GatewayProtocol::CreateProcessInstanceRequest.new(params)
34
+ )
35
+ end
36
+
37
+ def deploy_process(params = {})
38
+ run(:deploy_process,
39
+ ::Zeebe::Client::GatewayProtocol::DeployProcessRequest.new(params)
40
+ )
41
+ end
42
+
43
+ def fail_job(params = {})
44
+ run(:fail_job,
45
+ ::Zeebe::Client::GatewayProtocol::FailJobRequest.new(params)
46
+ )
47
+ end
48
+
49
+ def throw_error(params = {})
50
+ run(:throw_error,
51
+ ::Zeebe::Client::GatewayProtocol::ThrowErrorRequest.new(params)
52
+ )
53
+ end
54
+
55
+ def publish_message(params = {})
56
+ run(:publish_message,
57
+ ::Zeebe::Client::GatewayProtocol::PublishMessageRequest.new(params)
58
+ )
59
+ end
60
+
61
+ def resolve_incident(params = {})
62
+ run(:resolve_incident,
63
+ ::Zeebe::Client::GatewayProtocol::ResolveIncidentRequest.new(params)
64
+ )
65
+ end
66
+
67
+ def set_variables(params = {})
68
+ run(:set_variables,
69
+ ::Zeebe::Client::GatewayProtocol::SetVariablesRequest.new(params)
70
+ )
71
+ end
72
+
73
+ def topology(params = {})
74
+ run(:topology,
75
+ ::Zeebe::Client::GatewayProtocol::TopologyRequest.new(params)
76
+ )
77
+ end
78
+
79
+ def update_job_retries(params = {})
80
+ run(:update_job_retries,
81
+ ::Zeebe::Client::GatewayProtocol::UpdateJobRetriesRequest.new(params)
82
+ )
83
+ end
84
+
85
+ private
86
+
87
+ def run(method, params = {})
88
+ client.public_send(method, params)
89
+ rescue ::GRPC::Unavailable => exception
90
+ logger.error exception.message
91
+ raise exception
92
+ end
93
+
94
+ def logger
95
+ # ::Cloudmunda.logger
96
+ end
97
+
98
+ def authentication_headers
99
+ token = Cloudmunda::API::AccessToken.create
100
+ channel_creds = GRPC::Core::ChannelCredentials.new()
101
+ auth_proc = proc { { 'authorization' => "Bearer #{token.access_token}" } }
102
+ call_creds = GRPC::Core::CallCredentials.new(auth_proc)
103
+ channel_creds.compose(call_creds)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1 @@
1
+ require_relative 'zeebe/client'
data/lib/cloudmunda.rb CHANGED
@@ -1,8 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'concurrent'
4
+
3
5
  require_relative "cloudmunda/version"
6
+ require_relative 'cloudmunda/loggable'
7
+ require_relative 'cloudmunda/cli/worker'
8
+ require_relative 'cloudmunda/configuration'
9
+ require_relative 'cloudmunda/api'
10
+ require_relative 'cloudmunda/zeebe'
11
+ require_relative 'cloudmunda/graphql'
4
12
 
5
13
  module Cloudmunda
6
- class Error < StandardError; end
7
- # Your code goes here...
14
+ extend Configuration
15
+ extend Loggable
16
+
17
+ def self.client
18
+ @client ||= ::Cloudmunda::Zeebe::Client.new
19
+ end
20
+
21
+ def self.register_worker(worker)
22
+ self.workers << worker
23
+ end
24
+
25
+ def self.workers
26
+ @workers ||= []
27
+ end
8
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudmunda
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lien Van Den Steen
@@ -9,11 +9,54 @@ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 2021-12-16 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: zeebe-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.16'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: concurrent-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
13
55
  description: Ruby wrapper for Camunda Cloud
14
56
  email:
15
57
  - lienvandensteen@gmail.com
16
- executables: []
58
+ executables:
59
+ - cloudmunda
17
60
  extensions: []
18
61
  extra_rdoc_files: []
19
62
  files:
@@ -28,8 +71,25 @@ files:
28
71
  - Rakefile
29
72
  - bin/console
30
73
  - bin/setup
74
+ - exe/cloudmunda
31
75
  - lib/cloudmunda.rb
76
+ - lib/cloudmunda/api.rb
77
+ - lib/cloudmunda/api/access_token.rb
78
+ - lib/cloudmunda/api/client.rb
79
+ - lib/cloudmunda/api/o_auth_resource.rb
80
+ - lib/cloudmunda/cli.rb
81
+ - lib/cloudmunda/cli/launcher.rb
82
+ - lib/cloudmunda/cli/processor.rb
83
+ - lib/cloudmunda/cli/supervisor.rb
84
+ - lib/cloudmunda/cli/worker.rb
85
+ - lib/cloudmunda/configuration.rb
86
+ - lib/cloudmunda/graphql.rb
87
+ - lib/cloudmunda/graphql/client.rb
88
+ - lib/cloudmunda/graphql/user_tasks.rb
89
+ - lib/cloudmunda/loggable.rb
32
90
  - lib/cloudmunda/version.rb
91
+ - lib/cloudmunda/zeebe.rb
92
+ - lib/cloudmunda/zeebe/client.rb
33
93
  homepage: https://github.com/lienvdsteen/cloudmunda
34
94
  licenses:
35
95
  - MIT