marty 1.2.9 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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