puppetbox 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad288284d9a66b09a591260219ab1c3ad31c9562
4
- data.tar.gz: 810ebf10d5f24b32eb3ba98d01b45db454805bb8
3
+ metadata.gz: f0b4270e3681f985ebb627e7126987337345963f
4
+ data.tar.gz: aa5f16dd84a2f10e25abe4e23c73a03082316fb6
5
5
  SHA512:
6
- metadata.gz: 35b2473e845e2aa9ad67d4012434a81ecaff79266d1a11823e29333eab3cb7cb78ffb8322f9e112b523967b142f7a19a29608c0e52d070fa8f5bb64558695745
7
- data.tar.gz: 84b43a030638aad37d350bd7179882e1860f9bcd59ca324380ad7d45d2652cdb0df46276fd1384c77436bb90cf5a24aa43f69c8c6222c1e091ff8602a9c80968
6
+ metadata.gz: af4ca9d3108b2d81150d53ea25473f4a5ddb722e14a76814f37e433c698c073919d3fbcaf228044740040651342de8fcc7146a912dafa7e5387864c61d29df1e
7
+ data.tar.gz: fa61ab2481c0fb6d49681168eb44b9917c5320f244b0d130123a6a140d0e1916c795bd986f6e1e8fbc5cf23179b8f7f4ddbb97dfe8c785f7e5e5b1f2f72477b8
data/Gemfile CHANGED
@@ -2,5 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in puppetbox.gemspec
4
4
  gem 'derelict', :git => 'https://github.com/GeoffWilliams/derelict', :ref => 'preserve_real_status'
5
+ #gem 'vagrantomatic', :path => '/home/geoff/github/vagrantomatic'
5
6
 
6
7
  gemspec
@@ -7,20 +7,47 @@ module PuppetBox
7
7
  module Driver
8
8
  class Vagrant
9
9
  # fixme - seems abandoned, might need to make my own :(
10
- DEFAULT_VAGRANT_BOX = "puppetlabs/centos-7.2-64-puppet"
10
+ # DEFAULT_VAGRANT_BOX = "puppetlabs/centos-7.2-64-puppet"
11
11
  PUPPET_CODE_MOUNT = "/etc/puppetlabs/code/environments/production"
12
12
 
13
- def initialize(name, codedir, keep_vm:true, working_dir:nil, config:{'box'=> DEFAULT_VAGRANT_BOX}, logger: nil)
13
+ def node_name
14
+ @name
15
+ end
16
+
17
+ # def initialize(name, codedir, keep_vm:true, working_dir:nil, config:{'box'=> DEFAULT_VAGRANT_BOX}, logger: nil)
18
+ def initialize(name, codedir, config, keep_vm:false, working_dir:nil, logger: nil)
19
+
14
20
  @name = name
15
21
  @keep_vm = keep_vm
16
22
  @working_dir = working_dir || File.join(Dir.home, '.puppetbox')
17
23
  @config = config
18
- @result = PuppetBox::Result.new
19
- @logger = PuppetBox::Logger.new(logger).logger
24
+ @result = Result.new
25
+ @logger = Logger.new(logger).logger
26
+
27
+ if ! @config.has_key?("box")
28
+ raise "Node #{node_name} must specify box"
29
+ end
20
30
 
21
31
  # Add the code dir to the config has so that it will automatically become
22
32
  # a shared folder when the VM boots
23
- @config["folders"] = "#{codedir}:#{PUPPET_CODE_MOUNT}"
33
+
34
+ # can't use dig() might not be ruby 2.3
35
+ if @config.has_key?("folders")
36
+ @config["folders"] = Array(@config["folders"])
37
+
38
+ # all paths must be fully qualified. If we were asked to do a relative path, change
39
+ # it to the current directory since that's probably what the user wanted. Not right?
40
+ # user supply correct path!
41
+ @config["folders"] = @config["folders"].map { |folder|
42
+ if ! folder.start_with? '/'
43
+ folder = "#{Dir.pwd}/#{folder}"
44
+ end
45
+ folder
46
+ }
47
+ else
48
+ @config["folders"] = []
49
+ end
50
+ @config["folders"] << "#{codedir}:#{PUPPET_CODE_MOUNT}"
24
51
  @logger.debug "instance #{name} initialised"
25
52
  end
26
53
 
@@ -38,15 +65,19 @@ module PuppetBox
38
65
  # 4: The run succeeded, and some resources failed.
39
66
  # 6: The run succeeded, and included both changes and failures.
40
67
  def run_puppet(puppet_class)
41
- run_hash = @vm.run("sudo -i puppet apply --detailed-exitcodes -e 'include #{puppet_class}'")
42
- @result.report(run_hash[:status], run_hash[:messages])
68
+ status_code, messages = @vm.run(
69
+ "sudo -i puppet apply --detailed-exitcodes -e 'include #{puppet_class}'"
70
+ )
71
+ @result.save(status_code, messages)
72
+ @result.passed?
43
73
  end
44
74
 
45
75
  # Open a connection to a box (eg start a vm, ssh to a host etc)
46
76
  def open()
47
77
  # make sure working dir exists...
48
78
  FileUtils.mkdir_p(@working_dir)
49
- vom = Vagrantomatic::Vagrantomatic.new(vagrant_vm_dir: @working_dir)
79
+
80
+ vom = Vagrantomatic::Vagrantomatic.new(vagrant_vm_dir: @working_dir, logger: @logger)
50
81
 
51
82
  @logger.debug("reading instance metadata for #{@name}")
52
83
  @vm = vom.instance(@name)
@@ -56,26 +87,42 @@ module PuppetBox
56
87
  @vm.config=(@config)
57
88
  @vm.save
58
89
  @logger.debug("Instance saved and ready for starting")
59
- @vm.start
90
+ started = @vm.start
60
91
  end
61
92
 
62
93
  # Close a connection to a box (eg stop a vm, probaly doesn't need to do
63
94
  # anything on SSH...)
64
95
  def close()
65
96
  if ! @keep_vm
97
+ @logger.info("Closing #{@node_name}")
66
98
  @vm.purge
67
99
  end
68
100
  end
69
101
 
102
+ def reset()
103
+ @vm.reset
104
+ end
105
+
70
106
  # Test that a VM is operational and able to run puppet
71
107
  def self_test()
72
- @vm.run("sudo -i puppet --version")[:status] == 0
108
+ status_code, messages = @vm.run("sudo -i puppet --version")
109
+ self_test = (status_code == 0)
110
+ if self_test
111
+ @logger.info("Running under Puppet version: #{messages[0].strip}")
112
+ else
113
+ @logger.error("Error #{status_code} running puppet: #{messages}")
114
+ end
115
+ self_test
73
116
  end
74
117
 
75
118
  def run_puppet_x2(puppet_class)
76
- # fixme - link module
77
- run_puppet(puppet_class)
78
- run_puppet(puppet_class)
119
+ # if you need to link a module into puppet's modulepath either do it
120
+ # before running puppet (yet to be supported) or use the @config hash
121
+ # for vagrant to mount what you need as a shared folder
122
+ if run_puppet(puppet_class)
123
+ # Only do the second run if the first run passes
124
+ run_puppet(puppet_class)
125
+ end
79
126
  end
80
127
 
81
128
  end
@@ -10,7 +10,11 @@ module PuppetBox
10
10
  else
11
11
  @logger = ::Logger.new(STDOUT)
12
12
  @logger.formatter = proc do |severity, datetime, progname, msg|
13
- "#{severity}: #{msg}"
13
+ # depending on the source, some messages come in with new lines and
14
+ # some do not so strip off any exiting and then add our own for
15
+ # consistency
16
+ msg = msg.strip
17
+ "#{severity}: #{msg}\n"
14
18
  end
15
19
  end
16
20
  end
@@ -0,0 +1,81 @@
1
+ require 'yaml'
2
+
3
+ module PuppetBox
4
+ class NodeSet
5
+ NODESET_FILE = "spec/acceptance/nodesets/puppetbox.yaml"
6
+ VERSION_KEY = "puppetbox_nodeset"
7
+ UNDERSTANDS_VERSION = [1]
8
+ REQUIRED_KEYS = ["config", "driver"]
9
+ NODE_ELEMENT = "nodes"
10
+
11
+ def initialize(nodeset_file=nil)
12
+ @nodeset_file = nodeset_file || NODESET_FILE
13
+
14
+ # parse the yaml file and simplify to human readable errors
15
+ begin
16
+ @nodeset = YAML.load(IO.read(@nodeset_file))
17
+ rescue Errno::ENOENT
18
+ raise "File not found: #{@nodeset_file}"
19
+ rescue Psych::SyntaxError
20
+ raise "Syntax error reading #{@nodeset_file}"
21
+ end
22
+ if @nodeset.has_key?(VERSION_KEY)
23
+ if UNDERSTANDS_VERSION.include?(@nodeset[VERSION_KEY])
24
+ if @nodeset.has_key?(NODE_ELEMENT)
25
+ hosts = @nodeset[NODE_ELEMENT]
26
+ hosts.each { |node_name, data|
27
+ # check each node has required keys
28
+ REQUIRED_KEYS.each { |required_key|
29
+ if ! data.has_key?(required_key)
30
+ raise "Nodeset file #{@nodeset_file} missing required key #{required_key} for node #{node_name}"
31
+ end
32
+ }
33
+ }
34
+ else
35
+ raise "Nodeset file #{@nodeset_file} missing root element `nodes`"
36
+ end
37
+ else
38
+ raise "Nodeset file format is #{@nodeset[VERSION_KEY]} but PuppetBox only supports versions #{UNDERSTANDS_VERSION}"
39
+ end
40
+ else
41
+ raise "Nodeset file #{@nodeset_file} does not contain #{VERSION_KEY} - check syntax"
42
+ end
43
+
44
+ end
45
+
46
+ def has_node?(node_name)
47
+ @nodeset[NODE_ELEMENT].has_key?(node_name)
48
+ end
49
+
50
+ def get_node(node_name)
51
+ if has_node?(node_name)
52
+ @nodeset[NODE_ELEMENT][node_name]
53
+ else
54
+ raise "Node #{node_name} is not defined in nodset file: #{@nodeset_file}"
55
+ end
56
+ end
57
+
58
+ #
59
+ #
60
+ # if nodeset["hosts"][node.name].has_key?('config') and nodeset_yaml["HOSTS"][node.name].has_key?('driver')
61
+ # test.classes.each { |puppet_class|
62
+ # logger.info "Acceptance testing #{node.name} #{puppet_class.name}"
63
+ # summary[node.name][puppet_class.name] = pb.provision_and_test(
64
+ # nodeset_yaml["HOSTS"][node.name]["driver"],
65
+ # node.name,
66
+ # puppet_class.name,
67
+ # nodeset_yaml["HOSTS"][node.name]['config'],
68
+ # @repo,
69
+ # )
70
+ #
71
+ # overall &= ! summary[node.name][puppet_class.name]
72
+ # }
73
+ # else
74
+ # message = "onceover-nodes.yaml missing `config` or `driver` element for #{node.name} (tests skipped)"
75
+ # summary[node.name] = message
76
+ # overall = false
77
+ # end
78
+ # end
79
+
80
+ end
81
+ end
@@ -0,0 +1,185 @@
1
+ require "puppetbox/result_set"
2
+ require "puppetbox/logger"
3
+ require "puppetbox/nodeset"
4
+ require "puppetbox/driver/vagrant"
5
+
6
+ module PuppetBox
7
+ class PuppetBox
8
+
9
+ def initialize(logger:nil, nodeset_file: nil)
10
+ # The results of all tests on all driver instances
11
+ @result_set = ResultSet.new
12
+
13
+ # A complete test suite of tests to run - includes driver instance, host
14
+ # and classes
15
+ @testsuite = {}
16
+ @logger = Logger.new(logger).logger
17
+
18
+ # the nodesets file contains a YAML representation of a hash containing
19
+ # the node name, config options, driver to use etc - so external tools can
20
+ # talk to use about nodes of particular name and puppetbox will sort out
21
+ # the how and why of what this exactly should involve
22
+ @nodeset = NodeSet.new(nodeset_file)
23
+ end
24
+
25
+
26
+ # Enqueue a test into the `testsuite` for
27
+ def enqueue_test(node_name, run_from, puppet_class)
28
+ instantiate_driver(node_name, run_from)
29
+ @testsuite[node_name]["classes"] << puppet_class
30
+ # get_driver_instance(driver_name, host)
31
+ # node_name
32
+ # puppet_class.name,
33
+ # nodeset_yaml["HOSTS"][node.name]['config'],
34
+ # @repo,
35
+ end
36
+
37
+ def run_testsuite
38
+ @testsuite.each { |id, tests|
39
+ run_puppet(tests["instance"], tests["classes"], logger:@logger, reset_after_run:true)
40
+ }
41
+ end
42
+
43
+ def instantiate_driver(node_name, run_from)
44
+ node = @nodeset.get_node(node_name)
45
+ config = node["config"]
46
+ driver = node["driver"]
47
+ if @testsuite.has_key?(node_name)
48
+ @logger.debug("#{node_name} already registered")
49
+ else
50
+ @logger.debug("Creating new driver instance for #{node_name}")
51
+
52
+ # for now just support the vagrant driver
53
+ case driver
54
+ when "vagrant"
55
+
56
+ # For the moment, just use the checked out production environment inside
57
+ # onceover's working directory. The full path resolves to something like
58
+ # .onceover/etc/puppetlabs/code/environments/production -- in the
59
+ # directory your running onceover from
60
+ #
61
+ # we pass in our pre-configured logger instance for separation and to
62
+ # reduce the amount of log output. We only print puppet apply output for
63
+ # failed runs, however, if user runs in onceover's --debug mode, then we
64
+ # will print the customary ton of messages, including those from vagrant
65
+ # itself.
66
+ puts config["box"]
67
+ di = Driver::Vagrant.new(
68
+ node_name,
69
+ run_from,
70
+ config,
71
+ # "#{repo.tempdir}/etc/puppetlabs/code/environments/production",
72
+ logger: @logger,
73
+
74
+ )
75
+ else
76
+ raise "PuppetBox only supports driver: 'vagrant' at the moment (requested: #{driver})"
77
+ end
78
+
79
+ @testsuite[node_name] = {
80
+ "instance" => di,
81
+ "classes" => [],
82
+ }
83
+ end
84
+
85
+ # di
86
+ # result = ::PuppetBox.run_puppet(di, puppet_class)
87
+
88
+ # indent = " "
89
+ # if result.passed
90
+ # logger.info("#{indent}#{host}:#{puppet_class} --> PASSED")
91
+ # else
92
+ # logger.error("#{indent}#{host}:#{puppet_class} --> FAILED")
93
+ # # since we stop running on failure, the error messages will be in the
94
+ # # last element of the result.messages array (tada!)
95
+ # messages = result.messages
96
+ # messages[-1].each { |line|
97
+ # # puts "XXXXXXX #{line}"
98
+ # logger.error "#{indent}#{host} - #{line}"
99
+ # }
100
+ # # puts "size of result messages #{result.messages.size}"
101
+ # # puts "size of result messages #{result.messages[0].size}"
102
+ # # run.each { |message_arr|
103
+ # # puts message_arr
104
+ # # #message_arr.each { |line|
105
+ # # # puts line
106
+ # # # }
107
+ # # # require 'pry'
108
+ # # # binding.pry
109
+ # # #puts "messages size"
110
+ # # #puts messages.size
111
+ # # # messages.each { |message|
112
+ # # # messages from the puppet run are avaiable in a nested array of run
113
+ # # # and then lines so lets print each one out indended from the host so
114
+ # # # we can see what's what
115
+ # # # logger.error("#{host} #{message}")
116
+ # # # }
117
+ # # }
118
+ # # }
119
+ # end
120
+ # result.passed
121
+ end
122
+
123
+
124
+ # Print all results to STDOUT
125
+ def print_results
126
+ # print the report summary
127
+ indent = " "
128
+ puts "\n\n\nSummary\n======="
129
+ summary.each { |node, class_results|
130
+ puts node
131
+ if class_results.class == String
132
+ puts "#{indent}#{class_results}"
133
+ else
134
+ class_results.each { |puppet_class, passed|
135
+ line = "#{indent}#{puppet_class}: #{passed ? "OK": "FAILED"}"
136
+ if passed
137
+ puts line.green
138
+ else
139
+ puts line.red
140
+ end
141
+ }
142
+ end
143
+ }
144
+
145
+ puts "Overall acceptance testing result #{overall}"
146
+ end
147
+
148
+
149
+
150
+ # Run puppet using `driver_instance` to execute
151
+ def run_puppet(driver_instance, puppet_classes, logger:nil, reset_after_run:true)
152
+ # use supplied logger in preference to the default puppetbox logger instance
153
+ logger = logger || @logger
154
+ logger.debug("#{driver_instance.node_name} running test for #{puppet_classes}")
155
+ puppet_classes = Array(puppet_classes)
156
+ results = ResultSet.new
157
+ if driver_instance.open
158
+ logger.debug("#{driver_instance.node_name} started")
159
+ if driver_instance.self_test
160
+ logger.debug("#{driver_instance.node_name} self_test OK, running puppet")
161
+ puppet_classes.each{ |puppet_class|
162
+ if results.class_size(driver_instance.node_name) > 0 and reset_after_run
163
+ # purge and reboot the vm - this will save approximately 1 second
164
+ # per class on the self-test which we now know will succeed
165
+ driver_instance.reset
166
+ end
167
+ driver_instance.run_puppet_x2(puppet_class)
168
+ results.save(driver_instance.node_name, puppet_class, driver_instance.result)
169
+ }
170
+ logger.debug("#{driver_instance.node_name} test completed, closing instance")
171
+ driver_instance.close
172
+ else
173
+ driver_instance.close
174
+ raise "#{driver_instance.node_name} self test failed, unable to continue"
175
+ end
176
+ else
177
+ driver_instance.close
178
+ raise "#{driver_instance.node_name} failed to start, unable to continue"
179
+ end
180
+
181
+ results
182
+ end
183
+
184
+ end
185
+ end
@@ -0,0 +1,27 @@
1
+ module PuppetBox
2
+ module Report
3
+ def self.printstuff(stream=$STDOUT)
4
+ # print the report summary
5
+ indent = " "
6
+ stream.puts "\n\n\nSummary\n======="
7
+ summary.each { |node, class_results|
8
+ puts node
9
+ if class_results.class == String
10
+ stream.puts "#{indent}#{class_results}"
11
+ else
12
+ class_results.each { |puppet_class, passed|
13
+ line = "#{indent}#{puppet_class}: #{passed ? "OK": "FAILED"}"
14
+ if passed
15
+ stream.puts line.green
16
+ else
17
+ stream.puts line.red
18
+ end
19
+ }
20
+ end
21
+ }
22
+
23
+ stream.puts "OVERALL STATUS #{overall}"
24
+ overall
25
+ end
26
+ end
27
+ end
@@ -23,7 +23,7 @@ module PuppetBox
23
23
  # 2: The run succeeded, and some resources were changed.
24
24
  # 4: The run succeeded, and some resources failed.
25
25
  # 6: The run succeeded, and included both changes and failures.
26
- def report(status_code, messages)
26
+ def save(status_code, messages)
27
27
  status = PS_ERROR
28
28
  if @report.empty?
29
29
  # first run
@@ -40,19 +40,37 @@ module PuppetBox
40
40
  @report.push({:status => status, :messages => messages})
41
41
  end
42
42
 
43
- def passed
44
- passed = true
43
+ # Test whether this set of results passed or not
44
+ # @return true if tests were executed and passed, nil if no tests were
45
+ # executed, false if tests were exectued and there were failures
46
+ def passed?
47
+ passed = nil
45
48
  @report.each { |r|
46
- passed &= r[:status] == PS_OK
49
+ puts "...REPORT"
50
+ if passed == nil
51
+ passed = (r[:status] == PS_OK)
52
+ else
53
+ passed &= (r[:status] == PS_OK)
54
+ end
47
55
  }
48
56
 
49
57
  passed
50
58
  end
51
59
 
60
+ def report_count
61
+ @report.size
62
+ end
63
+
64
+ def report_message_count(report)
65
+ @report[report].messages.size
66
+ end
67
+
68
+
69
+
52
70
  def messages(run=-1)
53
71
  messages = []
54
72
  if run < 0
55
- # all runs concatenated
73
+ # all NESTED in order of report
56
74
  @report.each { |r|
57
75
  messages << r[:messages]
58
76
  }
@@ -0,0 +1,67 @@
1
+ module PuppetBox
2
+ class ResultSet
3
+ def initialize
4
+ @results = {}
5
+ end
6
+
7
+ def save(node_name, class_name, result)
8
+ # check we didn't make a stupid programming error
9
+ if result.class != ::PuppetBox::Result
10
+ raise "result to save must be instance of PuppetBox::Result"
11
+ end
12
+
13
+ # if this is the first set of results for this node then we need to make
14
+ # a hash to contain the results
15
+ if ! @results.has_key?(node_name)
16
+ @results[node_name] = {}
17
+ end
18
+
19
+ # We can only run the same class on each node once, if we attempt to do so
20
+ # again,
21
+ if @results[node_name].has_key?(class_name)
22
+ raise "Duplicate results for class #{class_name} detected, You can " \
23
+ "only test the same class once per node. Check your test configuration"
24
+ else
25
+ @results[node_name][class_name] = result
26
+ end
27
+ end
28
+
29
+ def passed?
30
+ @results.map { |node_name, class_results_hash|
31
+ class_results_hash.map { |class_name, class_results|
32
+ class_results.passed?
33
+ }.all?
34
+ }.all?
35
+ end
36
+
37
+ def data
38
+ @results
39
+ end
40
+
41
+ # The count of how many nodes we presently have saved
42
+ def node_size
43
+ @results.size
44
+ end
45
+
46
+ # The count of how many classes we presently have saved for a given node
47
+ def class_size(node_name)
48
+ if @results.has_key?(node_name)
49
+ size = @results[node_name].size
50
+ else
51
+ size = 0
52
+ end
53
+
54
+ size
55
+ end
56
+
57
+ # The count of how many tests this result_set contains for all nodes and
58
+ # classes
59
+ def test_size
60
+ @results.map {|node_name, classes|
61
+ classes.size
62
+ }.reduce(:+)
63
+ end
64
+
65
+
66
+ end
67
+ end
@@ -1,3 +1,3 @@
1
1
  module PuppetBox
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/puppetbox.rb CHANGED
@@ -2,14 +2,5 @@ require "puppetbox/version"
2
2
 
3
3
  module PuppetBox
4
4
 
5
- def self.run_puppet(driver_instance, puppet_class)
6
- if driver_instance.open
7
- if driver_instance.self_test
8
- driver_instance.run_puppet_x2(puppet_class)
9
- driver_instance.close
10
- end
11
- end
12
- driver_instance.result
13
- end
14
5
 
15
6
  end
data/puppetbox.gemspec CHANGED
@@ -23,5 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
24
  spec.add_development_dependency "rspec", "~> 3.0"
25
25
 
26
- spec.add_dependency "vagrantomatic"
26
+ spec.add_dependency "vagrantomatic", "0.2.1"
27
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppetbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geoff Williams
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-11 00:00:00.000000000 Z
11
+ date: 2017-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: vagrantomatic
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 0.2.1
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 0.2.1
69
69
  description:
70
70
  email:
71
71
  - geoff@geoffwilliams.me.uk
@@ -86,7 +86,11 @@ files:
86
86
  - lib/puppetbox/driver.rb
87
87
  - lib/puppetbox/driver/vagrant.rb
88
88
  - lib/puppetbox/logger.rb
89
+ - lib/puppetbox/nodeset.rb
90
+ - lib/puppetbox/puppetbox.rb
91
+ - lib/puppetbox/report.rb
89
92
  - lib/puppetbox/result.rb
93
+ - lib/puppetbox/result_set.rb
90
94
  - lib/puppetbox/version.rb
91
95
  - puppetbox.gemspec
92
96
  homepage: https://github.com/GeoffWilliams/puppetbox