moose-inventory 0.1.0

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