pupistry 1.0.0 → 1.1.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: d510aff9adf9c6b3be5c31627368e8f121cd688b
4
- data.tar.gz: 1ea65ab0a96149ce31b622cadbfda987ea1583d1
3
+ metadata.gz: 8e3280a3e4dd9385278ae57d3ce8ac72ada37c0f
4
+ data.tar.gz: 1625107171f0d871a16b35008fac3c5e4ba3db63
5
5
  SHA512:
6
- metadata.gz: 15f88302ae54dd109db24ec08a8ae0852edb75070f0ef7f80ade1f15c1e5fd53f9b631624c9d04e7200cd4e372a6aa4e8d1b7b139362a6a1d41425d5a55aa205
7
- data.tar.gz: c18e071d7a52a28ea87d656fc5942b6ae27a3c2adefdd9bc41d74ca4ce980f64152eab386505caef9e4e9f1e38fd3889c55a7706f5050eddf7169d43da2fe46c
6
+ metadata.gz: 388aeb48985189832a1acd9f3e469cf07ec3a3eb784dee51fea8be3fae325dac439802727d8e7efcf124304e035ed9b53450051c0a2df3cdb4e35b7db5378b60
7
+ data.tar.gz: c8c90250e40b22b82c9192a96dc3f1d572d84b6b4f01c7303be889ffaadee86ea266fa76c800f521338696ad7537875c83c6ab49a8a75a196e2c6db9d6de455d
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # pupistry
2
2
 
3
+ [![Build Status](https://travis-ci.org/jethrocarr/pupistry.svg)](https://travis-ci.org/jethrocarr/pupistry)
4
+
3
5
  Pupistry (puppet + artistry) is a solution for implementing reliable and secure
4
6
  masterless puppet deployments by taking Puppet modules assembled by r10k and
5
7
  generating compresed and signed archives for distribution to the masterless
@@ -501,7 +503,9 @@ author.
501
503
 
502
504
  When developing Pupistry, you can run the git repo copy with:
503
505
 
504
- ruby -Ilib/ -r rubygems bin/pupistry
506
+ gem install bundler
507
+ bundle install
508
+ bundle exec pupistry
505
509
 
506
510
  By default Pupistry will try to load a settings.yaml file in the current
507
511
  working directory, before then trying `~/.pupistry/settings.yaml` and then
@@ -510,6 +514,14 @@ finally `/etc/pupistry/settings.yaml`. You can also override with `--config`.
510
514
  Add `--verbose` for additional debugging information. If you have a bug this
511
515
  is the first thing you should run to get more context for reports.
512
516
 
517
+ Whilst Pupistry has few tests, we would like to improve this. Please feel free
518
+ to contribute any additional tests and aim to write tests for new features and
519
+ definetly for any bug fixes. Once you have written tests, check the output of
520
+ the tests and Rubocop with:
521
+
522
+ bundle exec rake
523
+
524
+
513
525
 
514
526
  # Contributions
515
527
 
@@ -14,23 +14,20 @@ STDOUT.sync = true
14
14
  # Logging - STDOUT only
15
15
  $logger = Logger.new(STDOUT)
16
16
 
17
-
18
17
  # Thor is a toolkit for producing command line applications, see http://whatisthor.com/
19
18
  class CLI < Thor
20
- class_option :verbose, :type => :boolean
21
- class_option :config, :type => :string
22
-
19
+ class_option :verbose, type: :boolean
20
+ class_option :config, type: :string
23
21
 
24
22
  ## Agent Commands
25
-
26
- desc "apply", "Apply the latest Puppet artifact"
27
- method_option :noop, :type => :boolean, :desc => "No changes mode (note: does change checked out artifact, but no Puppet changes)"
28
- method_option :force, :type => :boolean, :desc => "Ignore existing versions, re-apply every time"
29
- method_option :minimal, :type => :boolean, :desc => "Don't run Puppet unless the artifact has changed"
30
- method_option :daemon, :type => :boolean, :desc => "Run as a system daemon"
31
- method_option :environment, :type => :string, :desc => "Specifiy which environment to deploy (default: master)"
32
- def apply
33
23
 
24
+ desc 'apply', 'Apply the latest Puppet artifact'
25
+ method_option :noop, type: :boolean, desc: 'No changes mode (note: does change checked out artifact, but no Puppet changes)'
26
+ method_option :force, type: :boolean, desc: 'Ignore existing versions, re-apply every time'
27
+ method_option :minimal, type: :boolean, desc: "Don't run Puppet unless the artifact has changed"
28
+ method_option :daemon, type: :boolean, desc: 'Run as a system daemon'
29
+ method_option :environment, type: :string, desc: 'Specifiy which environment to deploy (default: master)'
30
+ def apply
34
31
  # Thor seems to force class options to be defined repeatedly? :-/
35
32
  if options[:verbose]
36
33
  $logger.level = Logger::DEBUG
@@ -45,14 +42,9 @@ class CLI < Thor
45
42
  end
46
43
 
47
44
  # Muppet Check
48
- if options[:noop] and options[:daemon]
49
- $logger.warn "A daemon running in noop will do nothing except log what changes it could apply"
50
- end
51
-
52
- if options[:force] and options[:daemon]
53
- $logger.warn "A daemon running with force will be very wasteful of system resources! NOT RECOMMENDED."
54
- end
45
+ $logger.warn 'A daemon running in noop will do nothing except log what changes it could apply' if options[:noop] and options[:daemon]
55
46
 
47
+ $logger.warn 'A daemon running with force will be very wasteful of system resources! NOT RECOMMENDED.' if options[:force] and options[:daemon]
56
48
 
57
49
  if options[:daemon]
58
50
  # Run as a daemon service
@@ -63,13 +55,10 @@ class CLI < Thor
63
55
  end
64
56
  end
65
57
 
66
-
67
-
68
58
  ## Workstation Commands
69
59
 
70
- desc "build", "Build a new archive file"
60
+ desc 'build', 'Build a new archive file'
71
61
  def build
72
-
73
62
  # Thor seems to force class options to be defined repeatedly? :-/
74
63
  if options[:verbose]
75
64
  $logger.level = Logger::DEBUG
@@ -83,7 +72,6 @@ class CLI < Thor
83
72
  Pupistry::Config.find_and_load
84
73
  end
85
74
 
86
-
87
75
  begin
88
76
  # Fetch the latest data with r10k
89
77
  artifact = Pupistry::Artifact.new
@@ -91,20 +79,17 @@ class CLI < Thor
91
79
  artifact.fetch_r10k
92
80
  artifact.build_artifact
93
81
 
94
- puts "--"
95
- puts "Tip: Run pupistry diff to see what changed since the last artifact version"
82
+ puts '--'
83
+ puts 'Tip: Run pupistry diff to see what changed since the last artifact version'
96
84
 
97
- rescue Exception => e
98
- $logger.fatal "An unexpected error occured when trying to generate the new artifact file"
85
+ rescue StandardError => e
86
+ $logger.fatal 'An unexpected error occured when trying to generate the new artifact file'
99
87
  raise e
100
88
  end
101
-
102
89
  end
103
90
 
104
-
105
- desc "diff", "Show what has changed between now and the current live artifact"
91
+ desc 'diff', 'Show what has changed between now and the current live artifact'
106
92
  def diff
107
-
108
93
  # Thor seems to force class options to be defined repeatedly? :-/
109
94
  if options[:verbose]
110
95
  $logger.level = Logger::DEBUG
@@ -123,7 +108,7 @@ class CLI < Thor
123
108
  artifact_upstream.checksum = artifact_upstream.fetch_latest
124
109
 
125
110
  unless artifact_upstream.checksum
126
- $logger.error "There is no upstream artifact to compare to."
111
+ $logger.error 'There is no upstream artifact to compare to.'
127
112
  exit 0
128
113
  end
129
114
 
@@ -134,16 +119,14 @@ class CLI < Thor
134
119
  artifact_current.checksum = artifact_current.fetch_current
135
120
 
136
121
  unless artifact_current.checksum
137
- $logger.error "There is no current artifact to compare to, run \"pupistry build\" first to generate one with current changes"
122
+ $logger.error 'There is no current artifact to compare to, run "pupistry build" first to generate one with current changes'
138
123
  exit 0
139
124
  end
140
125
 
141
126
  artifact_current.fetch_artifact
142
127
 
143
128
  # Are they the same version?
144
- if artifact_current.checksum == artifact_upstream.checksum
145
- $logger.info "Current version and upstream version are the same, no diff"
146
- end
129
+ $logger.info 'Current version and upstream version are the same, no diff' if artifact_current.checksum == artifact_upstream.checksum
147
130
 
148
131
  # Unpack the archives
149
132
  artifact_current.unpack
@@ -161,25 +144,22 @@ class CLI < Thor
161
144
  # produce a new mega diff, we want only the real changes to be
162
145
  # easily visible, or the diff function loses value to people.
163
146
  # Pull requests welcome :-) xoxo
164
-
165
- Dir.chdir("#{$config["general"]["app_cache"]}/artifacts/") do
147
+
148
+ Dir.chdir("#{$config['general']['app_cache']}/artifacts/") do
166
149
  unless system "diff -Nuar unpacked.#{artifact_upstream.checksum} unpacked.#{artifact_current.checksum}"
167
150
  end
168
151
  end
169
152
 
170
-
171
153
  # Cleanup
172
154
  artifact_current.clean_unpack
173
155
  artifact_upstream.clean_unpack
174
156
 
175
- puts "--"
176
- puts "Tip: Run pupistry push to GPG sign & upload if happy to go live"
157
+ puts '--'
158
+ puts 'Tip: Run pupistry push to GPG sign & upload if happy to go live'
177
159
  end
178
160
 
179
-
180
- desc "push", "Sign & Upload a new artifact version"
161
+ desc 'push', 'Sign & Upload a new artifact version'
181
162
  def push
182
-
183
163
  # Thor seems to force class options to be defined repeatedly? :-/
184
164
  if options[:verbose]
185
165
  $logger.level = Logger::DEBUG
@@ -198,12 +178,10 @@ class CLI < Thor
198
178
  artifact.push_artifact
199
179
  end
200
180
 
201
-
202
- desc "bootstrap", "Generate a user-data bootstrap script for a node"
203
- method_option :template, :type => :string, :desc => 'The template you want to generate'
204
- method_option :base64, :type => :boolean, :desc => 'Output in base64 format'
181
+ desc 'bootstrap', 'Generate a user-data bootstrap script for a node'
182
+ method_option :template, type: :string, desc: 'The template you want to generate'
183
+ method_option :base64, type: :boolean, desc: 'Output in base64 format'
205
184
  def bootstrap
206
-
207
185
  # Thor seems to force class options to be defined repeatedly? :-/
208
186
  if options[:verbose]
209
187
  $logger.level = Logger::DEBUG
@@ -217,7 +195,6 @@ class CLI < Thor
217
195
  Pupistry::Config.find_and_load
218
196
  end
219
197
 
220
-
221
198
  if options[:template]
222
199
  $logger.info "Generating bootstrap template #{options[:template]}"
223
200
 
@@ -232,20 +209,17 @@ class CLI < Thor
232
209
  else
233
210
  templates = Pupistry::Bootstrap.new
234
211
  templates.list
235
-
236
- puts "--"
237
- puts "Tip: Run `pupistry bootstrap --template example` to generate a specific template"
212
+
213
+ puts '--'
214
+ puts 'Tip: Run `pupistry bootstrap --template example` to generate a specific template'
238
215
  end
239
-
240
216
  end
241
217
 
242
-
243
218
  ## Other Commands
244
219
 
245
- desc "setup", "Write a template configuration file"
246
- method_option :force, :type => :boolean, :desc => "Replace an existing config file"
220
+ desc 'setup', 'Write a template configuration file'
221
+ method_option :force, type: :boolean, desc: 'Replace an existing config file'
247
222
  def setup
248
-
249
223
  # Thor seems to force class options to be defined repeatedly? :-/
250
224
  if options[:verbose]
251
225
  $logger.level = Logger::DEBUG
@@ -253,52 +227,49 @@ class CLI < Thor
253
227
  $logger.level = Logger::INFO
254
228
  end
255
229
 
256
-
257
230
  # Generally we should put the Pupistry configuration into the home dir, a
258
231
  # developer who wants it elsewhere will be capable of figuring out how to
259
232
  # install themselves.
260
- config_dest = "~/.pupistry/settings.yaml"
233
+ config_dest = '~/.pupistry/settings.yaml'
261
234
 
262
235
  # If the HOME environmental hasn't been set, dump the config into CWD.
263
236
  unless ENV['HOME']
264
237
  config_dest = "#{Dir.pwd}/settings.yaml"
265
238
  $logger.warn "HOME is not set, so writing configuration file into #{config_dest}"
266
239
  end
267
-
240
+
268
241
  config_dest = File.expand_path config_dest
269
242
 
270
243
  # Make sure the directory exists
271
- unless Dir.exists?(File.dirname(config_dest))
272
- FileUtils.mkdir_p(File.dirname(config_dest))
273
- end
244
+ FileUtils.mkdir_p(File.dirname(config_dest)) unless Dir.exist?(File.dirname(config_dest))
274
245
 
275
246
  # Does a local template exist?
276
- if File.exists?("#{Dir.pwd}/settings.example.yaml")
247
+ if File.exist?("#{Dir.pwd}/settings.example.yaml")
277
248
  config_source = "#{Dir.pwd}/settings.example.yaml"
278
249
  else
279
250
  # Check for GEM installed location
280
251
  begin
281
- config_source = Gem::Specification.find_by_name("pupistry").gem_dir
252
+ config_source = Gem::Specification.find_by_name('pupistry').gem_dir
282
253
  config_source = "#{config_source}/settings.example.yaml"
283
254
  rescue Gem::LoadError
284
255
  # Yeah I dunno what you're doing...
285
- $logger.error "Unable to find settings.example.yaml, seems we are not running as a Gem nor in the CWD of the app source"
256
+ $logger.error 'Unable to find settings.example.yaml, seems we are not running as a Gem nor in the CWD of the app source'
286
257
  exit 0
287
258
  end
288
259
  end
289
260
 
290
- unless File.exists?(config_source)
261
+ unless File.exist?(config_source)
291
262
  $logger.error "Template configuration should exist in #{config_source} but no file found/readable!"
292
263
  exit 0
293
264
  end
294
265
 
295
266
  # Prevent Overwrite
296
- if File.exists?(config_dest)
297
- unless options[:force]
267
+ if File.exist?(config_dest)
268
+ if options[:force]
269
+ $logger.warn "Overwriting #{config_dest}..."
270
+ else
298
271
  $logger.error "Configuration file #{config_dest} already exists, if you wish to replace it please call with --force"
299
272
  exit 0
300
- else
301
- $logger.warn "Overwriting #{config_dest}..."
302
273
  end
303
274
  end
304
275
 
@@ -307,7 +278,7 @@ class CLI < Thor
307
278
  FileUtils.cp config_source, config_dest
308
279
 
309
280
  $logger.info "Successfully installed configuration file into #{config_dest}"
310
- rescue Exception => e
281
+ rescue StandardError => e
311
282
  $logger.error "An unexpected error occured when copying #{config_source} to #{config_dest}"
312
283
  raise e
313
284
  end
@@ -322,9 +293,7 @@ class CLI < Thor
322
293
  else
323
294
  $logger.info "You now need to edit #{config_dest} with your configuration values before running Pupistry."
324
295
  end
325
-
326
296
  end
327
-
328
297
  end
329
298
 
330
299
  CLI.start(ARGV)
data/lib/pupistry.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'pupistry/version'
1
2
  require 'pupistry/agent'
2
3
  require 'pupistry/artifact'
3
4
  require 'pupistry/bootstrap'
@@ -5,5 +6,4 @@ require 'pupistry/config'
5
6
  require 'pupistry/gpg'
6
7
  require 'pupistry/storage_aws'
7
8
 
8
-
9
9
  # vim:shiftwidth=2:tabstop=2:softtabstop=2:expandtab:smartindent
@@ -1,80 +1,69 @@
1
+ # rubocop:disable Style/GlobalVars
1
2
  require 'rubygems'
2
3
  require 'fileutils'
3
4
  require 'rufus/scheduler'
4
5
 
6
+ # Pupistry::Agent
5
7
  module Pupistry
6
- # Pupistry::Agent
7
-
8
+ # Functions for running the Pupistry agent aka "apply mode" to actually
9
+ # download and run Puppet against the contents of the artifact.
8
10
  class Agent
9
- # Functions for running the Pupistry agent aka "apply mode" to actually
10
- # download and run Puppet against the contents of the artifact.
11
-
12
-
13
- def self.daemon options
14
- ## Run as a daemon
15
-
16
-
11
+ ## Run as a daemon
12
+ def self.daemon(options)
17
13
  # Since options comes from Thor, it can't be modified, so we need to
18
14
  # copy the options and then we can edit it.
19
15
 
20
- options_new = options.inject({}) do |new, (name, value)|
21
- new[name] = value;
22
- new
16
+ options_new = options.inject({}) do |new, (name, value)|
17
+ new[name] = value
18
+ new
23
19
  end
24
20
 
25
21
  # If the minimal mode has been enabled in config, respect.
26
- if $config["agent"]["daemon_minimal"]
27
- options_new[:minimal] = true
28
- end
22
+ options_new[:minimal] = true if $config['agent']['daemon_minimal']
29
23
 
30
24
  # If no frequency supplied, use 300 seconds safe default.
31
- unless $config["agent"]["daemon_frequency"]
32
- $config["agent"]["daemon_frequency"] = 300
33
- end
34
-
25
+ $config['agent']['daemon_frequency'] = 300 unless $config['agent']['daemon_frequency']
35
26
 
36
27
  # Use rufus-scheduler to run our apply job as a regularly scheduled job
37
28
  # but with build in locking handling.
38
-
39
- $logger.info "Launching daemon... frequency of #{$config["agent"]["daemon_frequency"]} seconds."
29
+
30
+ $logger.info "Launching daemon... frequency of #{$config['agent']['daemon_frequency']} seconds."
40
31
 
41
32
  begin
42
33
 
43
34
  scheduler = Rufus::Scheduler.new
44
35
 
45
- scheduler.every "#{$config["agent"]["daemon_frequency"]}s", :overlap => false, :timeout => '1d', :first_at => Time.now + 1 do
46
- $logger.info "Triggering another Pupistry run (#{$config["agent"]["daemon_frequency"]}s)"
36
+ scheduler.every "#{$config['agent']['daemon_frequency']}s", overlap: false, timeout: '1d', first_at: Time.now + 1 do
37
+ $logger.info "Triggering another Pupistry run (#{$config['agent']['daemon_frequency']}s)"
47
38
  apply options_new
48
39
  end
49
40
 
50
41
  scheduler.join
51
42
 
52
43
  rescue Rufus::Scheduler::TimeoutError
53
- $logger.error "A run of Pupistry timed out after 1 day as a safety measure. There may be a bug or a Puppet action causing it to get stuck"
44
+ $logger.error 'A run of Pupistry timed out after 1 day as a safety measure. There may be a bug or a Puppet action causing it to get stuck'
54
45
 
55
- rescue SignalException => e
46
+ rescue SignalException
56
47
  # Clean shutdown signal (eg SIGTERM)
57
- $logger.info "Clean shutdown of Pupistry daemon requests"
48
+ $logger.info 'Clean shutdown of Pupistry daemon requests'
58
49
  exit 0
59
50
 
60
- rescue Exception => e
51
+ rescue StandardError => e
61
52
  raise e
62
53
  end
63
-
64
54
  end
65
55
 
66
-
67
- def self.apply options
56
+ def self.apply(options)
68
57
  ## Download and apply the latest artifact (if any)
69
58
 
70
59
  # Fetch artifact versions
71
- $logger.info "Checking version of artifact available..."
60
+ $logger.info 'Checking version of artifact available...'
72
61
 
73
62
  artifact = Pupistry::Artifact.new
74
63
  artifact.checksum = artifact.fetch_latest
75
64
 
76
65
  unless artifact.checksum
77
- $logger.error "There is no current artifact available for download, no steps can be taken."
66
+ $logger.error 'There is no current artifact available for download, no steps can be taken.'
78
67
  return false
79
68
  end
80
69
 
@@ -84,18 +73,16 @@ module Pupistry
84
73
  if artifact_installed.checksum
85
74
  $logger.debug "Currently on #{artifact_installed.checksum}"
86
75
  else
87
- $logger.debug "No currently installed artifact - blank slate!"
76
+ $logger.debug 'No currently installed artifact - blank slate!'
88
77
  end
89
78
 
90
79
  # Download the new artifact if one has changed. If we already have this
91
80
  # version, then we should skip downloading and go straight to running
92
81
  # Puppet - unless the user runs with --force (eg to fix a corrupted
93
82
  # artifact).
94
-
95
- if artifact.checksum != artifact_installed.checksum or options[:force]
96
- if options[:force]
97
- $logger.warn "Forcing download of latest artifact regardless of current one."
98
- end
83
+
84
+ if artifact.checksum != artifact_installed.checksum || options[:force]
85
+ $logger.warn 'Forcing download of latest artifact regardless of current one.' if options[:force]
99
86
 
100
87
  # Install the artifact
101
88
  $logger.info "Downloading latest artifact (#{artifact.checksum})..."
@@ -104,14 +91,14 @@ module Pupistry
104
91
  artifact.unpack
105
92
 
106
93
  unless artifact.install
107
- $logger.fatal "An unexpected error happened when installing the latest artifact, cancelling Puppet run"
94
+ $logger.fatal 'An unexpected error happened when installing the latest artifact, cancelling Puppet run'
108
95
  return false
109
96
  end
110
97
 
111
98
  # Remove temporary unpacked files
112
99
  artifact.clean_unpack
113
100
  else
114
- $logger.info "Already have latest artifact applied."
101
+ $logger.info 'Already have latest artifact applied.'
115
102
 
116
103
  # By default we run Puppet even if we have the latest artifact. There's
117
104
  # some grounds for debate about whether this is the right thing - in some
@@ -125,9 +112,9 @@ module Pupistry
125
112
  # To provide users with options, we provide the --lazy parameter to avoid
126
113
  # running Puppet except when the artifact changes. By default, Puppet
127
114
  # runs every thing to avoid surprise.
128
-
115
+
129
116
  if options[:minimal]
130
- $logger.info "Running with minimal effort mode enabled, not running Puppet since artifact version already applied"
117
+ $logger.info 'Running with minimal effort mode enabled, not running Puppet since artifact version already applied'
131
118
  return false
132
119
  end
133
120
 
@@ -140,35 +127,28 @@ module Pupistry
140
127
  environment = 'master'
141
128
  end
142
129
 
143
- unless Dir.exists?("#{$config["agent"]["puppetcode"]}/#{environment}")
130
+ unless Dir.exist?("#{$config['agent']['puppetcode']}/#{environment}")
144
131
  $logger.fatal "The requested branch/environment of #{environment} does not exist, unable to run Puppet"
145
132
  return false
146
133
  end
147
134
 
148
-
149
135
  # Execute Puppet.
150
- puppet_cmd = "puppet apply"
136
+ puppet_cmd = 'puppet apply'
151
137
 
152
- if options[:noop]
153
- puppet_cmd += " --noop"
154
- end
138
+ puppet_cmd += ' --noop' if options[:noop]
155
139
 
156
140
  puppet_cmd += " --environment #{environment}"
157
- puppet_cmd += " --confdir #{$config["agent"]["puppetcode"]}"
158
- puppet_cmd += " --modulepath #{$config["agent"]["puppetcode"]}/#{environment}/modules/"
159
- puppet_cmd += " --hiera_config #{$config["agent"]["puppetcode"]}/#{environment}/hiera.yaml"
160
- puppet_cmd += " #{$config["agent"]["puppetcode"]}/#{environment}/manifests/site.pp"
141
+ puppet_cmd += " --confdir #{$config['agent']['puppetcode']}"
142
+ puppet_cmd += " --modulepath #{$config['agent']['puppetcode']}/#{environment}/modules/"
143
+ puppet_cmd += " --hiera_config #{$config['agent']['puppetcode']}/#{environment}/hiera.yaml"
144
+ puppet_cmd += " #{$config['agent']['puppetcode']}/#{environment}/manifests/site.pp"
161
145
 
162
- $logger.info "Executing Puppet..."
146
+ $logger.info 'Executing Puppet...'
163
147
  $logger.debug "With: #{puppet_cmd}"
164
148
 
165
- unless system puppet_cmd
166
- $logger.error "An unexpected issue occured when running puppet"
167
- end
168
-
149
+ $logger.error 'An unexpected issue occured when running puppet' unless system puppet_cmd
169
150
  end
170
-
171
- end
151
+ end
172
152
  end
173
153
 
174
154
  # vim:shiftwidth=2:tabstop=2:softtabstop=2:expandtab:smartindent