moose-inventory 0.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 +7 -0
- data/.coveralls.yml +0 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +793 -0
- data/Gemfile +3 -0
- data/Guardfile +38 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/README.md.orig +35 -0
- data/Rakefile +1 -0
- data/bin/moose_inventory +10 -0
- data/config/dotfiles/coveralls.yml +0 -0
- data/config/dotfiles/gitignore +17 -0
- data/config/dotfiles/rubocop.yml +793 -0
- data/lib/moose/inventory/cli/application.rb +30 -0
- data/lib/moose/inventory/cli/formatter.rb +92 -0
- data/lib/moose/inventory/cli/group.rb +23 -0
- data/lib/moose/inventory/cli/group_add.rb +98 -0
- data/lib/moose/inventory/cli/group_addchild.rb +21 -0
- data/lib/moose/inventory/cli/group_addhost.rb +97 -0
- data/lib/moose/inventory/cli/group_addvar.rb +72 -0
- data/lib/moose/inventory/cli/group_get.rb +52 -0
- data/lib/moose/inventory/cli/group_list.rb +41 -0
- data/lib/moose/inventory/cli/group_rm.rb +77 -0
- data/lib/moose/inventory/cli/group_rmchild.rb +20 -0
- data/lib/moose/inventory/cli/group_rmhost.rb +89 -0
- data/lib/moose/inventory/cli/group_rmvar.rb +65 -0
- data/lib/moose/inventory/cli/host.rb +24 -0
- data/lib/moose/inventory/cli/host_add.rb +93 -0
- data/lib/moose/inventory/cli/host_addgroup.rb +88 -0
- data/lib/moose/inventory/cli/host_addvar.rb +76 -0
- data/lib/moose/inventory/cli/host_get.rb +59 -0
- data/lib/moose/inventory/cli/host_list.rb +40 -0
- data/lib/moose/inventory/cli/host_rm.rb +62 -0
- data/lib/moose/inventory/cli/host_rmgroup.rb +80 -0
- data/lib/moose/inventory/cli/host_rmvar.rb +69 -0
- data/lib/moose/inventory/config/config.rb +169 -0
- data/lib/moose/inventory/db/db.rb +249 -0
- data/lib/moose/inventory/db/exceptions.rb +14 -0
- data/lib/moose/inventory/db/models.rb +32 -0
- data/lib/moose/inventory/moose_inventory_cli.rb +25 -0
- data/lib/moose/inventory/version.rb +7 -0
- data/moose-inventory.gemspec +45 -0
- data/scripts/guard_quality.sh +3 -0
- data/scripts/guard_test.sh +2 -0
- data/scripts/reports.sh +4 -0
- data/spec/config/config.yml +12 -0
- data/spec/lib/moose/inventory/cli/application_spec.rb +15 -0
- data/spec/lib/moose/inventory/cli/cli_spec.rb +26 -0
- data/spec/lib/moose/inventory/cli/formatter_spec.rb +63 -0
- data/spec/lib/moose/inventory/cli/group_add_spec.rb +398 -0
- data/spec/lib/moose/inventory/cli/group_addhost_spec.rb +251 -0
- data/spec/lib/moose/inventory/cli/group_addvar_spec.rb +235 -0
- data/spec/lib/moose/inventory/cli/group_get_spec.rb +107 -0
- data/spec/lib/moose/inventory/cli/group_list_spec.rb +79 -0
- data/spec/lib/moose/inventory/cli/group_rm_spec.rb +191 -0
- data/spec/lib/moose/inventory/cli/group_rmhost_spec.rb +215 -0
- data/spec/lib/moose/inventory/cli/group_rmvar_spec.rb +202 -0
- data/spec/lib/moose/inventory/cli/group_spec.rb +15 -0
- data/spec/lib/moose/inventory/cli/host_add_spec.rb +330 -0
- data/spec/lib/moose/inventory/cli/host_addgroup_spec.rb +248 -0
- data/spec/lib/moose/inventory/cli/host_addvar_spec.rb +233 -0
- data/spec/lib/moose/inventory/cli/host_get_spec.rb +106 -0
- data/spec/lib/moose/inventory/cli/host_list_spec.rb +83 -0
- data/spec/lib/moose/inventory/cli/host_rm_spec.rb +132 -0
- data/spec/lib/moose/inventory/cli/host_rmgroup_spec.rb +245 -0
- data/spec/lib/moose/inventory/cli/host_rmvar_spec.rb +206 -0
- data/spec/lib/moose/inventory/cli/host_spec.rb +12 -0
- data/spec/lib/moose/inventory/config/config_spec.rb +80 -0
- data/spec/lib/moose/inventory/db/db_spec.rb +184 -0
- data/spec/lib/moose/inventory/db/models_spec.rb +150 -0
- data/spec/shared/shared_config_setup.rb +21 -0
- data/spec/spec_helper.rb +110 -0
- metadata +386 -0
@@ -0,0 +1,249 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require_relative './exceptions.rb'
|
5
|
+
|
6
|
+
module Moose
|
7
|
+
module Inventory
|
8
|
+
##
|
9
|
+
# Module for DB-related functionality
|
10
|
+
module DB
|
11
|
+
# rubocop:disable Style/ModuleFunction
|
12
|
+
extend self
|
13
|
+
# rubocop:enable Style/ModuleFunction
|
14
|
+
|
15
|
+
@db = nil
|
16
|
+
@models = nil
|
17
|
+
@exceptions = nil
|
18
|
+
|
19
|
+
attr_reader :db
|
20
|
+
attr_reader :models
|
21
|
+
attr_reader :exceptions
|
22
|
+
|
23
|
+
#----------------------
|
24
|
+
def self.init
|
25
|
+
# If we allow init more than once, then the db connection is remade,
|
26
|
+
# which changes Sequel:DATABASES[0], thereby invalidating the sequel
|
27
|
+
# models. This causes unexpected behavour. That is to say, because
|
28
|
+
# of the way Sequel initializes models, this method is not idempotent.
|
29
|
+
# In our single-shot application, this shouldn't be a problem. However,
|
30
|
+
# our unit tests like to call init multiple times, which borks things.
|
31
|
+
# So, we allow init only once, gated by whether @db is nil. In effect,
|
32
|
+
# this means we pool the DB connection for the life of the application.
|
33
|
+
# Again, not a problem for our one-shot app, but it may be an issue in
|
34
|
+
# long-running code. Personally, I don't like this pooling regime -
|
35
|
+
# perhaps I'm not understanding how it's supposed to be used?
|
36
|
+
#
|
37
|
+
# TODO: can the models be refreshed, to make then again valid? What if
|
38
|
+
# we "load" instead of "require" the models?
|
39
|
+
# UPDATE: Nope, still borks even if we use a load.
|
40
|
+
#
|
41
|
+
# @db = nil # <- fails for unit tests
|
42
|
+
return unless @db.nil? # <- works for unit tests
|
43
|
+
|
44
|
+
Sequel::Model.plugin :json_serializer
|
45
|
+
connect
|
46
|
+
create_tables
|
47
|
+
|
48
|
+
# Make our models work
|
49
|
+
Sequel::DATABASES[0] = @db
|
50
|
+
require_relative 'models'
|
51
|
+
# load( load_dir = File.join(File.dirname(__FILE__), "models.rb") )
|
52
|
+
|
53
|
+
# For convenience
|
54
|
+
@models = {}
|
55
|
+
@models[:host] = Moose::Inventory::DB::Host
|
56
|
+
@models[:hostvar] = Moose::Inventory::DB::Hostvar
|
57
|
+
@models[:group] = Moose::Inventory::DB::Group
|
58
|
+
@models[:groupvar] = Moose::Inventory::DB::Groupvar
|
59
|
+
|
60
|
+
@exceptions = {}
|
61
|
+
@exceptions[:moose] = Moose::Inventory::DB::MooseDBException
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
#--------------------
|
66
|
+
def self.transaction
|
67
|
+
fail('Database connection has not been established') if @db.nil?
|
68
|
+
begin
|
69
|
+
@db.transaction(savepoint: true) do
|
70
|
+
yield
|
71
|
+
end
|
72
|
+
|
73
|
+
rescue @exceptions[:moose] => e
|
74
|
+
warn 'An error occurred during a transaction, any changes have been rolled back.'
|
75
|
+
|
76
|
+
if Moose::Inventory::Config._confopts[:trace] == true
|
77
|
+
abort("ERROR: #{e}")
|
78
|
+
else
|
79
|
+
abort("ERROR: #{e.message}")
|
80
|
+
end
|
81
|
+
|
82
|
+
rescue Exception => e
|
83
|
+
warn 'An error occurred during a transaction, any changes have been rolled back.'
|
84
|
+
raise e
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
#--------------------
|
89
|
+
def self.reset
|
90
|
+
fail('Database connection has not been established') if @db.nil?
|
91
|
+
# @debug << 'reset'
|
92
|
+
purge
|
93
|
+
create_tables
|
94
|
+
end
|
95
|
+
|
96
|
+
#===============================
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
#--------------------
|
101
|
+
def self.purge # rubocop:disable Metrics/AbcSize
|
102
|
+
adapter = Moose::Inventory::Config._settings[:config][:db][:adapter]
|
103
|
+
adapter.downcase!
|
104
|
+
|
105
|
+
if adapter == 'sqlite3'
|
106
|
+
# HACK: SQLite3 supposedly supports CASCADE, see
|
107
|
+
# https://www.sqlite.org/foreignkeys.html#fk_actions
|
108
|
+
# However, when we do a drop_table with :cascade=>true
|
109
|
+
# on an sqlite3 database, it throws errors regarding
|
110
|
+
# foreign keys constraints. Instead, the following is
|
111
|
+
# less efficient, but does work.
|
112
|
+
|
113
|
+
Group.all.each do |g|
|
114
|
+
g.remove_all_hosts
|
115
|
+
g.remove_all_groupvars
|
116
|
+
g.destroy
|
117
|
+
end
|
118
|
+
|
119
|
+
Host.all.each do |h|
|
120
|
+
h.remove_all_groups
|
121
|
+
h.remove_all_hostvars
|
122
|
+
h.destroy
|
123
|
+
end
|
124
|
+
|
125
|
+
Groupvar.all.each(&:destroy)
|
126
|
+
Hostvar.all.each(&:destroy)
|
127
|
+
|
128
|
+
else
|
129
|
+
@db.drop_table(:hosts, :hostvars,
|
130
|
+
:groups, :groupvars, :group_hosts,
|
131
|
+
if_exists: true, cascade: true)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
#--------------------
|
136
|
+
def self.create_tables # rubocop:disable Metrics/AbcSize
|
137
|
+
unless @db.table_exists? :hosts
|
138
|
+
@db.create_table(:hosts) do
|
139
|
+
primary_key :id
|
140
|
+
column :name, :text, unique: true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
unless @db.table_exists? :hostvars
|
145
|
+
@db.create_table(:hostvars) do
|
146
|
+
primary_key :id
|
147
|
+
foreign_key :host_id
|
148
|
+
column :name, :text
|
149
|
+
column :value, :text
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
unless @db.table_exists? :groups
|
154
|
+
@db.create_table(:groups) do
|
155
|
+
primary_key :id
|
156
|
+
column :name, :text, unique: true
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
unless @db.table_exists? :groupvars
|
161
|
+
@db.create_table(:groupvars) do
|
162
|
+
primary_key :id
|
163
|
+
foreign_key :group_id
|
164
|
+
column :name, :text
|
165
|
+
column :value, :text
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
unless @db.table_exists? :groups_hosts
|
170
|
+
@db.create_table(:groups_hosts) do
|
171
|
+
primary_key :id
|
172
|
+
foreign_key :host_id, :hosts
|
173
|
+
foreign_key :group_id, :groups
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#--------------------
|
179
|
+
def self.connect
|
180
|
+
return unless @db.nil?
|
181
|
+
|
182
|
+
adapter = Moose::Inventory::Config._settings[:config][:db][:adapter]
|
183
|
+
adapter.downcase!
|
184
|
+
|
185
|
+
case adapter
|
186
|
+
when 'sqlite3'
|
187
|
+
init_sqlite3
|
188
|
+
|
189
|
+
when 'msqsql'
|
190
|
+
init_mysql
|
191
|
+
|
192
|
+
when 'postgresql'
|
193
|
+
init_postgresql
|
194
|
+
|
195
|
+
else
|
196
|
+
fail @exceptions[:moose ],
|
197
|
+
"database adapter #{adapter} is not yet supported."
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
#--------------------
|
202
|
+
def self.init_sqlite3 # rubocop:disable Metrics/AbcSize
|
203
|
+
require 'sqlite3'
|
204
|
+
|
205
|
+
# Quick check that expected keys are at least present & sensible
|
206
|
+
config = Moose::Inventory::Config._settings[:config][:db]
|
207
|
+
[:file].each do |key|
|
208
|
+
if config[key].nil?
|
209
|
+
fail @exceptions[:moose ],
|
210
|
+
"Expected key #{key} missing in sqlite3 configuration"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
config[:file].empty? && fail("SQLite3 DB 'file' cannot be empty")
|
214
|
+
|
215
|
+
# Make sure the directory exists
|
216
|
+
dbfile = File.expand_path(config[:file])
|
217
|
+
dbdir = File.dirname(dbfile)
|
218
|
+
Dir.mkdir(dbdir) unless Dir.exist?(dbdir)
|
219
|
+
|
220
|
+
# Create and/or open the database file
|
221
|
+
@db = Sequel.sqlite(dbfile)
|
222
|
+
end
|
223
|
+
|
224
|
+
#--------------------
|
225
|
+
def self.init_mysql
|
226
|
+
require 'mysql'
|
227
|
+
|
228
|
+
# TODO: native MySQL driver vs the pure ruby one?
|
229
|
+
# Sequel requires the native on.
|
230
|
+
# gem('mysql')
|
231
|
+
|
232
|
+
# Quick check that expected keys are at least present
|
233
|
+
config = Moose::Inventory::Config._settings[:config][:db]
|
234
|
+
[:host, :database, :user, :password].each do |key|
|
235
|
+
if config[key].nil?
|
236
|
+
fail @exceptions[:moose ],
|
237
|
+
"Expected key #{key} missing in mysql configuration"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
@db = Sequel.mysql(user: config[:user],
|
242
|
+
password: config[:password],
|
243
|
+
host: config[:host],
|
244
|
+
database: config[:database]
|
245
|
+
)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Moose
|
2
|
+
module Inventory
|
3
|
+
module DB
|
4
|
+
##
|
5
|
+
# This class provides a Moose-specific db exception error
|
6
|
+
class MooseDBException < RuntimeError
|
7
|
+
attr_reader :message
|
8
|
+
def initialize(message)
|
9
|
+
@message = message || 'An undefined Moose exception occurred'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Moose
|
2
|
+
module Inventory
|
3
|
+
module DB
|
4
|
+
##
|
5
|
+
# Model for the hosts table
|
6
|
+
class Host < Sequel::Model
|
7
|
+
many_to_many :groups
|
8
|
+
one_to_many :hostvars
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Model for the groups table
|
13
|
+
class Group < Sequel::Model
|
14
|
+
# TODO: Groups of groups? (i.e. a group with children?)
|
15
|
+
many_to_many :hosts
|
16
|
+
one_to_many :groupvars
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Model for the hostvars table
|
21
|
+
class Hostvar < Sequel::Model
|
22
|
+
many_to_one :hosts
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Model for the groupvars table
|
27
|
+
class Groupvar < Sequel::Model
|
28
|
+
many_to_one :groups
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require_relative './config/config.rb'
|
3
|
+
require_relative './db/db.rb'
|
4
|
+
require_relative './cli/application.rb'
|
5
|
+
|
6
|
+
module Moose
|
7
|
+
module Inventory
|
8
|
+
##
|
9
|
+
# Module implementing the CLI for moose-inventory
|
10
|
+
module Cli
|
11
|
+
# rubocop:disable Style/ModuleFunction
|
12
|
+
extend self
|
13
|
+
# rubocop:enable Style/ModuleFunction
|
14
|
+
|
15
|
+
def start(args)
|
16
|
+
# initialization stuff.
|
17
|
+
Moose::Inventory::Config.init(args)
|
18
|
+
Moose::Inventory::DB.init
|
19
|
+
|
20
|
+
# Start the main application
|
21
|
+
Moose::Inventory::Cli::Application.start(Moose::Inventory::Config._argv)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
lib = File.expand_path('../lib', __FILE__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'moose/inventory/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'moose-inventory'
|
10
|
+
spec.version = Moose::Inventory::VERSION
|
11
|
+
spec.authors = ['Russell Davies']
|
12
|
+
spec.email = ['russell@blakemere.ca']
|
13
|
+
spec.summary = 'Moose-tools inventory manager'
|
14
|
+
# rubocop:disable Metrics/LineLength
|
15
|
+
spec.description = 'The Moosecastle CLI tool for Ansible-compatable dynamic inventory management.'
|
16
|
+
# rubocop:enable Metrics/LineLength
|
17
|
+
spec.homepage = 'http://www.blakemere.ca'
|
18
|
+
spec.license = 'MIT'
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0")
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_runtime_dependency 'indentation', '~> 0.1'
|
26
|
+
spec.add_runtime_dependency 'json', '~>1.8'
|
27
|
+
spec.add_runtime_dependency 'mysql', '~>2.9'
|
28
|
+
# spec.add_runtime_dependency 'mysql2', '~>0.3'
|
29
|
+
spec.add_runtime_dependency 'pg', '~>0.17'
|
30
|
+
spec.add_runtime_dependency 'sequel', '~>4.22'
|
31
|
+
spec.add_runtime_dependency 'sqlite3', '~>1.3'
|
32
|
+
spec.add_runtime_dependency 'thor', '~>0.19'
|
33
|
+
# spec.add_runtime_dependency 'yaml', '~>1.0'
|
34
|
+
|
35
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
36
|
+
spec.add_development_dependency 'coveralls', '~> 0.8'
|
37
|
+
spec.add_development_dependency 'hitimes', '~> 1.2'
|
38
|
+
spec.add_development_dependency 'guard', '~> 2.12'
|
39
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.5'
|
40
|
+
spec.add_development_dependency 'guard-rubocop', '~> 1.2'
|
41
|
+
spec.add_development_dependency 'rake', '~> 10.1'
|
42
|
+
spec.add_development_dependency 'rspec', '~>3.2'
|
43
|
+
spec.add_development_dependency 'rubocop', '>= 0.19'
|
44
|
+
spec.add_development_dependency 'simplecov', '~> 0.10'
|
45
|
+
end
|
data/scripts/reports.sh
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# require 'spec_helper'
|
2
|
+
#
|
3
|
+
# RSpec.describe Moose::Inventory::Cli::Group do
|
4
|
+
# before do
|
5
|
+
# # Set up the configuration object
|
6
|
+
# mockargs = "--format yaml --env testing --config ./test.config"
|
7
|
+
# Moose::Inventory::Config
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# describe ".add" do
|
11
|
+
# it '"add test" should add a group called test' do
|
12
|
+
# expect(["group","add","test").to_eq(2)
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
# end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Moose::Inventory::Cli::Application do
|
4
|
+
before do
|
5
|
+
@app = Moose::Inventory::Cli::Application
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ".version" do
|
9
|
+
# --------------------
|
10
|
+
it 'method should be responsive' do
|
11
|
+
result = @app.instance_methods(false).include?(:version)
|
12
|
+
expect(result).to eq(true)
|
13
|
+
end
|
14
|
+
|
15
|
+
# --------------------
|
16
|
+
# it 'should output version information' do
|
17
|
+
# actual = runner { @app.version }
|
18
|
+
#
|
19
|
+
# desired = {}
|
20
|
+
# desired[:STDERR] = "Version #{Moose::Inventory::VERSION}"
|
21
|
+
#
|
22
|
+
# expected(actual, desired)
|
23
|
+
# end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|