forked from ManageIQ/manageiq
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevm_database.rb
185 lines (151 loc) · 5.19 KB
/
evm_database.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
class EvmDatabase
include Vmdb::Logging
SCHEMA_FILE = Rails.root.join("db/schema.yml").freeze
PRIMORDIAL_CLASSES = %w(
MiqDatabase
MiqRegion
MiqEnterprise
Zone
MiqServer
ServerRole
Tenant
MiqProductFeature
MiqUserRole
MiqGroup
User
MiqReport
VmdbDatabase
)
ORDERED_CLASSES = %w(
RssFeed
MiqWidget
MiqAction
MiqEventDefinition
MiqPolicySet
)
RAILS_ENGINE_MODEL_CLASS_NAMES = %w(MiqAeDatastore)
def self.find_seedable_model_class_names
@found_model_class_names ||= begin
Dir.glob(Rails.root.join("app/models/*.rb")).collect { |f| File.basename(f, ".*").camelize if File.read(f).include?("self.seed") }.compact.sort
end
end
def self.seedable_model_class_names
ORDERED_CLASSES + (find_seedable_model_class_names - ORDERED_CLASSES) + RAILS_ENGINE_MODEL_CLASS_NAMES
end
def self.seed_primordial
if ENV['SKIP_PRIMORDIAL_SEED'] && MiqDatabase.count > 0
puts "** Primordial seedings is skipped."
puts "** Unset SKIP_PRIMORDIAL_SEED to re-enable"
else
seed(PRIMORDIAL_CLASSES)
end
end
def self.seed_last
seed(seedable_model_class_names - PRIMORDIAL_CLASSES)
end
def self.seed(classes = nil, exclude_list = [])
_log.info("Seeding...")
classes ||= PRIMORDIAL_CLASSES + (seedable_model_class_names - PRIMORDIAL_CLASSES)
classes -= exclude_list
# Only 1 machine can go through this at a time
# Populating the DB takes 20 seconds
# Not populating the db takes 3 seconds
MiqDatabase.with_lock(10.minutes) do
classes.each do |klass|
begin
klass = klass.constantize if klass.kind_of?(String)
rescue => err
_log.log_backtrace(err)
raise
end
if klass.respond_to?(:seed)
_log.info("Seeding #{klass}")
begin
klass.seed
rescue => err
_log.log_backtrace(err)
raise
end
else
_log.error("Class #{klass} does not have a seed")
end
end
end
_log.info("Seeding... Complete")
end
def self.host
Rails.configuration.database_configuration[Rails.env]['host']
end
def self.local?
host.blank? || ["localhost", "localhost.localdomain", "127.0.0.1", "0.0.0.0"].include?(host)
end
# Determines the average time to the database in milliseconds
def self.ping(connection = ApplicationRecord.connection)
query = "SELECT 1"
Benchmark.realtime { 10.times { connection.select_value(query) } } / 10 * 1000
end
# Determines if the schema currently being used is the same as the one we expect
#
# @param connection Check the database at this connection against the local file
# @return nil if the schemas match, an error message otherwise
def self.check_schema(connection = ActiveRecord::Base.connection)
check_schema_tables(connection) || check_schema_columns(connection)
end
# Writes the schema to SCHEMA_FILE as it currently exists in the database
#
# @param connection Write the schema at this connection to the file
def self.write_expected_schema(connection = ActiveRecord::Base.connection)
File.write(SCHEMA_FILE, current_schema(connection).to_yaml)
end
class << self
private
def expected_schema
YAML.load_file(SCHEMA_FILE)
end
def current_schema(connection)
connection.tables.sort.each_with_object({}) do |t, h|
h[t] = connection.columns(t).map(&:name)
end
end
def check_schema_columns(connection)
compare_schema = current_schema(connection)
errors = []
expected_schema.each do |table, expected_columns|
next if compare_schema[table] == expected_columns
errors << <<-ERROR.gsub!(/^ +/, "")
Schema validation failed for host #{db_connection_host(connection)}:
Columns for table #{table} in the current schema do not match the columns listed in #{SCHEMA_FILE}
expected:
#{expected_columns.inspect}
got:
#{compare_schema[table].inspect}
ERROR
end
errors.empty? ? nil : errors.join("\n")
end
def check_schema_tables(connection)
current_tables = current_schema(connection).keys
expected_tables = expected_schema.keys
return if current_tables == expected_tables
diff_in_current = current_tables - expected_tables
diff_in_expected = expected_tables - current_tables
if diff_in_current.empty? && diff_in_expected.empty?
<<-ERROR.gsub!(/^ +/, "")
Schema validation failed for host #{db_connection_host(connection)}:
Expected schema table order does not match sorted current tables.
Use 'rake evm:db:write_schema' to generate the new expected schema when making changes.
ERROR
else
<<-ERROR.gsub!(/^ +/, "")
Schema validation failed for host #{db_connection_host(connection)}:
Current schema tables do not match expected
Additional tables in current schema: #{diff_in_current}
Missing tables in current schema: #{diff_in_expected}
ERROR
end
end
def db_connection_host(connection)
connection.raw_connection.conninfo_hash[:host] || "localhost"
end
end
end