marty 1.2.9 → 2.0.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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +11 -9
  3. data/Gemfile.lock +93 -80
  4. data/app/components/marty/data_grid_view.rb +1 -1
  5. data/app/components/marty/main_auth_app.rb +1 -1
  6. data/app/components/marty/mcfly_grid_panel/client/dup_in_form.js +1 -1
  7. data/app/components/marty/posting_grid.rb +1 -1
  8. data/app/components/marty/promise_view.rb +1 -1
  9. data/app/components/marty/simple_app.rb +1 -1
  10. data/app/controllers/marty/application_controller.rb +2 -2
  11. data/app/controllers/marty/diagnostic/controller.rb +1 -5
  12. data/app/models/marty/api_auth.rb +6 -4
  13. data/app/models/marty/config.rb +1 -1
  14. data/app/models/marty/data_grid.rb +13 -13
  15. data/app/models/marty/delorean_rule.rb +2 -2
  16. data/app/models/marty/event.rb +1 -1
  17. data/app/models/marty/import_type.rb +2 -2
  18. data/app/models/marty/name_validator.rb +1 -1
  19. data/app/models/marty/posting.rb +0 -5
  20. data/app/models/marty/user.rb +1 -1
  21. data/app/views/marty/diagnostic/diag.html.erb +0 -2
  22. data/config/routes.rb +2 -2
  23. data/db/migrate/003_create_marty_users.rb +1 -1
  24. data/db/migrate/004_create_marty_roles.rb +1 -1
  25. data/db/migrate/005_create_marty_user_roles.rb +1 -1
  26. data/db/migrate/006_create_marty_tokens.rb +1 -1
  27. data/db/migrate/008_create_marty_posting_types.rb +1 -1
  28. data/db/migrate/068_create_marty_import_types.rb +1 -1
  29. data/db/migrate/069_create_marty_import_synonyms.rb +1 -1
  30. data/db/migrate/070_create_versions.rb +1 -1
  31. data/db/migrate/071_add_object_changes_column_to_versions.rb +1 -1
  32. data/db/migrate/072_add_validation_function_to_import_types.rb +1 -1
  33. data/db/migrate/073_add_preprocess_function_to_import_types.rb +1 -1
  34. data/db/migrate/090_create_delayed_jobs.rb +1 -1
  35. data/db/migrate/091_create_marty_promises.rb +1 -1
  36. data/db/migrate/096_add_user_roles_to_import_types.rb +1 -1
  37. data/db/migrate/097_drop_versions.rb +1 -1
  38. data/db/migrate/099_create_marty_configs.rb +1 -1
  39. data/db/migrate/101_create_marty_grid_index_numranges.rb +1 -1
  40. data/db/migrate/102_create_marty_grid_index_int4ranges.rb +1 -1
  41. data/db/migrate/103_create_marty_grid_index_integers.rb +1 -1
  42. data/db/migrate/104_create_marty_grid_index_strings.rb +1 -1
  43. data/db/migrate/105_create_marty_grid_index_booleans.rb +1 -1
  44. data/db/migrate/106_make_grid_indexes_nullable.rb +1 -1
  45. data/db/migrate/200_create_marty_event_operation_enum.rb +1 -1
  46. data/db/migrate/201_create_marty_events.rb +1 -1
  47. data/db/migrate/202_add_completion_status_to_event.rb +1 -1
  48. data/db/migrate/300_create_marty_api_configs.rb +1 -1
  49. data/db/migrate/301_create_marty_api_log.rb +1 -1
  50. data/db/migrate/302_add_api_configs_validate_result.rb +1 -1
  51. data/db/migrate/303_create_marty_logs.rb +1 -1
  52. data/db/migrate/304_drop_marty_api_logs.rb +1 -1
  53. data/db/migrate/400_create_dg_plv8_v1_fns.rb +1 -1
  54. data/lib/marty/migrations.rb +7 -8
  55. data/lib/marty/monkey.rb +2 -30
  56. data/lib/marty/version.rb +1 -1
  57. data/marty.gemspec +3 -4
  58. data/other/marty/diagnostic/aws/ec2_instance.rb +65 -25
  59. data/other/marty/diagnostic/base.rb +14 -5
  60. data/other/marty/diagnostic/collection.rb +1 -0
  61. data/other/marty/diagnostic/{delayed_job.rb → delayed_job_version.rb} +2 -8
  62. data/other/marty/diagnostic/delayed_job_workers.rb +11 -0
  63. data/other/marty/diagnostic/environment_variables.rb +4 -6
  64. data/other/marty/diagnostic/fatal.rb +0 -5
  65. data/other/marty/diagnostic/node.rb +4 -3
  66. data/other/marty/diagnostic/nodes.rb +46 -13
  67. data/other/marty/diagnostic/packer.rb +22 -25
  68. data/other/marty/diagnostic/version.rb +19 -21
  69. data/script_id, +0 -0
  70. data/spec/controllers/diagnostic/controller_spec.rb +8 -7
  71. data/spec/controllers/job_controller_spec.rb +5 -5
  72. data/spec/controllers/rpc_controller_spec.rb +52 -57
  73. data/spec/controllers/rpc_import_spec.rb +1 -1
  74. data/spec/dummy/config/environments/test.rb +4 -2
  75. data/spec/dummy/db/migrate/20140000000000_create_enums.rb +1 -1
  76. data/spec/dummy/db/migrate/20150406171536_create_categories.rb +2 -2
  77. data/spec/dummy/db/migrate/20150408200916_create_loan_programs.rb +1 -1
  78. data/spec/dummy/db/migrate/20150408201429_create_types.rb +1 -1
  79. data/spec/dummy/db/migrate/20151023000001_create_simple.rb +1 -1
  80. data/spec/dummy/db/migrate/20160100000038_create_gemini_states.rb +1 -1
  81. data/spec/dummy/db/migrate/20160923183516_add_bulk_pricing_event_ops.rb +1 -1
  82. data/spec/dummy/db/migrate/20170706081300_add_state_array_to_lp.rb +1 -1
  83. data/spec/dummy/db/migrate/20170725160000_add_misc_arrays_to_lp.rb +1 -1
  84. data/spec/dummy/db/migrate/20171220150101_add_rule_type_enums.rb +1 -1
  85. data/spec/dummy/db/migrate/20171222150100_add_rule_indices.rb +1 -1
  86. data/spec/features/auth_app_spec.rb +1 -0
  87. data/spec/features/data_import_spec.rb +2 -2
  88. data/spec/features/log_view_spec.rb +4 -4
  89. data/spec/features/reporting_spec.rb +16 -19
  90. data/spec/features/rule_spec.rb +11 -8
  91. data/spec/features/scripting_spec.rb +2 -2
  92. data/spec/features/scripting_test_spec.rb +0 -2
  93. data/spec/features/user_view_spec.rb +4 -6
  94. data/spec/lib/logger_spec.rb +4 -4
  95. data/spec/models/event_spec.rb +4 -4
  96. data/spec/models/promise_spec.rb +1 -1
  97. data/spec/other/diagnostic/base_spec.rb +12 -12
  98. data/spec/other/diagnostic/collection_spec.rb +8 -8
  99. data/spec/other/diagnostic/{delayed_job_spec.rb → delayed_job_version_spec.rb} +4 -4
  100. data/spec/other/diagnostic/delayed_job_workers_spec.rb +44 -0
  101. data/spec/other/diagnostic/reporter_spec.rb +13 -17
  102. data/spec/spec_helper.rb +36 -14
  103. data/spec/support/clean_db_helpers.rb +2 -2
  104. metadata +14 -39
data/lib/marty/monkey.rb CHANGED
@@ -67,7 +67,7 @@ module ActiveRecord
67
67
  super
68
68
  end
69
69
 
70
- def type_cast_for_database(value)
70
+ def deserialize(value)
71
71
  super
72
72
  end
73
73
  end
@@ -76,34 +76,6 @@ module ActiveRecord
76
76
  end
77
77
  end
78
78
 
79
-
80
- module ActiveRecord
81
- module ConnectionAdapters
82
- module PostgreSQL
83
- module OID # :nodoc:
84
- class Array
85
-
86
- # In the 4.2.1 version of this code, under Mutable, the code
87
- # checks for raw_old_value != type_cast_for_database(new_value)
88
- #
89
- # Since this is comparing db (string) version, we end up
90
- # comparing "{1}"!="{1.0}" for float arrays. The following
91
- # is a hack to check the new_value which is the ruby array.
92
- # This could be problematic in other ways. But, works for
93
- # our purposes. FIXME: In Rails 5.0 all this code has been
94
- # changed and this should no longer be an issue.
95
-
96
-
97
- def changed_in_place?(raw_old_value, new_value)
98
- new_value != type_cast_from_database(raw_old_value)
99
- end
100
-
101
- end
102
- end
103
- end
104
- end
105
- end
106
-
107
79
  ######################################################################
108
80
 
109
81
  # Rails 4 doesn't handle 'infinity' datetime properly due to
@@ -249,7 +221,7 @@ module ActiveRecord
249
221
  module PostgreSQL
250
222
  module OID
251
223
  class Enum < Type::Value
252
- def type_cast_from_database(value)
224
+ def cast(value)
253
225
  value && StringEnum.new(value)
254
226
  end
255
227
  end
data/lib/marty/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Marty
2
- VERSION = "1.2.9"
2
+ VERSION = "2.0.0"
3
3
  end
data/marty.gemspec CHANGED
@@ -28,14 +28,13 @@ Gem::Specification.new do |s|
28
28
 
29
29
  s.add_dependency "pg", "~> 0.21"
30
30
 
31
- s.add_dependency 'netzke-core', '~> 1.0.0'
32
- s.add_dependency 'netzke-basepack', '~> 1.0.0'
33
- s.add_development_dependency 'netzke-testing', '~> 1.0.0'
31
+ s.add_dependency 'netzke', '6.5.0.0'
34
32
 
35
33
  s.add_dependency 'axlsx', '3.0.0pre'
36
34
 
35
+
37
36
  s.add_dependency 'delorean_lang', '~> 0.3.33'
38
- s.add_dependency 'mcfly', '0.0.19'
37
+ s.add_dependency 'mcfly', '0.0.20'
39
38
 
40
39
  s.add_dependency 'coderay'
41
40
  # FIXME: for some reason 0.16.1 doesn't work at PennyMac -- investigate
@@ -1,23 +1,53 @@
1
1
  class Marty::Diagnostic::Aws::Ec2Instance
2
- attr_reader :id, :doc, :role, :creds, :version, :host, :tag, :nodes
3
-
4
2
  # aws reserved host used to get instance meta-data
5
3
  META_DATA_HOST = '169.254.169.254'
6
4
 
5
+ attr_reader :id,
6
+ :doc,
7
+ :role,
8
+ :creds,
9
+ :version,
10
+ :host,
11
+ :tag,
12
+ :nodes,
13
+ :instances
14
+
15
+ class InstancesSet
16
+ STATES = [
17
+ :pending, :running, :shutting_down, :terminated, :stopping, :stopped
18
+ ].freeze
19
+
20
+ attr_reader *STATES
21
+
22
+ def get_state instances, state
23
+ instances.map do
24
+ |i|
25
+ i.except('state') if i['state']['name'] == state
26
+ end.compact
27
+ end
28
+
29
+ def initialize instances
30
+ STATES.each do |s|
31
+ instance_variable_set("@#{s}", get_state(instances, s.to_s))
32
+ end
33
+ end
34
+ end
35
+
7
36
  def self.is_aws?
8
37
  response = get("http://#{META_DATA_HOST}") rescue nil
9
38
  response.present?
10
39
  end
11
40
 
12
41
  def initialize
13
- @id = get_instance_id
14
- @doc = get_document
15
- @role = get_role
16
- @creds = get_credentials
17
- @host = "ec2.#{@doc['region']}.amazonaws.com"
18
- @version = '2016-11-15'
19
- @tag = get_tag
20
- @nodes = get_private_ips
42
+ @id = get_instance_id
43
+ @doc = get_document
44
+ @role = get_role
45
+ @creds = get_credentials
46
+ @host = "ec2.#{@doc['region']}.amazonaws.com"
47
+ @version = '2016-11-15'
48
+ @tag = get_tag
49
+ @instances = InstancesSet.new(get_instances)
50
+ @nodes = get_private_ips
21
51
  end
22
52
 
23
53
  def self.get url
@@ -37,6 +67,7 @@ class Marty::Diagnostic::Aws::Ec2Instance
37
67
  self.class.get("http://#{META_DATA_HOST}/latest/dynamic/#{query}/")
38
68
  end
39
69
 
70
+ private
40
71
  def get_instance_id
41
72
  query_meta_data('instance-id').to_s
42
73
  end
@@ -85,25 +116,34 @@ class Marty::Diagnostic::Aws::Ec2Instance
85
116
  def get_instances
86
117
  params = {'Filter.1.Name' => 'tag-value',
87
118
  'Filter.1.Value.1' => @tag}
88
- ec2_request('DescribeInstances', params)
119
+
120
+ instances = ensure_resp(
121
+ ['reservationSet', 'item', 'instancesSet', 'item'],
122
+ ec2_request('DescribeInstances', params)
123
+ ).map do |i|
124
+ {
125
+ 'id' => i['instanceId'],
126
+ 'ip' => i['privateIpAddress'],
127
+ 'state' => i['instanceState'],
128
+ }
129
+ end.flatten(1)
89
130
  end
90
131
 
91
132
  def get_private_ips
92
- begin
93
- reservation_set_item = get_instances['reservationSet']['item']
94
- reservation_set_item = [reservation_set_item] unless
95
- reservation_set_item.is_a?(Array)
133
+ @instances.running.map{|i| i['ip']}.compact
134
+ end
96
135
 
97
- reservation_set_item.map{
98
- |i|
99
- instances_set_item = i['instancesSet']['item']
100
- instances_set_item = [instances_set_item] unless
101
- instances_set_item.is_a?(Array)
102
-
103
- instances_set_item.map{|j| j['privateIpAddress']}
104
- }.flatten
105
- rescue => e
106
- raise "Unexpected result came back from AWS. Error: (#{e.message})"
136
+ def ensure_resp path, obj
137
+ if path == []
138
+ obj.is_a?(Array) ? obj : [obj]
139
+ elsif obj.is_a?(Hash)
140
+ key = path.shift
141
+ raise "Unexpected AWS Response: #{key} missing" unless
142
+ (obj.is_a?(Hash) && obj[key])
143
+
144
+ ensure_resp(path, obj[key])
145
+ else
146
+ obj.map{|s| ensure_resp(path.clone, s)}.flatten(1)
107
147
  end
108
148
  end
109
149
  end
@@ -7,14 +7,23 @@ module Marty::Diagnostic; class Base < Request
7
7
  # should be aggregated as these types of diagnostics are
8
8
  # aggregated differently (or not at all).
9
9
  class_attribute :aggregatable, :status_only
10
- self.aggregatable = true
11
- self.status_only = false
12
10
 
13
11
  @@read_only = Marty::Util.db_in_recovery?
14
12
  @@template = ActionController::Base.new.lookup_context.
15
- find_template("marty/diagnostic/diag").identifier
13
+ find_template("marty/diagnostic/diag").identifier
16
14
 
17
- def self.generate
15
+ def self.diagnostic_fn opts={}
16
+ opts.each do |k,v|
17
+ send("#{k}=", v)
18
+ end
19
+ class << self
20
+ define_method :generate do
21
+ pack{yield}
22
+ end
23
+ end
24
+ end
25
+
26
+ diagnostic_fn aggregatable: true, status_only: false do
18
27
  raise "generate has not been defined for #{name}"
19
28
  end
20
29
 
@@ -52,7 +61,7 @@ module Marty::Diagnostic; class Base < Request
52
61
 
53
62
  def self.display data
54
63
  consistent = consistent?(data)
55
- success = consistent && !fatal?
64
+ success = consistent && !fatal?
56
65
  ERB.new(File.open(@@template).read).result(binding)
57
66
  end
58
67
 
@@ -1,5 +1,6 @@
1
1
  module Marty::Diagnostic; class Collection < Base
2
2
  class_attribute :diagnostics
3
+
3
4
  self.diagnostics = []
4
5
  self.status_only = true
5
6
 
@@ -5,7 +5,7 @@
5
5
  # `DELAYED_VER` environment variable should be set in the
6
6
  # delayed jobs initializer.
7
7
  #
8
- module Marty::Diagnostic; class DelayedJob < Base
8
+ module Marty::Diagnostic; class DelayedJobVersion < Base
9
9
  self.aggregatable = false
10
10
 
11
11
  def self.generate
@@ -14,7 +14,7 @@ module Marty::Diagnostic; class DelayedJob < Base
14
14
  raise 'DELAYED_VER environment variable has not been initialized.' if
15
15
  ENV['DELAYED_VER'].nil?
16
16
 
17
- total_workers = delayed_worker_count
17
+ total_workers = Node.get_target_connections('delayed').count
18
18
 
19
19
  raise 'No delayed jobs are running.' if total_workers.zero?
20
20
 
@@ -40,11 +40,5 @@ module Marty::Diagnostic; class DelayedJob < Base
40
40
  {node => {'Version' => create_info(versions.join("\n"), status)}}
41
41
  }.reduce(:deep_merge)
42
42
  end
43
-
44
- def self.delayed_worker_count
45
- db = Database.db_name
46
- Node.get_postgres_connections[db].
47
- count{|conn| conn['application_name'].include?('delayed_job')}
48
- end
49
43
  end
50
44
  end
@@ -0,0 +1,11 @@
1
+ module Marty::Diagnostic; class DelayedJobWorkers < Base
2
+ diagnostic_fn do
3
+ my_ip = Node.my_ip
4
+ count = Node.get_target_connections('delayed').count{
5
+ |ip|
6
+ (ip == my_ip || ip == '127.0.0.1')
7
+ }
8
+ count.zero? ? error(count) : count
9
+ end
10
+ end
11
+ end
@@ -1,4 +1,8 @@
1
1
  module Marty::Diagnostic; class EnvironmentVariables < Base
2
+ diagnostic_fn do
3
+ env
4
+ end
5
+
2
6
  def self.env filter=''
3
7
  env = ENV.clone
4
8
 
@@ -14,12 +18,6 @@ module Marty::Diagnostic; class EnvironmentVariables < Base
14
18
  h[k] = v if to_block.all?{|b| !k.include?(b)} && k.include?(filter)}
15
19
  end
16
20
 
17
- def self.generate
18
- pack do
19
- env
20
- end
21
- end
22
-
23
21
  # overwritten to only return inconsitent data
24
22
  def self.apply_consistency data
25
23
  diff = get_difference(data)
@@ -1,9 +1,4 @@
1
1
  module Marty::Diagnostic; class Fatal < Base
2
- def self.display_alert_message
3
- '<h3 class="error">Something went wrong.</br>'\
4
- 'Consistency is checked between remaining nodes if applicable.</h3>'
5
- end
6
-
7
2
  def self.message msg, opts = {}
8
3
  node = opts[:node] || Node.my_ip
9
4
  type = opts[:type] || 'RuntimeError'
@@ -24,12 +24,13 @@ module Marty::Diagnostic::Node
24
24
  get_postgres_connections[Marty::Diagnostic::Database.db_name].select{|conn|
25
25
  conn['application_name'].include?(target)
26
26
  }.map{|conn|
27
- conn['client_addr'] == '127.0.0.1' ? my_ip : conn['client_addr']
28
- }.uniq.compact
27
+ conn['client_addr'] == '127.0.0.1' ? my_ip :
28
+ conn['client_addr'] || '127.0.0.1'
29
+ }
29
30
  end
30
31
 
31
32
  def self.get_nodes
32
- nodes = get_target_connections('Passenger')
33
+ nodes = get_target_connections('Passenger').uniq.compact
33
34
  nodes.empty? ? [my_ip] : nodes
34
35
  end
35
36
  end
@@ -1,21 +1,54 @@
1
1
  require_relative 'aws/ec2_instance'
2
2
 
3
3
  module Marty::Diagnostic; class Nodes < Base
4
- def self.generate
5
- pack do
6
- begin
7
- a_nodes = Aws::Ec2Instance.new.nodes.sort if
8
- Aws::Ec2Instance.is_aws?
9
- rescue => e
10
- a_nodes = [e.message]
11
- end
4
+ diagnostic_fn aggregatable: false do
5
+ begin
12
6
  pg_nodes = Node.get_nodes.sort
13
- a_nodes.nil? || pg_nodes == a_nodes ? pg_nodes.join("\n") :
14
- error("There is a discrepancy between nodes connected to "\
15
- "Postgres and those discovered through AWS EC2.\n"\
16
- "Postgres: \n#{pg_nodes.join("\n")}\n"\
17
- "AWS: \n#{a_nodes.join("\n")}")
7
+ rescue => e
8
+ next error(e.message)
18
9
  end
10
+
11
+ next pg_nodes.join("\n") unless
12
+ Marty::Diagnostic::Aws::Ec2Instance.is_aws?
13
+
14
+ begin
15
+ instance_data = Marty::Diagnostic::Aws::Ec2Instance.new
16
+ rescue => e
17
+ next error(pg_nodes.join("\n") +
18
+ "\nAws Communication Error: #{e.message}")
19
+ end
20
+
21
+ begin
22
+ a_nodes = instance_data.nodes.sort
23
+ next pg_nodes.join("\n") if a_nodes == pg_nodes
24
+
25
+ # generate instance information when there is an issue
26
+ # between aws and postgres
27
+ instances = instance_data.instances
28
+ {'nodes' => error("There is a discrepancy between nodes connected to "\
29
+ "Postgres and those discovered through AWS EC2.\n"\
30
+ "Postgres: \n#{pg_nodes.join("\n")}\n"\
31
+ "AWS: \n#{a_nodes.join("\n")}"),
32
+ 'pending' => error_if(instances.pending),
33
+ 'running' => valid_if(instances.running),
34
+ 'shutting_down' => error_if(instances.shutting_down),
35
+ 'terminated' => error_if(instances.terminated),
36
+ 'stopping' => error_if(instances.stopping),
37
+ 'stopped' => error_if(instances.stopped),
38
+ }.delete_if{|k,v| v.empty?}
39
+ rescue => e
40
+ error(e.message)
41
+ end
42
+ end
43
+
44
+ def self.valid_if arr
45
+ return arr.join("\n") unless arr.empty?
46
+ error('---')
47
+ end
48
+
49
+ def self.error_if arr
50
+ return arr if arr.empty?
51
+ error(arr.join("\n"))
19
52
  end
20
53
  end
21
54
  end
@@ -1,36 +1,33 @@
1
1
  module Marty::Diagnostic; module Packer
2
- # expects a block that returns either a String or a Hash value and formats
3
- # it into a diagnostic info object.
4
2
  def pack include_ip=true
5
- begin
6
- data = yield
7
- info = case data
8
- when Hash
9
- is_valid_info?(data) ? {name.demodulize => data} :
10
- data.each_with_object({}) do
11
- |(key, value), hash|
12
- case value
13
- when Hash
14
- raise "Invalid Diagnostic Info #{value}" unless
15
- is_valid_info?(value)
3
+ info = process(yield)
4
+ include_ip ? {Node.my_ip => info} : info
5
+ end
6
+
7
+ def process obj
8
+ obj.is_a?(Hash) ? process_hash(obj) :
9
+ {name.demodulize => create_info(obj.to_s)}
10
+ end
11
+
12
+ def process_hash data
13
+ return {name.demodulize => data} if is_valid_info?(data)
16
14
 
17
- hash[key] = value
18
- else
19
- hash[key] = create_info(value.to_s)
20
- end
21
- end
22
- else
23
- {name.demodulize => create_info(data.to_s)}
24
- end
25
- include_ip ? {Node.my_ip => info} : info
15
+ data.each_with_object({}) do
16
+ |(k, v), h|
17
+ if v.is_a?(Hash)
18
+ raise "Invalid Diagnostic Info #{v}" unless is_valid_info?(v)
19
+ h[k] = v
20
+ else
21
+ h[k] = create_info(v)
22
+ end
26
23
  end
27
24
  end
28
25
 
29
26
  def create_info description, status=true, consistent=nil
30
27
  {
31
- 'description' => description,
32
- 'status' => status,
33
- 'consistent' => consistent
28
+ 'description' => description.to_s,
29
+ 'status' => status,
30
+ 'consistent' => consistent
34
31
  }
35
32
  end
36
33