pampa 2.0.29 → 2.0.31

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: '095438d108ee4f3cd1cf5d329fb1a0d29c38d6647a130c811e75ed2d73105d81'
4
- data.tar.gz: 45dd332d64c86e75d7e0b0f8e4575e3884a9cf486eabb959371af3b1da2c674c
3
+ metadata.gz: af7a0536c38fa454e4f28d00ec1be0d13399d6dffb2d390e8128f417c8f7af8e
4
+ data.tar.gz: 11bd7721b54ae0a8e3ae56702ab3891272ab8818ccfb3d04da077b747cfed833
5
5
  SHA512:
6
- metadata.gz: e76a96906f54dafa73f37c4109581f1779c77f086788a98e8278960bf2086228a1fd09851b3e37b94c72920495d009567d1f96699c63b87567925c84b8a1af2c
7
- data.tar.gz: a4869784e7f39a12eb3ef8327584ab773a0a0eac2b22c997cde5dd008e34f13fcdc5e9c0b05b5db86392e3fe8ffa4f8fdd5699052c5e5781d9a9990cae0546d9
6
+ metadata.gz: 3dd788d3ab9b61d0c36cf777cd2233dbed35a8c21b32b12ed2e393d77ed12f034a27bfb9f6cd4fc6d81d20f714babd96c73e6d916e68439bd22fb629d185e42b
7
+ data.tar.gz: 24a4bb824b6d4d39572e23033508f846d799f0cd5681c896a25298ef352b09cd5df58b1fe1a82ab25f9307658f236080b72880ab57234f70862cf28ae3a13d70
data/lib/pampa/app.rb ADDED
@@ -0,0 +1,194 @@
1
+ # MySaaS - Pampa Dashboard
2
+ # Copyright (C) 2022 ExpandedVenture, LLC.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # You may not use this file except in compliance with the License.
6
+ #
7
+ # Authors: Leandro Daniel Sardi (https://github.com/leandrosardi)
8
+ #
9
+
10
+ require 'pampa'
11
+ require "rubygems"
12
+
13
+ #
14
+ PARSER = BlackStack::SimpleCommandLineParser.new(
15
+ :description => 'This command will launch a Sinatra-based Pampa dashboard.',
16
+ :configuration => [{
17
+ :name=>'port',
18
+ :mandatory=>false,
19
+ :description=>'Listening port. Default: 3000.',
20
+ :type=>BlackStack::SimpleCommandLineParser::INT,
21
+ :default => 3000,
22
+ }, {
23
+ :name=>'config',
24
+ :mandatory=>false,
25
+ :description=>'Configuration file. Default: "config.rb".',
26
+ :type=>BlackStack::SimpleCommandLineParser::STRING,
27
+ :default => 'config.rb',
28
+ }, {
29
+ :name=>'db',
30
+ :mandatory=>false,
31
+ :default=>'postgres',
32
+ :description=>'Database driver. Supported values: postgres, crdb. Default: postgres.',
33
+ :type=>BlackStack::SimpleCommandLineParser::STRING,
34
+ }, {
35
+ :name=>'log',
36
+ :mandatory=>false,
37
+ :default=>true,
38
+ :description=>'If write log in the file ./app.log or not. Default: "yes"',
39
+ :type=>BlackStack::SimpleCommandLineParser::BOOL,
40
+ }]
41
+ )
42
+
43
+ # create logger
44
+ l = PARSER.value('log') ? BlackStack::LocalLogger.new('app.log') : BlackStack::BaseLogger.new(nil)
45
+
46
+ #
47
+ # load config file
48
+ l.logs "Loading #{PARSER.value('config').to_s.blue}... "
49
+ require PARSER.value('config')
50
+ l.logf 'done'.green
51
+
52
+ l.logs 'Connecting to database... '
53
+ if PARSER.value('db') == 'postgres'
54
+ DB = BlackStack::PostgreSQL::connect
55
+ elsif PARSER.value('db') == 'crdb'
56
+ DB = BlackStack::CockroachDB::connect
57
+ else
58
+ raise 'Unknown database driver.'
59
+ end
60
+ l.logf 'done'.green
61
+
62
+ #
63
+ spec = Gem.loaded_specs['pampa']
64
+ puts '
65
+ _______ _______ __ __ _______ _______
66
+ | || _ || |_| || || _ |
67
+ | _ || |_| || || _ || |_| |
68
+ | |_| || || || |_| || |
69
+ | ___|| || || ___|| |
70
+ | | | _ || ||_|| || | | _ |
71
+ |___| |__| |__||_| |_||___| |__| |__|
72
+
73
+ Version: '+spec.version.to_s.green+'.
74
+ Authors: '+spec.authors.join(', ').green+'.
75
+ Documentation: '+spec.homepage.blue+'
76
+
77
+ Sandbox: '+ (BlackStack.sandbox? ? 'yes'.green : 'no'.yellow) +'
78
+
79
+ '
80
+
81
+ PORT = PARSER.value("port")
82
+
83
+ configure { set :server, :puma }
84
+ set :bind, '0.0.0.0'
85
+ set :port, PORT
86
+ enable :sessions
87
+ enable :static
88
+
89
+ configure do
90
+ enable :cross_origin
91
+ end
92
+
93
+ before do
94
+ headers 'Access-Control-Allow-Origin' => '*',
95
+ 'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST']
96
+ end
97
+
98
+ set :protection, false
99
+
100
+ # Setting the root of views and public folders in the `~/code` folder in order to have access to extensions.
101
+ # reference: https://stackoverflow.com/questions/69028408/change-sinatra-views-directory-location
102
+ set :root, '.'
103
+ binding.pry
104
+ set :views, Gem.loaded_specs['pampa'].full_gem_path
105
+
106
+ # page not found redirection
107
+ not_found do
108
+ redirect '/404'
109
+ end
110
+
111
+ # unhandled exception redirectiopn
112
+ error do
113
+ max_lenght = 8000
114
+ s = "message=#{CGI.escape(env['sinatra.error'].to_s)}&"
115
+ s += "backtrace_size=#{CGI.escape(env['sinatra.error'].backtrace.size.to_s)}&"
116
+ i = 0
117
+ env['sinatra.error'].backtrace.each { |a|
118
+ a = "backtrace[#{i.to_s}]=#{CGI.escape(a.to_s)}&"
119
+ and_more = "backtrace[#{i.to_s}]=..."
120
+ if (s+a).size > max_lenght - and_more.size
121
+ s += and_more
122
+ break
123
+ else
124
+ s += a
125
+ end
126
+ i += 1
127
+ }
128
+ redirect "/500?#{s}"
129
+ end
130
+
131
+ # condition: api_key parameter is required too for the access points
132
+ set(:api_key) do |*roles|
133
+ condition do
134
+ @return_message = {}
135
+
136
+ @return_message[:status] = 'success'
137
+
138
+ # validate: the pages using the :api_key condition must work as post only.
139
+ if request.request_method != 'POST'
140
+ @return_message[:status] = 'Pages with an `api_key` parameter are only available for POST requests.'
141
+ @return_message[:value] = ""
142
+ halt @return_message.to_json
143
+ end
144
+
145
+ @body = JSON.parse(request.body.read)
146
+
147
+ if !@body.has_key?('api_key')
148
+ # libero recursos
149
+ DB.disconnect
150
+ GC.start
151
+ @return_message[:status] = "api_key is required on #{@body.to_s}"
152
+ @return_message[:value] = ""
153
+ halt @return_message.to_json
154
+ end
155
+
156
+ if !@body['api_key'].guid?
157
+ # libero recursos
158
+ DB.disconnect
159
+ GC.start
160
+
161
+ @return_message[:status] = "Invalid api_key (#{@body['api_key']}))"
162
+ @return_message[:value] = ""
163
+ halt @return_message.to_json
164
+ end
165
+
166
+ validation_api_key = @body['api_key'].to_guid.downcase
167
+
168
+ if validation_api_key != API_KEY
169
+ # libero recursos
170
+ DB.disconnect
171
+ GC.start
172
+ #
173
+ @return_message[:status] = 'Wrong api_key'
174
+ @return_message[:value] = ""
175
+ halt @return_message.to_json
176
+ end
177
+ end
178
+ end
179
+
180
+ get '/404', :agent => /(.*)/ do
181
+ erb :'views/404', :layout => :'/views/layouts/public'
182
+ end
183
+
184
+ get '/500', :agent => /(.*)/ do
185
+ erb :'views/500', :layout => :'/views/layouts/public'
186
+ end
187
+
188
+ # dashboard
189
+ get '/', :agent => /(.*)/ do
190
+ redirect '/dashboard'
191
+ end
192
+ get '/dashboard', :agent => /(.*)/ do
193
+ erb :'views/dashboard' #, :layout => :'/views/layouts/public'
194
+ end
@@ -0,0 +1,143 @@
1
+ # Pampa Dispatcher
2
+ # Copyright (C) 2022 ExpandedVenture, LLC.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # You may not use this file except in compliance with the License.
6
+ #
7
+ # Authors: Leandro Daniel Sardi (https://github.com/leandrosardi)
8
+ #
9
+
10
+ require 'pampa'
11
+
12
+ # parse command line parameters
13
+ PARSER = BlackStack::SimpleCommandLineParser.new(
14
+ :description => 'This script starts an infinite loop. Each loop will look for a task to perform. Must be a delay between each loop.',
15
+ :configuration => [{
16
+ :name=>'delay',
17
+ :mandatory=>false,
18
+ :default=>10, # 5 minutes
19
+ :description=>'Minimum delay between loops. A minimum of 10 seconds is recommended, in order to don\'t hard the database server. Default is 30 seconds.',
20
+ :type=>BlackStack::SimpleCommandLineParser::INT,
21
+ }, {
22
+ :name=>'config',
23
+ :mandatory=>false,
24
+ :default=>'config.rb',
25
+ :description=>'Configuration file. Default: config.',
26
+ :type=>BlackStack::SimpleCommandLineParser::STRING,
27
+ }, {
28
+ :name=>'db',
29
+ :mandatory=>false,
30
+ :default=>'postgres',
31
+ :description=>'Database driver. Supported values: postgres, crdb. Default: postgres.',
32
+ :type=>BlackStack::SimpleCommandLineParser::STRING,
33
+ }, {
34
+ :name=>'log',
35
+ :mandatory=>false,
36
+ :default=>true,
37
+ :description=>'If write log in the file ./dispatcher.log or not. Default: "yes"',
38
+ :type=>BlackStack::SimpleCommandLineParser::BOOL,
39
+ }]
40
+ )
41
+
42
+ # create logger
43
+ l = PARSER.value('log') ? BlackStack::LocalLogger.new('dispatcher.log') : BlackStack::BaseLogger.new(nil)
44
+
45
+ # assign logger to pampa
46
+ BlackStack::Pampa.set_logger(l)
47
+
48
+ # load config file
49
+ l.logs "Loading #{PARSER.value('config').to_s.blue}... "
50
+ require PARSER.value('config')
51
+ l.logf 'done'.green
52
+
53
+ l.logs 'Connecting to database... '
54
+ if PARSER.value('db') == 'postgres'
55
+ DB = BlackStack::PostgreSQL::connect
56
+ elsif PARSER.value('db') == 'crdb'
57
+ DB = BlackStack::CockroachDB::connect
58
+ else
59
+ raise 'Unknown database driver.'
60
+ end
61
+ l.logf 'done'.green
62
+
63
+ # call dispatcher code snippet
64
+ l.logs 'Calling dispatcher code snippet... '
65
+ f = BlackStack::Pampa.dispatcher_function
66
+ if f
67
+ f.call
68
+ l.logf 'done'.green
69
+ else
70
+ l.logf 'no dispatcher code snippet found'.yellow
71
+ end
72
+
73
+ # loop
74
+ begin
75
+ while true
76
+ # get the start loop time
77
+ l.logs 'Starting loop... '
78
+ start = Time.now()
79
+ l.logf 'done'.green
80
+
81
+ begin
82
+ # assign workers to each job
83
+ l.logs 'Stretching clusters... '
84
+ BlackStack::Pampa.stretch
85
+ l.logf 'done'.green
86
+
87
+ # relaunch expired tasks
88
+ l.logs 'Relaunching expired tasks... '
89
+ BlackStack::Pampa.relaunch
90
+ l.logf 'done'.green
91
+
92
+ # dispatch tasks to each worker
93
+ l.logs 'Dispatching tasks to workers... '
94
+ BlackStack::Pampa.dispatch
95
+ l.logf 'done'.green
96
+
97
+ # note: this catches the CTRL+C signal.
98
+ # note: this catches the `kill` command, ONLY if it has not the `-9` option.
99
+ rescue SignalException, SystemExit, Interrupt => e
100
+ l.logf 'Bye!'.yellow
101
+ raise e
102
+ rescue => e
103
+ l.logf "Error: #{e.to_console}".red
104
+ end
105
+
106
+ # release resource
107
+ l.logs 'Releasing resources... '
108
+ GC.start
109
+ DB.disconnect
110
+ l.logf 'done'.green
111
+
112
+ # get the end loop time
113
+ l.logs 'Ending loop... '
114
+ finish = Time.now()
115
+ l.logf 'done'.green
116
+
117
+ # get different in seconds between start and finish
118
+ # if diff > 30 seconds
119
+ l.logs 'Calculating loop duration... '
120
+ diff = finish - start
121
+ l.logf 'done'.green + " (#{diff.to_s.blue})"
122
+
123
+ if diff < PARSER.value('delay')
124
+ # sleep for 30 seconds
125
+ n = PARSER.value('delay')-diff
126
+
127
+ l.logs 'Sleeping for '+n.to_label+' seconds... '
128
+ sleep n
129
+ l.logf 'done'.green
130
+ else
131
+ l.log 'No sleeping. The loop took '+diff.to_label+' seconds.'
132
+ end
133
+ end # while true
134
+ rescue SignalException, SystemExit, Interrupt
135
+ # note: this catches the CTRL+C signal.
136
+ # note: this catches the `kill` command, ONLY if it has not the `-9` option.
137
+ l.logf 'Process Interrumpted.'.yellow
138
+ l.log 'Bye!'.yellow
139
+ rescue => e
140
+ l.logf "Fatal Error: #{e.to_console}".red
141
+ rescue
142
+ l.logf 'Unknown Fatal Error.'.red
143
+ end # begin
@@ -0,0 +1,182 @@
1
+ # MySaaS - Pampa Worker
2
+ # Copyright (C) 2022 ExpandedVenture, LLC.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # You may not use this file except in compliance with the License.
6
+ #
7
+ # Authors: Leandro Daniel Sardi (https://github.com/leandrosardi)
8
+ #
9
+
10
+ # load gem and connect database
11
+ require 'pampa'
12
+
13
+ # parse command line parameters
14
+ PARSER = BlackStack::SimpleCommandLineParser.new(
15
+ :description => 'This script starts an infinite loop. Each loop will look for a task to perform. Must be a delay between each loop.',
16
+ :configuration => [{
17
+ :name=>'delay',
18
+ :mandatory=>false,
19
+ :default=>10,
20
+ :description=>'Minimum delay between loops. A minimum of 10 seconds is recommended, in order to don\'t hard the database server. Default is 30 seconds.',
21
+ :type=>BlackStack::SimpleCommandLineParser::INT,
22
+ }, {
23
+ :name=>'config',
24
+ :mandatory=>false,
25
+ :default=>'config.rb',
26
+ :description=>'Configuration file. Default: config.',
27
+ :type=>BlackStack::SimpleCommandLineParser::STRING,
28
+ }, {
29
+ :name=>'id',
30
+ :mandatory=>true,
31
+ :description=>'Write here a unique identifier for the worker.',
32
+ :type=>BlackStack::SimpleCommandLineParser::STRING,
33
+ }, {
34
+ :name=>'db',
35
+ :mandatory=>false,
36
+ :default=>'postgres',
37
+ :description=>'Database driver. Values: postgres, crdb. Default: postgres.',
38
+ :type=>BlackStack::SimpleCommandLineParser::STRING,
39
+ }, {
40
+ :name=>'log',
41
+ :mandatory=>false,
42
+ :default=>true,
43
+ :description=>'If write log in the file ./worker.#{id}.log or not. Default: "yes"',
44
+ :type=>BlackStack::SimpleCommandLineParser::BOOL,
45
+ }]
46
+ )
47
+
48
+ # create logger
49
+ l = PARSER.value('log') ? BlackStack::LocalLogger.new("worker.#{PARSER.value('id')}.log") : BlackStack::BaseLogger.new(nil)
50
+
51
+ # assign logger to pampa
52
+ BlackStack::Pampa.set_logger(l)
53
+
54
+ # load config file
55
+ l.logs "Loading #{PARSER.value('config').to_s.blue}... "
56
+ require PARSER.value('config')
57
+ l.logf 'done'.green
58
+
59
+ l.logs 'Connecting to database... '
60
+ if PARSER.value('db') == 'postgres'
61
+ DB = BlackStack::PostgreSQL::connect
62
+ elsif PARSER.value('db') == 'crdb'
63
+ DB = BlackStack::CockroachDB::connect
64
+ else
65
+ raise 'Unknown database driver.'
66
+ end
67
+ l.logf 'done'.green
68
+
69
+ # call dispatcher code snippet
70
+ l.logs 'Calling worker code snippet... '
71
+ f = BlackStack::Pampa.worker_function
72
+ if f
73
+ f.call
74
+ l.logf 'done'.green
75
+ else
76
+ l.logf 'no worker code snippet found'.yellow
77
+ end
78
+
79
+ begin
80
+ # getting the worker object
81
+ l.logs 'Getting worker '+PARSER.value('id').blue+'... '
82
+ worker = BlackStack::Pampa.workers.select { |w| w.id == PARSER.value('id') }.first
83
+ raise 'Worker '+PARSER.value('id')+' not found.' if worker.nil?
84
+ l.logf 'done'.green
85
+
86
+ # start the loop
87
+ while true
88
+ # get the start loop time
89
+ l.logs 'Starting loop... '
90
+ start = Time.now()
91
+ l.done
92
+
93
+ begin
94
+ l.log ''
95
+ l.logs 'Starting cycle... '
96
+
97
+ BlackStack::Pampa.jobs.each { |job|
98
+ task = nil
99
+ begin
100
+ l.logs 'Processing job '+job.name.blue+'... '
101
+ tasks = job.occupied_slots(worker)
102
+ l.logf tasks.size.to_s+' tasks in queue.'
103
+
104
+ tasks.each { |t|
105
+ task = t
106
+
107
+ l.logs 'Flag task '+job.name.blue+'.'+task[job.field_primary_key.to_sym].to_s.blue+' started... '
108
+ job.start(task)
109
+ l.logf 'done'.green
110
+
111
+ l.logs 'Processing task '+task[job.field_primary_key.to_sym].to_s.blue+'... '
112
+ job.processing_function.call(task, l, job, worker)
113
+ l.logf 'done'.green
114
+
115
+ l.logs 'Flag task '+job.name.blue+'.'+task[job.field_primary_key.to_sym].to_s.blue+' finished... '
116
+ job.finish(task)
117
+ l.logf 'done'.green
118
+ }
119
+ # note: this catches the CTRL+C signal.
120
+ # note: this catches the `kill` command, ONLY if it has not the `-9` option.
121
+ rescue SignalException, SystemExit, Interrupt => e
122
+ l.logs 'Flag task '+job.name.blue+'.'+task[job.field_primary_key.to_sym].to_s.blue+' interrumpted... '
123
+ job.finish(task, e)
124
+ l.logf 'done'.green
125
+
126
+ l.logf 'Bye!'.yellow
127
+
128
+ raise e
129
+
130
+ rescue => e
131
+ l.logs 'Flag task '+job.name.blue+'.'+task[job.field_primary_key.to_sym].to_s.blue+' failed... '
132
+ job.finish(task, e)
133
+ l.logf 'done'.green
134
+
135
+ l.logf "Error: #{e.to_console}".red
136
+ end
137
+ }
138
+
139
+ l.done
140
+
141
+ rescue => e
142
+ l.logf 'Error: '+e.message
143
+ end
144
+
145
+ # release resource
146
+ l.logs 'Releasing resources... '
147
+ GC.start
148
+ DB.disconnect
149
+ l.logf 'done'.green
150
+
151
+ # get the end loop time
152
+ l.logs 'Ending loop... '
153
+ finish = Time.now()
154
+ l.logf 'done'.green
155
+
156
+ # get different in seconds between start and finish
157
+ # if diff > 30 seconds
158
+ l.logs 'Calculating loop duration... '
159
+ diff = finish - start
160
+ l.logf 'done'.green + " (#{diff.to_s.blue})"
161
+
162
+ if diff < PARSER.value('delay')
163
+ # sleep for 30 seconds
164
+ n = PARSER.value('delay')-diff
165
+
166
+ l.logs 'Sleeping for '+n.to_label+' seconds... '
167
+ sleep n
168
+ l.logf 'done'.green
169
+ else
170
+ l.log 'No sleeping. The loop took '+diff.to_label.blue+' seconds.'
171
+ end
172
+ end # while true
173
+ rescue SignalException, SystemExit, Interrupt
174
+ # note: this catches the CTRL+C signal.
175
+ # note: this catches the `kill` command, ONLY if it has not the `-9` option.
176
+ l.logf 'Process Interrumpted.'.yellow
177
+ l.log 'Bye!'.yellow
178
+ rescue => e
179
+ l.logf "Fatal Error: #{e.to_console}".red
180
+ rescue
181
+ l.logf 'Unknown Fatal Error.'.red
182
+ end