marty 5.2.0 → 6.1.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.
- 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
|