bin/onering in onering-client-0.0.46 vs bin/onering in onering-client-0.0.50

- old
+ new

@@ -1,328 +1,45 @@ #!/usr/bin/env ruby - -#onering -# list [options] field [key:value ..] -# search [options] [key:value .. ] -# provision [options] [key:value .. ] [pxe profile | ] - - -require 'multi_json' -require 'rubygems' -require 'subcommander' +require 'trollop' require 'onering' -require 'pp' +require 'hashlib' require 'rainbow' +require 'pp' -include Subcommander +plugins = Onering::CLI.submodules.collect{|i| i.name.split('::').last.downcase } +global = Trollop::options do + banner <<-EOS +onering command line client utility +Usage: + onering [global] [plugin] [subcommand] [options] -def print_format(data, format=nil) - format = :text unless format +where [global] options are: +EOS - case format.to_sym - when :text - if data.is_a?(Hash) - pp data - else - unless data.empty? - if data.is_a?(Array) - puts data.join("\n") - else - puts data.to_s - end - end - end + opt :url, "The URL of the Onering server to connect to", :short => "-s", :type => :string + opt :path, "The base path to prepend to all requests (default: /api)", :type => :string + opt :format, "The output format for return values (i.e.: json, yaml, text)", :default => 'text', :short => "-t", :type => :string + opt :sslkey, "Location of the SSL client key to use for authentication", :short => "-c", :type => :string + opt :apikey, "The API token to use for authentication", :short => "-k", :type => :string + opt :quiet, "Suppress standard output", :short => '-q' - when :yaml - require 'yaml' - puts YAML.dump(data) - - when :json - require 'json' - puts MultiJson.dump(data) - - else - raise "Unknown output format #{format}" - end + stop_on plugins end -begin - subcommander.version = ::Gem.loaded_specs['onering-client'].version.to_s - subcommander.desc = ::Gem.loaded_specs['onering-client'].description +plugin = ARGV.shift +Trollop::die("plugin argument is requried") if plugin.nil? - subcommand :devices, "Operations related to Onering's assets database" do |devices| - api = Onering::API::Devices - api.connect({ - :host => ENV['ONERING_URL'], - :pemfile => ENV['ONERING_PEM'] - }) - - def _field(action, field, value, opts={}) - rv = [] - ids = [] - - # append IDs from filter - ids += Onering::API::Devices.list('id', { - :filter => opts[:filter] - }) if opts[:filter] - - # add specific ID - ids << opts[:id] if opts[:id] - - ids.each do |id| - case action - when :get - rv << Onering::API::Devices.get_field(id, field) - when :set - rv << Onering::API::Devices.set_field(id, field, value) - end - end - - rv - end - - # SHOW - devices.subcommand :show, "Print out a single node by ID" do |sc| - sc.usage = "onering devices show ID" - sc.opt :format, '-t', '--format FORMAT', "Return the results as FORMAT" - - sc.exec do - id = sc[:args].first - print_format(api.get(id), sc[:format]) - end - end - - # GET [FIELD] - devices.subcommand :get, "Get a named field from one or more devices" do |sc| - sc.usage = "onering devices get FIELD" - sc.opt :filter, '-f', '--filter FILTER', "A urlquery filter string" - sc.opt :format, '-t', '--format FORMAT', "Return the results as FORMAT" - sc.opt :id, '-i', '--id ID', "A specific node ID" - - - sc.exec do - rv = _field(:get, sc[:args].first, nil, sc) - print_format(rv, sc[:format]) - end - end - - # SET [FIELD] - devices.subcommand :set, "Set a named field for one or more devices" do |sc| - sc.usage = "onering devices set FIELD VALUE" - sc.opt :filter, '-f', '--filter FILTER', "A urlquery filter string" - sc.opt :format, '-t', '--format FORMAT', "Return the results as FORMAT" - sc.opt :id, '-i', '--id ID', "A specific node ID" - - sc.exec do - rv = _field(:set, sc[:args].first, sc[:args][1], sc) - print_format(rv, sc[:format]) - end - end - - # LIST - devices.subcommand :list, "List field values" do |sc| - sc.usage = "onering devices list [-f FILTER] FIELD" - sc.opt :filter, '-f', '--filter FILTER', "A urlquery filter string" - sc.opt :format, '-t', '--format FORMAT', "Return the results as FORMAT" - - sc.exec do - field = sc[:args].first - filter = sc[:filter] - - print_format(api.list(field, { - :filter => filter - }), sc[:format]) - end - end - - # FIND - devices.subcommand :find, "Finds all nodes that match a urlquery filter string" do |sc| - sc.arity = 1 - sc.usage = "onering devices find FILTER" - sc.opt :format, '-t', '--format FORMAT', "Return the results as FORMAT" - - sc.exec do - print_format(api.find(sc[:args].first), sc[:format]) - end - end - - # SAVE - devices.subcommand :save, "Creates or updates a new device in Onering, reading a JSON document from standard input" do |sc| - sc.usage = "onering report | onering devices save [ID]" - - sc.exec do - unless STDIN.tty? - begin - json = ::MultiJson.load(STDIN.read) - raise "Input document must specify an ID" if sc[:args].empty? and not json['id'] - - rv = api.save((sc[:args].first || json['id']), json) - print_format(rv, :json) if rv - rescue Exception => e - STDERR.puts "#{e.class.name}: #{e.message}" - exit 1 - end - end - end - end +if plugins.include?(plugin) + begin + plugin = Onering::CLI.const_get(plugin.capitalize) + plugin.configure(global) + rv = plugin.run(ARGV) + Onering::CLI.output(rv, global[:format]) + rescue Onering::API::Errors::Exception => e + STDERR.puts("[#{e.class.name.split('::').last}]".foreground(:red) + " #{e.message}") + exit 1 end - - - subcommand :users, "Manage Onering users" do |users| - api = Onering::API::Auth - api.connect({ - :host => ENV['ONERING_URL'], - :pemfile => ENV['ONERING_PEM'] - }) - - # SHOW - users.subcommand :show, "Print out a single user by ID" do |sc| - sc.usage = "onering users show ID" - - sc.exec do - id = sc[:args].first - print_format(api.get(:users, id)) - end - end - - # LIST - users.subcommand :list, "List users" do |sc| - sc.usage = "onering users list FIELD" - sc.opt :format, '-t', '--format FORMAT', "Return the results as FORMAT" - - sc.exec do - field = sc[:args].first - filter = sc[:filter] - - print_format(api.list(:users, field, { - :filter => filter - }), sc[:format]) - end - end - - # SAVE - users.subcommand :save, "Creates or updates a new device in Onering, reading a JSON document from standard input" do |sc| - sc.usage = "cat user.json | onering users save [ID]" - - sc.exec do - unless STDIN.tty? - begin - json = ::MultiJson.load(STDIN.read) - raise "Input document must specify an ID" if sc[:args].empty? and not json['id'] - - print_format(api.save((sc[:args].first || json['id']), json)) - rescue Exception => e - STDERR.puts "#{e.class.name}: #{e.message}" - exit 1 - end - end - end - end - end - - subcommand :call, "Call generic Onering API endpoints" do |call| - api = Onering::API::Base - api.connect({ - :host => ENV['ONERING_URL'], - :pemfile => ENV['ONERING_PEM'] - }) - - call.usage = "onering call path/to/endpoint" - call.opt :format, '-t', '--format FORMAT', "Return the results as FORMAT" - call.opt :method, '-m', '--method VERB', "The HTTP method to use for the call (default: GET)" - call.opt :opts, '-o', '--option KEY:VALUE', Array, "A comma-separated list of key:value querystrings to pass with the request" - - call.exec do - rv = api.request(call[:args].first.to_sym, { - :method => (call[:method] || :get), - :data => (STDIN.tty? ? {} : ::MultiJson.load(STDIN.read) rescue {}), - :fields => (Hash[call[:opts].collect{|i| i.split(':',2) }] rescue {}) - }) - - print_format(rv, call[:format] || :json) unless rv.nil? or rv.to_s.strip.chomp.empty? - end - end - - subcommand :fact, "Retrieve a system fact" do |fact| - fact.usage = "onering fact NAME [DEFAULT] [NAME2 [DEFAULT2] ..]" - fact.opt :format, '-t', '--format FORMAT', "Return the results as FORMAT" - - fact.exec do - Onering::Reporter.setup() - rv = [] - - fact[:args].each_index do |i| - if i.even? - name = fact[:args][i] - else - default = fact[:args][i] - end - - rv << Onering::Reporter.fact(name, default) - end - - rv.compact! - rv = rv.first if rv.length == 1 - - print_format(rv, fact[:format]) unless rv.nil? or rv.to_s.empty? - end - end - - - subcommand :report, "Collect and output system information" do |report| - report.usage = "onering report" - report.opt :plugin_path, '-p', '--plugin PATH', 'Add the named path to the plugin search path' - report.opt :status, '-S', '--status STATUS', 'Set the status to report' - report.opt :tags, '-T', '--tag TAG[,...]', 'Add a tag to the report output' - report.opt :aliases, '-A', '--alias ALIAS[,...]', 'Add a alias to the report output' - report.opt :id, '-I', '--id ID', 'Override the auto-detected hardware ID' - report.opt :format, '-t', '--format FORMAT', 'Format the output' - - report.exec do - config = {} - %w{ - plugin_path - status - tags - aliases - id - }.each do |a| - a = a.to_sym - next if report[a].nil? - - if [:tags, :aliases].include?(a) - config[a] = report[a].split(',') - else - config[a] = report[a] - end - end - - Onering::Reporter.setup(config) - - rv = Onering::Reporter.report() - print_format(rv, report[:format] || :json) unless rv.nil? - end - end - - - subcommander.go! - -rescue SystemExit - exit 0 - -rescue Interrupt - exit 127 - -rescue Onering::API::Errors::ClientError => e - STDERR.puts("#{e.message}".foreground(:red)) - exit 1 - -rescue Exception => e - STDERR.puts("#{e.class.name}: #{e.message}".foreground(:red)) - e.backtrace.each do |b| - STDERR.puts(" #{b}") - end - - exit 1 +else + Trollop::die("unknown plugin #{plugin}") end \ No newline at end of file