~ubuntu-branches/ubuntu/lucid/puppet/lucid-security

« back to all changes in this revision

Viewing changes to lib/puppet/application.rb

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2009-12-23 00:48:10 UTC
  • mfrom: (1.1.10 upstream) (3.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091223004810-3i4oryds922g5n59
Tags: 0.25.1-3ubuntu1
* Merge from debian testing.  Remaining changes:
  - debian/rules:
    + Don't start puppet when first installing puppet.
  - debian/puppet.conf, lib/puppet/defaults.rb:
    + Move templates to /etc/puppet
  - lib/puppet/defaults.rb:
    + Fix /var/lib/puppet/state ownership.
  - man/man8/puppet.conf.8: 
    + Fix broken URL in manpage.
  - debian/control:
    + Update maintainer accordint to spec.
    + Puppetmaster Recommends -> Suggests
    + Created puppet-testsuite as a seperate. Allow the users to run puppet's 
      testsuite.
  - tests/Rakefile: Fix rakefile so that the testsuite can acutally be ran.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
require 'puppet'
 
2
require 'optparse'
 
3
 
 
4
# This class handles all the aspects of a Puppet application/executable
 
5
# * setting up options
 
6
# * setting up logs
 
7
# * choosing what to run
 
8
#
 
9
# === Usage
 
10
# The application is a Puppet::Application object that register itself in the list
 
11
# of available application. Each application needs a +name+ and a getopt +options+
 
12
# description array.
 
13
#
 
14
# The executable uses the application object like this:
 
15
#      Puppet::Application[:example].run
 
16
#
 
17
#
 
18
# Puppet::Application.new(:example) do
 
19
#
 
20
#     preinit do
 
21
#         # perform some pre initialization
 
22
#         @all = false
 
23
#     end
 
24
#
 
25
#     # dispatch is called to know to what command to call
 
26
#     dispatch do
 
27
#         ARGV.shift
 
28
#     end
 
29
#
 
30
#     option("--arg ARGUMENT") do |v|
 
31
#         @args << v
 
32
#     end
 
33
#
 
34
#     option("--debug", "-d") do |v|
 
35
#         @debug = v
 
36
#     end
 
37
#
 
38
#     option("--all", "-a:) do |v|
 
39
#         @all = v
 
40
#     end
 
41
#
 
42
#     unknown do |opt,arg|
 
43
#         # last chance to manage an option
 
44
#         ...
 
45
#         # let's say to the framework we finally handle this option
 
46
#         true
 
47
#     end
 
48
#
 
49
#     command(:read) do
 
50
#         # read action
 
51
#     end
 
52
#
 
53
#     command(:write) do
 
54
#         # writeaction
 
55
#     end
 
56
#
 
57
# end
 
58
#
 
59
# === Preinit
 
60
# The preinit block is the first code to be called in your application, before option parsing,
 
61
# setup or command execution.
 
62
#
 
63
# === Options
 
64
# Puppet::Application uses +OptionParser+ to manage the application options.
 
65
# Options are defined with the +option+ method to which are passed various
 
66
# arguments, including the long option, the short option, a description...
 
67
# Refer to +OptionParser+ documentation for the exact format.
 
68
# * If the option method is given a block, this one will be called whenever
 
69
# the option is encountered in the command-line argument.
 
70
# * If the option method has no block, a default functionnality will be used, that
 
71
# stores the argument (or true/false if the option doesn't require an argument) in
 
72
# the global (to the application) options array.
 
73
# * If a given option was not defined by a the +option+ method, but it exists as a Puppet settings:
 
74
#  * if +unknown+ was used with a block, it will be called with the option name and argument
 
75
#  * if +unknown+ wasn't used, then the option/argument is handed to Puppet.settings.handlearg for
 
76
#    a default behavior
 
77
#
 
78
# --help is managed directly by the Puppet::Application class, but can be overriden.
 
79
#
 
80
# === Setup
 
81
# Applications can use the setup block to perform any initialization.
 
82
# The defaul +setup+ behaviour is to: read Puppet configuration and manage log level and destination
 
83
#
 
84
# === What and how to run
 
85
# If the +dispatch+ block is defined it is called. This block should return the name of the registered command
 
86
# to be run.
 
87
# If it doesn't exist, it defaults to execute the +main+ command if defined.
 
88
#
 
89
class Puppet::Application
 
90
    include Puppet::Util
 
91
 
 
92
    @@applications = {}
 
93
    class << self
 
94
        include Puppet::Util
 
95
    end
 
96
 
 
97
    attr_reader :options, :opt_parser
 
98
 
 
99
    def self.[](name)
 
100
        name = symbolize(name)
 
101
        @@applications[name]
 
102
    end
 
103
 
 
104
    def should_parse_config
 
105
        @parse_config = true
 
106
    end
 
107
 
 
108
    def should_not_parse_config
 
109
        @parse_config = false
 
110
    end
 
111
 
 
112
    def should_parse_config?
 
113
        unless @parse_config.nil?
 
114
            return @parse_config
 
115
        end
 
116
        @parse_config = true
 
117
    end
 
118
 
 
119
    # used to declare a new command
 
120
    def command(name, &block)
 
121
        meta_def(symbolize(name), &block)
 
122
    end
 
123
 
 
124
    # used as a catch-all for unknown option
 
125
    def unknown(&block)
 
126
        meta_def(:handle_unknown, &block)
 
127
    end
 
128
 
 
129
    # used to declare code that handle an option
 
130
    def option(*options, &block)
 
131
        long = options.find { |opt| opt =~ /^--/ }.gsub(/^--(?:\[no-\])?([^ =]+).*$/, '\1' ).gsub('-','_')
 
132
        fname = "handle_#{long}"
 
133
        if (block_given?)
 
134
            meta_def(symbolize(fname), &block)
 
135
        else
 
136
            meta_def(symbolize(fname)) do |value|
 
137
                self.options["#{long}".to_sym] = value
 
138
            end
 
139
        end
 
140
        @opt_parser.on(*options) do |value|
 
141
            self.send(symbolize(fname), value)
 
142
        end
 
143
    end
 
144
 
 
145
    # used to declare accessor in a more natural way in the
 
146
    # various applications
 
147
    def attr_accessor(*args)
 
148
        args.each do |arg|
 
149
            meta_def(arg) do
 
150
                instance_variable_get("@#{arg}".to_sym)
 
151
            end
 
152
            meta_def("#{arg}=") do |value|
 
153
                instance_variable_set("@#{arg}".to_sym, value)
 
154
            end
 
155
        end
 
156
    end
 
157
 
 
158
    # used to declare code run instead the default setup
 
159
    def setup(&block)
 
160
        meta_def(:run_setup, &block)
 
161
    end
 
162
 
 
163
    # used to declare code to choose which command to run
 
164
    def dispatch(&block)
 
165
        meta_def(:get_command, &block)
 
166
    end
 
167
 
 
168
    # used to execute code before running anything else
 
169
    def preinit(&block)
 
170
        meta_def(:run_preinit, &block)
 
171
    end
 
172
 
 
173
    def initialize(name, banner = nil, &block)
 
174
        @opt_parser = OptionParser.new(banner)
 
175
 
 
176
        name = symbolize(name)
 
177
 
 
178
        init_default
 
179
 
 
180
        @options = {}
 
181
 
 
182
        instance_eval(&block) if block_given?
 
183
 
 
184
        @@applications[name] = self
 
185
    end
 
186
 
 
187
    # initialize default application behaviour
 
188
    def init_default
 
189
        setup do
 
190
            default_setup
 
191
        end
 
192
 
 
193
        dispatch do
 
194
            :main
 
195
        end
 
196
 
 
197
        # empty by default
 
198
        preinit do
 
199
        end
 
200
 
 
201
        option("--version", "-V") do |arg|
 
202
            puts "%s" % Puppet.version
 
203
            exit
 
204
        end
 
205
 
 
206
        option("--help", "-h") do |v|
 
207
            help
 
208
        end
 
209
    end
 
210
 
 
211
    # This is the main application entry point
 
212
    def run
 
213
        exit_on_fail("initialize") { run_preinit }
 
214
        exit_on_fail("parse options") { parse_options }
 
215
        exit_on_fail("parse configuration file") { Puppet.settings.parse } if should_parse_config?
 
216
        exit_on_fail("prepare for execution") { run_setup }
 
217
        exit_on_fail("run") { run_command }
 
218
    end
 
219
 
 
220
    def main
 
221
        raise NotImplementedError, "No valid command or main"
 
222
    end
 
223
 
 
224
    def run_command
 
225
        if command = get_command() and respond_to?(command)
 
226
            send(command)
 
227
        else
 
228
            main
 
229
        end
 
230
    end
 
231
 
 
232
    def default_setup
 
233
        # Handle the logging settings
 
234
        if options[:debug] or options[:verbose]
 
235
            Puppet::Util::Log.newdestination(:console)
 
236
            if options[:debug]
 
237
                Puppet::Util::Log.level = :debug
 
238
            else
 
239
                Puppet::Util::Log.level = :info
 
240
            end
 
241
        end
 
242
 
 
243
        unless options[:setdest]
 
244
            Puppet::Util::Log.newdestination(:syslog)
 
245
        end
 
246
    end
 
247
 
 
248
    def parse_options
 
249
        # get all puppet options
 
250
        optparse_opt = []
 
251
        optparse_opt = Puppet.settings.optparse_addargs(optparse_opt)
 
252
 
 
253
        # convert them to OptionParser format
 
254
        optparse_opt.each do |option|
 
255
            @opt_parser.on(*option) do |arg|
 
256
                handlearg(option[0], arg)
 
257
            end
 
258
        end
 
259
 
 
260
        # scan command line argument
 
261
        begin
 
262
            @opt_parser.parse!
 
263
        rescue OptionParser::ParseError => detail
 
264
            $stderr.puts detail
 
265
            $stderr.puts "Try '#{$0} --help'"
 
266
            exit(1)
 
267
        end
 
268
    end
 
269
 
 
270
    def handlearg(opt, arg)
 
271
        # rewrite --[no-]option to --no-option if that's what was given
 
272
        if opt =~ /\[no-\]/ and !arg
 
273
            opt = opt.gsub(/\[no-\]/,'no-')
 
274
        end
 
275
        # otherwise remove the [no-] prefix to not confuse everybody
 
276
        opt = opt.gsub(/\[no-\]/, '')
 
277
        unless respond_to?(:handle_unknown) and send(:handle_unknown, opt, arg)
 
278
            # Puppet.settings.handlearg doesn't handle direct true/false :-)
 
279
            if arg.is_a?(FalseClass)
 
280
                arg = "false"
 
281
            elsif arg.is_a?(TrueClass)
 
282
                arg = "true"
 
283
            end
 
284
            Puppet.settings.handlearg(opt, arg)
 
285
        end
 
286
    end
 
287
 
 
288
    # this is used for testing
 
289
    def self.exit(code)
 
290
        exit(code)
 
291
    end
 
292
 
 
293
    def help
 
294
        if Puppet.features.usage?
 
295
            ::RDoc::usage && exit
 
296
        else
 
297
            puts "No help available unless you have RDoc::usage installed"
 
298
            exit
 
299
        end
 
300
    end
 
301
 
 
302
    private
 
303
 
 
304
    def exit_on_fail(message, code = 1)
 
305
        begin
 
306
            yield
 
307
        rescue RuntimeError, NotImplementedError => detail
 
308
            puts detail.backtrace if Puppet[:trace]
 
309
            $stderr.puts "Could not %s: %s" % [message, detail]
 
310
            exit(code)
 
311
        end
 
312
    end
 
313
end