puppetbox 0.1.0 → 0.3.0

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