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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +0 -0
  3. data/.gitignore +17 -0
  4. data/.rubocop.yml +793 -0
  5. data/Gemfile +3 -0
  6. data/Guardfile +38 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +31 -0
  9. data/README.md.orig +35 -0
  10. data/Rakefile +1 -0
  11. data/bin/moose_inventory +10 -0
  12. data/config/dotfiles/coveralls.yml +0 -0
  13. data/config/dotfiles/gitignore +17 -0
  14. data/config/dotfiles/rubocop.yml +793 -0
  15. data/lib/moose/inventory/cli/application.rb +30 -0
  16. data/lib/moose/inventory/cli/formatter.rb +92 -0
  17. data/lib/moose/inventory/cli/group.rb +23 -0
  18. data/lib/moose/inventory/cli/group_add.rb +98 -0
  19. data/lib/moose/inventory/cli/group_addchild.rb +21 -0
  20. data/lib/moose/inventory/cli/group_addhost.rb +97 -0
  21. data/lib/moose/inventory/cli/group_addvar.rb +72 -0
  22. data/lib/moose/inventory/cli/group_get.rb +52 -0
  23. data/lib/moose/inventory/cli/group_list.rb +41 -0
  24. data/lib/moose/inventory/cli/group_rm.rb +77 -0
  25. data/lib/moose/inventory/cli/group_rmchild.rb +20 -0
  26. data/lib/moose/inventory/cli/group_rmhost.rb +89 -0
  27. data/lib/moose/inventory/cli/group_rmvar.rb +65 -0
  28. data/lib/moose/inventory/cli/host.rb +24 -0
  29. data/lib/moose/inventory/cli/host_add.rb +93 -0
  30. data/lib/moose/inventory/cli/host_addgroup.rb +88 -0
  31. data/lib/moose/inventory/cli/host_addvar.rb +76 -0
  32. data/lib/moose/inventory/cli/host_get.rb +59 -0
  33. data/lib/moose/inventory/cli/host_list.rb +40 -0
  34. data/lib/moose/inventory/cli/host_rm.rb +62 -0
  35. data/lib/moose/inventory/cli/host_rmgroup.rb +80 -0
  36. data/lib/moose/inventory/cli/host_rmvar.rb +69 -0
  37. data/lib/moose/inventory/config/config.rb +169 -0
  38. data/lib/moose/inventory/db/db.rb +249 -0
  39. data/lib/moose/inventory/db/exceptions.rb +14 -0
  40. data/lib/moose/inventory/db/models.rb +32 -0
  41. data/lib/moose/inventory/moose_inventory_cli.rb +25 -0
  42. data/lib/moose/inventory/version.rb +7 -0
  43. data/moose-inventory.gemspec +45 -0
  44. data/scripts/guard_quality.sh +3 -0
  45. data/scripts/guard_test.sh +2 -0
  46. data/scripts/reports.sh +4 -0
  47. data/spec/config/config.yml +12 -0
  48. data/spec/lib/moose/inventory/cli/application_spec.rb +15 -0
  49. data/spec/lib/moose/inventory/cli/cli_spec.rb +26 -0
  50. data/spec/lib/moose/inventory/cli/formatter_spec.rb +63 -0
  51. data/spec/lib/moose/inventory/cli/group_add_spec.rb +398 -0
  52. data/spec/lib/moose/inventory/cli/group_addhost_spec.rb +251 -0
  53. data/spec/lib/moose/inventory/cli/group_addvar_spec.rb +235 -0
  54. data/spec/lib/moose/inventory/cli/group_get_spec.rb +107 -0
  55. data/spec/lib/moose/inventory/cli/group_list_spec.rb +79 -0
  56. data/spec/lib/moose/inventory/cli/group_rm_spec.rb +191 -0
  57. data/spec/lib/moose/inventory/cli/group_rmhost_spec.rb +215 -0
  58. data/spec/lib/moose/inventory/cli/group_rmvar_spec.rb +202 -0
  59. data/spec/lib/moose/inventory/cli/group_spec.rb +15 -0
  60. data/spec/lib/moose/inventory/cli/host_add_spec.rb +330 -0
  61. data/spec/lib/moose/inventory/cli/host_addgroup_spec.rb +248 -0
  62. data/spec/lib/moose/inventory/cli/host_addvar_spec.rb +233 -0
  63. data/spec/lib/moose/inventory/cli/host_get_spec.rb +106 -0
  64. data/spec/lib/moose/inventory/cli/host_list_spec.rb +83 -0
  65. data/spec/lib/moose/inventory/cli/host_rm_spec.rb +132 -0
  66. data/spec/lib/moose/inventory/cli/host_rmgroup_spec.rb +245 -0
  67. data/spec/lib/moose/inventory/cli/host_rmvar_spec.rb +206 -0
  68. data/spec/lib/moose/inventory/cli/host_spec.rb +12 -0
  69. data/spec/lib/moose/inventory/config/config_spec.rb +80 -0
  70. data/spec/lib/moose/inventory/db/db_spec.rb +184 -0
  71. data/spec/lib/moose/inventory/db/models_spec.rb +150 -0
  72. data/spec/shared/shared_config_setup.rb +21 -0
  73. data/spec/spec_helper.rb +110 -0
  74. 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,7 @@
1
+ module Moose
2
+ ##
3
+ # The Moose-Tools dynanic inventory management library
4
+ module Inventory
5
+ VERSION = '0.1.0'
6
+ end
7
+ 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
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ guard -g quality
3
+
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ guard -g test
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ firefox spec/reports/quality/rubocop.html spec/reports/coverage/index.html spec/reports/test/rspec.html
4
+
@@ -0,0 +1,12 @@
1
+ ---
2
+ general:
3
+ defaultenv: test
4
+
5
+ test:
6
+ db:
7
+ adapter: "sqlite3"
8
+ file: "./tmp/test.db"
9
+
10
+ rspectest:
11
+ result: "true"
12
+
@@ -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