marty 5.2.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +1 -1
- data/.rubocop_todo.yml +62 -77
- data/Dockerfile.dummy +1 -1
- data/app/assets/javascripts/marty/extjs/extensions/marty.js +11 -0
- data/app/components/marty/log_view.rb +1 -1
- data/app/components/marty/promise_view.rb +0 -3
- data/app/jobs/marty/remove_old_promises_job.rb +7 -0
- data/app/models/marty/data_grid.rb +0 -163
- data/app/models/marty/event.rb +2 -2
- data/app/models/marty/posting.rb +0 -7
- data/app/models/marty/promise.rb +1 -1
- data/app/services/marty/data_grid_view/save_grid.rb +2 -2
- data/app/services/marty/jobs/schedule.rb +5 -0
- data/db/migrate/510_schedule_job_to_remove_old_promises.rb +19 -0
- data/lib/marty.rb +8 -0
- data/{other → lib}/marty/api/base.rb +14 -17
- data/{other → lib}/marty/diagnostic/aws/ec2_instance.rb +2 -2
- data/{other → lib}/marty/diagnostic/aws/error.rb +0 -0
- data/{other → lib}/marty/diagnostic/base.rb +0 -0
- data/{other → lib}/marty/diagnostic/collection.rb +0 -0
- data/{other → lib}/marty/diagnostic/connections.rb +0 -0
- data/{other → lib}/marty/diagnostic/database.rb +0 -0
- data/{other → lib}/marty/diagnostic/delayed_job_version.rb +0 -0
- data/{other → lib}/marty/diagnostic/delayed_job_workers.rb +0 -0
- data/{other → lib}/marty/diagnostic/environment_variables.rb +0 -0
- data/{other → lib}/marty/diagnostic/fatal.rb +0 -0
- data/{other → lib}/marty/diagnostic/node.rb +0 -0
- data/{other → lib}/marty/diagnostic/nodes.rb +1 -2
- data/{other → lib}/marty/diagnostic/packer.rb +0 -0
- data/{other → lib}/marty/diagnostic/reporter.rb +2 -2
- data/{other → lib}/marty/diagnostic/request.rb +0 -0
- data/{other → lib}/marty/diagnostic/scheduled_jobs.rb +0 -0
- data/{other → lib}/marty/diagnostic/version.rb +0 -0
- data/lib/marty/engine.rb +5 -0
- data/lib/marty/version.rb +3 -1
- data/lib/marty/xl.rb +5 -5
- data/spec/dummy/app/assets/config/manifest.js +0 -0
- data/spec/dummy/app/jobs/test2_job.rb +4 -0
- data/spec/dummy/config/application.rb +1 -4
- data/spec/dummy/config/initializers/assets.rb +1 -1
- data/spec/features/extjs_spec.rb +58 -0
- data/spec/features/schedule_jobs_dashboard_spec.rb +9 -9
- data/spec/lib/logger_spec.rb +2 -2
- data/spec/models/posting_spec.rb +0 -13
- data/spec/services/jobs/schedule_spec.rb +40 -0
- data/spec/support/chromedriver.rb +2 -0
- metadata +27 -22
- data/spec/dummy/app/jobs/test_job2.rb +0 -4
data/Dockerfile.dummy
CHANGED
@@ -897,3 +897,14 @@ Ext.define('Marty.layout.container.Auto', {
|
|
897
897
|
},
|
898
898
|
|
899
899
|
});
|
900
|
+
|
901
|
+
Ext.define('overrides.grid.column.Column', {
|
902
|
+
override: 'Ext.grid.column.Column',
|
903
|
+
|
904
|
+
initConfig: function(config) {
|
905
|
+
if (!config.renderer && !this.updater) {
|
906
|
+
config.formatter = 'htmlEncode'
|
907
|
+
}
|
908
|
+
return this.callParent(arguments)
|
909
|
+
}
|
910
|
+
})
|
@@ -226,12 +226,6 @@ class Marty::DataGrid < Marty::Base
|
|
226
226
|
"ri: #{row_info}" if res['error']
|
227
227
|
end
|
228
228
|
|
229
|
-
if ret_grid_data
|
230
|
-
dg = find(dgh['id'])
|
231
|
-
md, mmd = modify_grid(h_passed, dg.metadata, dg.data)
|
232
|
-
res['data'] = md
|
233
|
-
res['metadata'] = mmd
|
234
|
-
end
|
235
229
|
res
|
236
230
|
end
|
237
231
|
|
@@ -683,142 +677,8 @@ class Marty::DataGrid < Marty::Base
|
|
683
677
|
end
|
684
678
|
end
|
685
679
|
|
686
|
-
def self.modify_grid(params, metadata, data)
|
687
|
-
removes = ['h', 'v'].each_with_object({}) { |dir, hash| hash[dir] = Set.new }
|
688
|
-
|
689
|
-
metadata_copy, data_copy = metadata.deep_dup, data.deep_dup
|
690
|
-
|
691
|
-
metadata_copy.each do |meta|
|
692
|
-
dir, keys, type, rs_keep = meta.values_at(
|
693
|
-
'dir', 'keys', 'type', 'rs_keep')
|
694
|
-
next unless rs_keep
|
695
|
-
|
696
|
-
if type == 'numrange' || type == 'int4range'
|
697
|
-
modop, modvalparm = parse_bounds(rs_keep)
|
698
|
-
modval = params[modvalparm]
|
699
|
-
if modval
|
700
|
-
prune_a, rewrite_a = compute_numeric_mods(keys, modop, modval)
|
701
|
-
removes[dir].merge(prune_a)
|
702
|
-
rewrite_a.each { |(ind, value)| keys[ind] = value }
|
703
|
-
end
|
704
|
-
else
|
705
|
-
modval = params[rs_keep]
|
706
|
-
if modval
|
707
|
-
prune_a, rewrite_a = compute_set_mods(keys, modval)
|
708
|
-
removes[dir].merge(prune_a)
|
709
|
-
rewrite_a.each { |(ind, value)| keys[ind] = value }
|
710
|
-
end
|
711
|
-
end
|
712
|
-
end
|
713
|
-
|
714
|
-
removes.reject! { |_dir, set| set.empty? }
|
715
|
-
|
716
|
-
removes.each do |dir, _set|
|
717
|
-
metadata_copy.select { |m| m['dir'] == dir }.each do |meta|
|
718
|
-
meta['keys'] = remove_indices(meta['keys'], removes[dir])
|
719
|
-
end
|
720
|
-
end
|
721
|
-
|
722
|
-
data_copy = remove_indices(data_copy, removes['v']) if removes['v']
|
723
|
-
|
724
|
-
data_copy.each_index do |index|
|
725
|
-
data_copy[index] = remove_indices(data_copy[index], removes['h'])
|
726
|
-
end if removes['h']
|
727
|
-
|
728
|
-
[data_copy, metadata_copy]
|
729
|
-
end
|
730
|
-
|
731
680
|
private
|
732
681
|
|
733
|
-
def self.remove_indices(orig_array, inds)
|
734
|
-
orig_array.each_with_object([]).with_index do |(item, new_array), index|
|
735
|
-
new_array.push(item) unless inds.include?(index)
|
736
|
-
end
|
737
|
-
end
|
738
|
-
|
739
|
-
def self.opposite_sign(op) # toggle sign and inclusivity
|
740
|
-
{
|
741
|
-
:< => :>=,
|
742
|
-
:<= => :>,
|
743
|
-
:> => :<=,
|
744
|
-
:>= => :<,
|
745
|
-
}[op]
|
746
|
-
end
|
747
|
-
|
748
|
-
def self.compute_numeric_mods(keys, op, val)
|
749
|
-
@keyhash ||= {}
|
750
|
-
prune_a, rewrite_a = [], []
|
751
|
-
|
752
|
-
# features allow multiple values, but for constraint on a grid range
|
753
|
-
# only a scalar is meaningful. so if there are multiple values we
|
754
|
-
# take the first value to use
|
755
|
-
value = val.is_a?(Array) ? val[0] : val
|
756
|
-
keys.each_with_index do |key, index|
|
757
|
-
lhop, orig_lhv, orig_rhv, rhop = @keyhash[key] ||= parse_range(key)
|
758
|
-
|
759
|
-
lhv, rhv = orig_lhv || -Float::INFINITY, orig_rhv || Float::INFINITY
|
760
|
-
|
761
|
-
case op
|
762
|
-
when :>=, :>
|
763
|
-
next if value > rhv
|
764
|
-
|
765
|
-
if value == rhv
|
766
|
-
if rhop == :<= && op == :>=
|
767
|
-
rewrite_a.push(
|
768
|
-
[index, rewrite_range(lhop, orig_lhv, orig_rhv, :<)])
|
769
|
-
end
|
770
|
-
elsif value > lhv
|
771
|
-
rewrite_a.push(
|
772
|
-
[index, rewrite_range(lhop, orig_lhv, value, opposite_sign(op))])
|
773
|
-
elsif value == lhv && lhop == :>= && op == :>
|
774
|
-
rewrite_a.push([index, rewrite_range(:>=, value, value, :<=)])
|
775
|
-
elsif value <= lhv
|
776
|
-
prune_a.push(index)
|
777
|
-
end
|
778
|
-
when :<=, :<
|
779
|
-
next if value < lhv
|
780
|
-
|
781
|
-
if value == lhv
|
782
|
-
if lhop == :>= && op == :<=
|
783
|
-
rewrite_a.push(
|
784
|
-
[index, rewrite_range(:>, orig_lhv, orig_rhv, rhop)])
|
785
|
-
end
|
786
|
-
elsif value < rhv
|
787
|
-
rewrite_a.push(
|
788
|
-
[index, rewrite_range(opposite_sign(op), value, orig_rhv, rhop)])
|
789
|
-
elsif value == rhv && rhop == :<= && op == :<
|
790
|
-
rewrite_a.push([index, rewrite_range(:>=, value, value, :<=)])
|
791
|
-
elsif value >= rhv
|
792
|
-
prune_a.push(index)
|
793
|
-
end
|
794
|
-
end
|
795
|
-
end
|
796
|
-
[prune_a, rewrite_a]
|
797
|
-
end
|
798
|
-
|
799
|
-
# value is a list of what to keep
|
800
|
-
def self.compute_set_mods(keys, val)
|
801
|
-
prune_a, rewrite_a, value = [], [], Array(val)
|
802
|
-
|
803
|
-
keys.each_with_index do |key, index|
|
804
|
-
# rewrite any nil (wildcard) keys in the dimension
|
805
|
-
# to be our 'to-keep' val(s)
|
806
|
-
if key.nil?
|
807
|
-
rewrite_a.push([index, value])
|
808
|
-
next
|
809
|
-
end
|
810
|
-
|
811
|
-
remove = key - value
|
812
|
-
if remove == key
|
813
|
-
prune_a.push(index)
|
814
|
-
next
|
815
|
-
end
|
816
|
-
|
817
|
-
rewrite_a.push([index, key - remove]) if remove != []
|
818
|
-
end
|
819
|
-
[prune_a, rewrite_a]
|
820
|
-
end
|
821
|
-
|
822
682
|
def self.parse_range(key)
|
823
683
|
match = key.match(/\A(\[|\()([0-9\.-]*),([0-9\.-]*)(\]|\))\z/)
|
824
684
|
raise "unrecognized pattern #{key}" unless match
|
@@ -831,29 +691,6 @@ class Marty::DataGrid < Marty::Base
|
|
831
691
|
[lboundary == '(' ? :> : :>=, lhv, rhv, rboundary == ')' ? :< : :<=]
|
832
692
|
end
|
833
693
|
|
834
|
-
def self.rewrite_range(lb, lhv, rhv, rb)
|
835
|
-
lboundary = lb == :> ? '(' : '['
|
836
|
-
|
837
|
-
# even though numranges are float type, we don't want to output ".0"
|
838
|
-
# for integer values. So for values like that we convert to int
|
839
|
-
# first before conversion to string
|
840
|
-
lvalue = (lhv.to_i == lhv ? lhv.to_i : lhv).to_s
|
841
|
-
rvalue = (rhv.to_i == rhv ? rhv.to_i : rhv).to_s
|
842
|
-
rboundary = rb == :< ? ')' : ']'
|
843
|
-
lboundary + lvalue + ',' + rvalue + rboundary
|
844
|
-
end
|
845
|
-
|
846
|
-
def self.parse_bounds(key)
|
847
|
-
match = key.match(/\A *(<|>|<=|>=)? *([a-z_]+) *\z/)
|
848
|
-
raise "unrecognized pattern #{key}" unless match
|
849
|
-
|
850
|
-
opstr, ident = match[1..2]
|
851
|
-
|
852
|
-
# data grid value is expressed as what to keep
|
853
|
-
# we convert to the opposite (what to prune)
|
854
|
-
[opposite_sign(opstr.to_sym), ident]
|
855
|
-
end
|
856
|
-
|
857
694
|
def self.remove_not(string)
|
858
695
|
return string unless string.starts_with?(NOT_STRING_START)
|
859
696
|
return string unless string.ends_with?(NOT_STRING_END)
|
data/app/models/marty/event.rb
CHANGED
@@ -119,10 +119,10 @@ SQL
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def self.last_event(klass, subject_id, operation = nil)
|
122
|
-
hash = all_running.
|
122
|
+
hash = all_running.reverse.find do |pm|
|
123
123
|
pm['klass'] == klass && pm['subject_id'] == subject_id.to_i &&
|
124
124
|
(operation.nil? || pm['enum_event_operation'] == operation)
|
125
|
-
end
|
125
|
+
end
|
126
126
|
|
127
127
|
return hash if hash
|
128
128
|
|
data/app/models/marty/posting.rb
CHANGED
@@ -67,13 +67,6 @@ class Marty::Posting < Marty::Base
|
|
67
67
|
q.order('created_dt DESC').first.attributes
|
68
68
|
end
|
69
69
|
|
70
|
-
def self.get_latest(limit, _is_test = nil)
|
71
|
-
# IMPORTANT: is_test arg is ignored (KEEP for backward compat.)
|
72
|
-
|
73
|
-
q = where("created_dt <> 'infinity'").
|
74
|
-
order('created_dt DESC').limit(limit)
|
75
|
-
end
|
76
|
-
|
77
70
|
delorean_fn :get_latest_by_type, sig: [1, 2] do |limit, posting_types = []|
|
78
71
|
raise 'missing posting types list' unless posting_types
|
79
72
|
raise 'bad posting types list' unless posting_types.is_a?(Array)
|
data/app/models/marty/promise.rb
CHANGED
@@ -213,7 +213,7 @@ class Marty::Promise < Marty::Base
|
|
213
213
|
def cleanup(all = false)
|
214
214
|
where(
|
215
215
|
'start_dt < ? AND parent_id IS NULL',
|
216
|
-
|
216
|
+
all ? Time.zone.now : 4.hours.ago
|
217
217
|
).destroy_all
|
218
218
|
rescue StandardError => e
|
219
219
|
Marty::Util.logger.error("promise GC error: #{e}")
|
@@ -25,8 +25,8 @@ module Marty
|
|
25
25
|
data_as_array = data.map do |row|
|
26
26
|
row.keys.map { |key| row[key] }
|
27
27
|
end
|
28
|
-
vcnt = dg.metadata.
|
29
|
-
hcnt = dg.metadata.
|
28
|
+
vcnt = dg.metadata.count { |md| md['dir'] == 'v' }
|
29
|
+
hcnt = dg.metadata.count { |md| md['dir'] == 'h' }
|
30
30
|
cur_data_dim = [dg.data.length, dg.data[0].length]
|
31
31
|
exported = dg.export.lines
|
32
32
|
sep = exported.each_with_index.detect { |l, _i| /^\s*$/.match(l) }.last
|
@@ -7,6 +7,11 @@ module Marty
|
|
7
7
|
glob = Rails.root.join('app', 'jobs', '**', '*_job.rb')
|
8
8
|
Dir.glob(glob).each { |f| require f }
|
9
9
|
|
10
|
+
glob2 = Marty.root.join('app', 'jobs', '**', '*_job.rb')
|
11
|
+
Dir.glob(glob2).each { |f| require f }
|
12
|
+
|
13
|
+
Delayed::Job.where.not(cron: nil).each(&:destroy!)
|
14
|
+
|
10
15
|
Marty::CronJob.subclasses.map do |klass|
|
11
16
|
klass.schedule
|
12
17
|
[klass.name, klass.cron_expression]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class ScheduleJobToRemoveOldPromises < ActiveRecord::Migration[4.2]
|
2
|
+
def up
|
3
|
+
cron_every_hour = '0 * * * *'
|
4
|
+
|
5
|
+
Marty::BackgroundJob::Schedule.create!(
|
6
|
+
job_class: 'Marty::RemoveOldPromisesJob',
|
7
|
+
cron: cron_every_hour,
|
8
|
+
state: 'on'
|
9
|
+
)
|
10
|
+
|
11
|
+
::Marty::RemoveOldPromisesJob.schedule
|
12
|
+
end
|
13
|
+
|
14
|
+
def down
|
15
|
+
Marty::BackgroundJob::Schedule.find_by(
|
16
|
+
job_class: 'Marty::RemoveOldPromisesJob'
|
17
|
+
)&.destroy
|
18
|
+
end
|
19
|
+
end
|
data/lib/marty.rb
CHANGED
@@ -28,11 +28,9 @@ class Marty::Api::Base
|
|
28
28
|
params
|
29
29
|
end
|
30
30
|
|
31
|
-
def self.before_evaluate api_params
|
32
|
-
end
|
31
|
+
def self.before_evaluate api_params; end
|
33
32
|
|
34
|
-
def self.after_evaluate api_params, result
|
35
|
-
end
|
33
|
+
def self.after_evaluate api_params, result; end
|
36
34
|
|
37
35
|
@@numbers = {}
|
38
36
|
@@schemas = {}
|
@@ -60,7 +58,7 @@ class Marty::Api::Base
|
|
60
58
|
# get_schema will either return a hash with the schema,
|
61
59
|
# or a string with the error
|
62
60
|
input_schema = @@schemas[schema_key] ||=
|
63
|
-
|
61
|
+
Marty::JsonSchema.get_schema(*schema_key)
|
64
62
|
rescue StandardError => e
|
65
63
|
return { error: e.message }
|
66
64
|
end
|
@@ -69,7 +67,7 @@ class Marty::Api::Base
|
|
69
67
|
if input_schema.is_a?(Hash)
|
70
68
|
# fix numbers types
|
71
69
|
numbers = @@numbers[schema_key] ||=
|
72
|
-
|
70
|
+
Marty::JsonSchema.get_numbers(input_schema)
|
73
71
|
|
74
72
|
# modify params in place
|
75
73
|
Marty::JsonSchema.fix_numbers(params[:params], numbers)
|
@@ -85,14 +83,14 @@ class Marty::Api::Base
|
|
85
83
|
return { "error": input_schema } if input_schema.is_a?(String)
|
86
84
|
|
87
85
|
begin
|
88
|
-
res = SchemaValidator
|
86
|
+
res = SchemaValidator.validate_schema(input_schema, params[:params])
|
89
87
|
rescue NameError
|
90
88
|
return { error: "Unrecognized PgEnum for attribute #{params[:attr]}" }
|
91
89
|
rescue StandardError => e
|
92
90
|
return { error: "#{params[:attr]}: #{e.message}" }
|
93
91
|
end
|
94
92
|
|
95
|
-
schema_errors = SchemaValidator
|
93
|
+
schema_errors = SchemaValidator.get_errors(res) unless res.empty?
|
96
94
|
return { error: "Error(s) validating: #{schema_errors}" } if
|
97
95
|
schema_errors
|
98
96
|
end
|
@@ -101,8 +99,8 @@ class Marty::Api::Base
|
|
101
99
|
begin
|
102
100
|
engine = Marty::ScriptSet.new(params[:tag]).get_engine(params[:script])
|
103
101
|
rescue StandardError => e
|
104
|
-
error = "Can't get engine: #{params[:script] || 'nil'} with tag: "
|
105
|
-
|
102
|
+
error = "Can't get engine: #{params[:script] || 'nil'} with tag: " \
|
103
|
+
"#{params[:tag] || 'nil'}; message: #{e.message}"
|
106
104
|
Marty::Logger.info error
|
107
105
|
return { error: error }
|
108
106
|
end
|
@@ -127,13 +125,13 @@ class Marty::Api::Base
|
|
127
125
|
if config[:output_validated] && !(res.is_a?(Hash) && res['error'])
|
128
126
|
begin
|
129
127
|
output_schema_params = params + { attr: params[:attr] + '_' }
|
130
|
-
schema = SchemaValidator
|
128
|
+
schema = SchemaValidator.get_schema(output_schema_params)
|
131
129
|
rescue StandardError => e
|
132
130
|
return { error: e.message }
|
133
131
|
end
|
134
132
|
|
135
133
|
begin
|
136
|
-
schema_errors = SchemaValidator
|
134
|
+
schema_errors = SchemaValidator.validate_schema(schema, res)
|
137
135
|
rescue NameError
|
138
136
|
return { error: "Unrecognized PgEnum for attribute #{attr}" }
|
139
137
|
rescue StandardError => e
|
@@ -160,7 +158,7 @@ class Marty::Api::Base
|
|
160
158
|
Marty::Logger.info "Evaluation error: #{msg}"
|
161
159
|
return retval = msg
|
162
160
|
ensure
|
163
|
-
error = Hash
|
161
|
+
error = retval.is_a?(Hash) ? retval[:error] : nil
|
164
162
|
end
|
165
163
|
end
|
166
164
|
|
@@ -189,8 +187,7 @@ class Marty::Api::Base
|
|
189
187
|
end_time: Time.zone.now,
|
190
188
|
error: error,
|
191
189
|
remote_ip: request.remote_ip,
|
192
|
-
auth_name: params[:auth]
|
193
|
-
}
|
190
|
+
auth_name: params[:auth] }
|
194
191
|
end
|
195
192
|
|
196
193
|
def self.log result, params, request
|
@@ -221,7 +218,7 @@ class Marty::Api::Base
|
|
221
218
|
end
|
222
219
|
|
223
220
|
def self.massage_message(msg)
|
224
|
-
m = %r
|
221
|
+
m = %r{'#/([^']+)' of type ([^ ]+) matched the disallowed schema}.
|
225
222
|
match(msg)
|
226
223
|
|
227
224
|
return msg unless m
|
@@ -239,7 +236,7 @@ class Marty::Api::Base
|
|
239
236
|
fa, fragment, message, errors = errs.values_at(:failed_attribute,
|
240
237
|
:fragment,
|
241
238
|
:message, :errors)
|
242
|
-
(
|
239
|
+
(['AllOf', 'AnyOf', 'Not'].include?(fa) && fragment == '#/' ?
|
243
240
|
[] : [massage_message(message)]) + _get_errors(errors || {})
|
244
241
|
end
|
245
242
|
end
|
@@ -70,13 +70,13 @@ class Marty::Diagnostic::Aws::Ec2Instance < Marty::Aws::Request
|
|
70
70
|
instances = ensure_resp(
|
71
71
|
['reservationSet', 'item', 'instancesSet', 'item'],
|
72
72
|
resp
|
73
|
-
).
|
73
|
+
).flat_map do |i|
|
74
74
|
{
|
75
75
|
'id' => i['instanceId'],
|
76
76
|
'ip' => i['privateIpAddress'],
|
77
77
|
'state' => i['instanceState'],
|
78
78
|
}
|
79
|
-
end
|
79
|
+
end
|
80
80
|
end
|
81
81
|
|
82
82
|
def get_private_ips
|