Module: Moose::Inventory::DB
- Extended by:
- DB, SchemaMigrations
- Included in:
- DB
- Defined in:
- lib/moose_inventory/db/db.rb,
lib/moose_inventory/db/models.rb,
lib/moose_inventory/db/exceptions.rb,
lib/moose_inventory/db/schema_migrations.rb
Overview
Module for DB-related functionality
Defined Under Namespace
Modules: SchemaMigrations
Classes: AuditEvent, Group, Groupvar, Host, Hostvar, MooseDBException, Tag
Constant Summary
collapse
- SCHEMA_VERSION =
SchemaMigrations::SCHEMA_VERSION
- TABLE_DEFINITIONS =
SchemaMigrations::TABLE_DEFINITIONS
- SCHEMA_MIGRATIONS =
SchemaMigrations::SCHEMA_MIGRATIONS
- INDEX_DEFINITIONS =
SchemaMigrations::INDEX_DEFINITIONS
- MODEL_KEYS =
{
host: :Host,
hostvar: :Hostvar,
group: :Group,
groupvar: :Groupvar,
audit_event: :AuditEvent,
tag: :Tag
}.freeze
- BUSY_RETRY_LIMIT =
10
- BUSY_RETRY_BASE_DELAY_SECONDS =
0.05
- BUSY_RETRY_MAX_DELAY_SECONDS =
1.0
Instance Attribute Summary collapse
Class Method Summary
collapse
add_index, apply_schema_indexes!, apply_schema_migration!, clean_duplicate_index_rows!, create_table, create_tables, dedupe_duplicate_rows!, duplicate_keys, index_exists?, migrate_schema!, migration_versions, record_schema_version!, reject_conflicting_duplicates!, reject_future_schema!, schema_indexes_missing?, schema_migration_artifacts_missing?, schema_migration_tables_missing?, schema_version
Instance Attribute Details
#db ⇒ Object
Returns the value of attribute db.
22
23
24
|
# File 'lib/moose_inventory/db/db.rb', line 22
def db
@db
end
|
#exceptions ⇒ Object
Returns the value of attribute exceptions.
22
23
24
|
# File 'lib/moose_inventory/db/db.rb', line 22
def exceptions
@exceptions
end
|
#models ⇒ Object
Returns the value of attribute models.
22
23
24
|
# File 'lib/moose_inventory/db/db.rb', line 22
def models
@models
end
|
Class Method Details
.backup(path) ⇒ Object
155
156
157
158
159
160
161
162
163
164
165
|
# File 'lib/moose_inventory/db/db.rb', line 155
def self.backup(path)
raise @exceptions[:moose], 'Database backup is currently supported for sqlite3 only.' unless sqlite_adapter?
source = sqlite_file
raise @exceptions[:moose], "SQLite database file #{source} does not exist." unless File.exist?(source)
destination = File.expand_path(path)
FileUtils.mkdir_p(File.dirname(destination))
FileUtils.cp(source, destination)
destination
end
|
.bind_models! ⇒ Object
102
103
104
105
106
107
108
|
# File 'lib/moose_inventory/db/db.rb', line 102
def self.bind_models!
Sequel::DATABASES[0] = @db
require_relative 'models'
@models = MODEL_KEYS.transform_values do |name|
Moose::Inventory::DB.const_get(name)
end
end
|
.busy_database_error?(error) ⇒ Boolean
110
111
112
|
# File 'lib/moose_inventory/db/db.rb', line 110
def self.busy_database_error?(error)
error.message.include?('BusyException')
end
|
.busy_retry_delay(tries) ⇒ Object
.config_db_settings ⇒ Object
.connect ⇒ Object
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
# File 'lib/moose_inventory/db/db.rb', line 204
def self.connect
return unless @db.nil?
case normalized_adapter
when 'sqlite3'
init_sqlite3
when 'mysql'
init_mysql
when 'postgresql'
init_postgresql
else
raise @exceptions[:moose],
"database adapter #{normalized_adapter} is not yet supported."
end
end
|
.db_password(config, adapter) ⇒ Object
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
|
# File 'lib/moose_inventory/db/db.rb', line 285
def self.db_password(config, adapter)
return config[:password] unless config[:password].nil?
if config[:password_env].nil?
raise @exceptions[:moose],
"Expected key password or password_env missing in #{adapter} configuration"
end
password = ENV.fetch(config[:password_env].to_s, nil)
if password.nil? || password.empty?
raise @exceptions[:moose],
"Environment variable #{config[:password_env]} is not set for #{adapter} password"
end
password
end
|
.ensure_required_config_keys!(config, keys, adapter) ⇒ Object
275
276
277
278
279
280
281
282
|
# File 'lib/moose_inventory/db/db.rb', line 275
def self.ensure_required_config_keys!(config, keys, adapter)
keys.each do |key|
next unless config[key].nil?
raise @exceptions[:moose],
"Expected key #{key} missing in #{adapter} configuration"
end
end
|
.init ⇒ Object
45
46
47
48
49
50
51
52
53
|
# File 'lib/moose_inventory/db/db.rb', line 45
def self.init
init_exceptions
return unless @db.nil?
Sequel::Model.plugin :json_serializer
connect
migrate_schema!
bind_models!
end
|
.init_exceptions ⇒ Object
62
63
64
65
|
# File 'lib/moose_inventory/db/db.rb', line 62
def self.init_exceptions
@exceptions ||= {}
@exceptions[:moose] ||= Moose::Inventory::DB::MooseDBException
end
|
.init_mysql ⇒ Object
246
247
248
249
250
251
252
253
254
255
256
257
258
|
# File 'lib/moose_inventory/db/db.rb', line 246
def self.init_mysql
require 'mysql2'
init_exceptions
config = config_db_settings
ensure_required_config_keys!(config, %i[host database user], 'mysql')
password = db_password(config, 'mysql')
@db = Sequel.mysql2(user: config[:user],
password: password,
host: config[:host],
database: config[:database])
end
|
.init_postgresql ⇒ Object
261
262
263
264
265
266
267
268
269
270
271
272
273
|
# File 'lib/moose_inventory/db/db.rb', line 261
def self.init_postgresql
require 'pg'
init_exceptions
config = config_db_settings
ensure_required_config_keys!(config, %i[host database user], 'postgresql')
password = db_password(config, 'postgresql')
@db = Sequel.postgres(user: config[:user],
password: password,
host: config[:host],
database: config[:database])
end
|
.init_sqlite3 ⇒ Object
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
# File 'lib/moose_inventory/db/db.rb', line 229
def self.init_sqlite3
require 'sqlite3'
require 'fileutils'
init_exceptions
config = config_db_settings
ensure_required_config_keys!(config, [:file], 'sqlite3')
raise("SQLite3 DB 'file' cannot be empty") if config[:file].empty?
dbfile = File.expand_path(config[:file])
dbdir = File.dirname(dbfile)
FileUtils.mkdir_p(dbdir)
@db = Sequel.sqlite(dbfile)
end
|
.migrate! ⇒ Object
150
151
152
153
|
# File 'lib/moose_inventory/db/db.rb', line 150
def self.migrate!
migrate_schema!
status
end
|
.normalized_adapter ⇒ Object
224
225
226
|
# File 'lib/moose_inventory/db/db.rb', line 224
def self.normalized_adapter
config_db_settings[:adapter].downcase
end
|
.purge ⇒ Object
132
133
134
135
136
137
138
|
# File 'lib/moose_inventory/db/db.rb', line 132
def self.purge
return purge_sqlite_associations if sqlite_adapter?
@db.drop_table(:hosts, :hostvars,
:groups, :groupvars, :group_hosts,
if_exists: true, cascade: true)
end
|
.purge_sqlite_associations ⇒ Object
175
176
177
178
179
180
181
182
|
# File 'lib/moose_inventory/db/db.rb', line 175
def self.purge_sqlite_associations
purge_sqlite_groups
purge_sqlite_hosts
Groupvar.all.each(&:destroy)
Hostvar.all.each(&:destroy)
AuditEvent.all.each(&:destroy) if @db.table_exists?(:audit_events)
Tag.all.each(&:destroy) if @db.table_exists?(:tags)
end
|
.purge_sqlite_groups ⇒ Object
184
185
186
187
188
189
190
191
192
|
# File 'lib/moose_inventory/db/db.rb', line 184
def self.purge_sqlite_groups
Group.all.each do |group|
group.remove_all_hosts
group.remove_all_groupvars
group.remove_all_children
group.remove_all_tags if @db.table_exists?(:groups_tags)
group.destroy
end
end
|
.purge_sqlite_hosts ⇒ Object
194
195
196
197
198
199
200
201
|
# File 'lib/moose_inventory/db/db.rb', line 194
def self.purge_sqlite_hosts
Host.all.each do |host|
host.remove_all_groups
host.remove_all_hostvars
host.remove_all_tags if @db.table_exists?(:hosts_tags)
host.destroy
end
end
|
.reset ⇒ Object
93
94
95
96
97
98
|
# File 'lib/moose_inventory/db/db.rb', line 93
def self.reset
raise('Database connection has not been established') if @db.nil?
purge
migrate_schema!
end
|
.reset_runtime_state ⇒ Object
55
56
57
58
59
|
# File 'lib/moose_inventory/db/db.rb', line 55
def self.reset_runtime_state
@db = nil
@models = nil
@exceptions = nil
end
|
.retry_busy_transaction(error, tries, sleeper: method(:sleep)) ⇒ Object
119
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/moose_inventory/db/db.rb', line 119
def self.retry_busy_transaction(error, tries, sleeper: method(:sleep))
if tries <= BUSY_RETRY_LIMIT
warn error.message if Moose::Inventory::Config.trace_enabled?
sleeper.call(busy_retry_delay(tries))
return
end
warn('The database appears to be locked by another process, and ' \
"did not become free after #{tries} tries. Giving up. ")
raise error
end
|
.sqlite_adapter? ⇒ Boolean
167
168
169
|
# File 'lib/moose_inventory/db/db.rb', line 167
def self.sqlite_adapter?
normalized_adapter == 'sqlite3'
end
|
.sqlite_file ⇒ Object
171
172
173
|
# File 'lib/moose_inventory/db/db.rb', line 171
def self.sqlite_file
File.expand_path(config_db_settings[:file])
end
|
.status ⇒ Object
140
141
142
143
144
145
146
147
148
|
# File 'lib/moose_inventory/db/db.rb', line 140
def self.status
{
adapter: normalized_adapter,
schema_version: schema_version,
expected_schema_version: SCHEMA_VERSION,
tables: TABLE_DEFINITIONS.keys.to_h { |name| [name, @db.table_exists?(name)] },
sqlite_file: sqlite_adapter? ? sqlite_file : nil
}
end
|
.transaction ⇒ Object
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
# File 'lib/moose_inventory/db/db.rb', line 68
def self.transaction(&)
raise('Database connection has not been established') if @db.nil?
tries = 0
begin
@db.transaction(savepoint: true, &)
rescue Sequel::DatabaseError => e
raise unless busy_database_error?(e)
tries += 1
retry_busy_transaction(e, tries)
retry
rescue @exceptions[:moose] => e
warn 'An error occurred during a transaction, any changes have been rolled back.'
warn e.full_message(highlight: false, order: :top) if Moose::Inventory::Config.trace_enabled?
abort("ERROR: #{e.message}")
rescue SystemExit, StandardError
warn 'An error occurred during a transaction, any changes have been rolled back.'
raise
end
end
|