class OpenNebulaHelper::OneHelper
Attributes
Public Class Methods
# File lib/one_helper.rb, line 496 def self.client if defined?(@@client) @@client else self.get_client end end
# File lib/one_helper.rb, line 1132 def self.filterflag_to_i_desc desc=<<-EOT a, all all the known #{self.rname}s m, mine the #{self.rname} belonging to the user in ONE_AUTH g, group 'mine' plus the #{self.rname} belonging to the groups the user is member of G, primary group the #{self.rname} owned the user's primary group uid #{self.rname} of the user identified by this uid user #{self.rname} of the user identified by the username EOT end
# File lib/one_helper.rb, line 457 def self.get_client(options={}, force=false) if !force && defined?(@@client) @@client else secret=nil password=nil if defined?(@@user) user=@@user password=@@password if defined?(@@password) else user=options[:user] end if user password=password||options[:password]||self.get_password secret="#{user}:#{password}" end if defined?(@@endpoint) endpoint=@@endpoint else endpoint=options[:endpoint] end # This breaks the CLI SSL support for Ruby 1.8.7, but is necessary # in order to do template updates, otherwise you get the broken pipe # error (bug #3341) if RUBY_VERSION < '1.9' sync = false else sync = true end options[:sync] = sync @@client=OpenNebula::Client.new(secret, endpoint, options) end end
# File lib/one_helper.rb, line 518 def self.get_password print "Password: " pass=nil STDIN.noecho {|io| pass=io.gets } puts pass.chop! if pass @@password=pass pass end
# File lib/one_helper.rb, line 1086 def self.list_to_id_desc "Comma-separated list of OpenNebula #{self.rname} names or ids" end
# File lib/one_helper.rb, line 1090 def self.name_to_id(name, pool, ename) if ename=="CLUSTER" and name.upcase=="ALL" return 0, "ALL" end objects=pool.select {|object| object.name==name } if objects.length>0 if objects.length>1 return -1, "There are multiple #{ename}s with name #{name}." else result = objects.first.id end else return -1, "#{ename} named #{name} not found." end return 0, result end
# File lib/one_helper.rb, line 543 def initialize(secret=nil, endpoint=nil) @client=nil @translation_hash = nil end
# File lib/one_helper.rb, line 512 def self.set_endpoint(endpoint) @@endpoint=endpoint end
# File lib/one_helper.rb, line 508 def self.set_password(password) @@password=password end
# File lib/one_helper.rb, line 504 def self.set_user(user) @@user=user end
# File lib/one_helper.rb, line 1144 def self.table_conf(conf_file=self.conf_file) path = "#{ENV["HOME"]}/.one/cli/#{conf_file}" if File.exists?(path) return path else return "#{TABLE_CONF_PATH}/#{conf_file}" end end
# File lib/one_helper.rb, line 1058 def self.to_id_desc "OpenNebula #{self.rname} name or id" end
Public Instance Methods
Check if a resource defined by attributes is referenced in pool
@param pool pool to search in @param xpath xpath to search in pool @param resource_name name of the resource to search (e.g IMAGE) @attributes hash with resource attributes, must contains :id, :name and :uname
atributes {uname => …, name => …, id => …}
# File lib/one_helper.rb, line 952 def check_orphan(pool, xpath, resource_name, attributes) return false if attributes.empty? return false unless pool["#{xpath}[#{resource_name}_ID = "\ "#{attributes[:id]}]"].nil? return false unless pool["#{xpath}[#{resource_name} = "\ "'#{attributes[:name]}' and "\ "#{resource_name}_UNAME = "\ "'#{attributes[:uname]}']"].nil? true end
# File lib/one_helper.rb, line 557 def create_resource(options, &block) resource = factory rc = block.call(resource) if OpenNebula.is_error?(rc) return -1, rc.message else puts "ID: #{resource.id.to_s}" return 0 end end
# File lib/one_helper.rb, line 1110 def filterflag_to_i(str) filter_flag = case str when "a", "all" then OpenNebula::Pool::INFO_ALL when "m", "mine" then OpenNebula::Pool::INFO_MINE when "g", "group" then OpenNebula::Pool::INFO_GROUP when "G", "primary group" then OpenNebula::Pool::INFO_PRIMARY_GROUP else if str.match(/^[0123456789]+$/) str.to_i else rc = OpenNebulaHelper.rname_to_id(str, "USER") if rc.first==-1 return rc else rc[1] end end end return 0, filter_flag end
# File lib/one_helper.rb, line 1035 def group_name(resource, options={}) if options[:numeric] resource['GID'] else resource['GNAME'] end end
# File lib/one_helper.rb, line 901 def list_pool(options, top=false, filter_flag=nil) # Capture Broken pipe Signal.trap('PIPE', 'EXIT') table = format_pool(options) if options[:describe] table.describe_columns return 0 end filter_flag ||= OpenNebula::Pool::INFO_ALL pool = factory_pool(filter_flag) pname = pool.pool_name ename = pool.element_name if top return list_pool_top(table, pool, options) elsif options[:xml] return list_pool_xml(pool, options, filter_flag) elsif options[:json] list_pool_format(pool, options, filter_flag) do |pool| hash = check_resource_xsd(pool, pname) puts ::JSON.pretty_generate(hash) end elsif options[:yaml] list_pool_format(pool, options, filter_flag) do |pool| hash = check_resource_xsd(pool, pname) puts hash.to_yaml(:indent => 4) end else return list_pool_table(table, pool, options, filter_flag) end return 0 rescue SystemExit, Interrupt # Rescue ctrl + c when paginated 0 end
# File lib/one_helper.rb, line 812 def list_pool_format(pool, options, filter_flag) extended = options.include?(:extended) && options[:extended] if $stdout.isatty and (!options.key?:no_pager) size = $stdout.winsize[0] - 1 # ----------- First page, check if pager is needed ------------- rc = pool.get_page(size, 0, extended, options[:state]) ps = "" return -1, rc.message if OpenNebula.is_error?(rc) elements = get_format_size(pool, options) ppid = -1 if elements >= size ppid = start_pager end yield(pool) if block_given? if elements < size return 0 end if elements < size return 0 elsif !pool.is_paginated? stop_pager(ppid) return 0 end # ------- Rest of the pages in the pool, piped to pager -------- current = size loop do rc = pool.get_page(size, current, extended, options[:state]) return -1, rc.message if OpenNebula.is_error?(rc) current += size begin Process.waitpid(ppid, Process::WNOHANG) rescue Errno::ECHILD break end elements = get_format_size(pool, options) break if elements < size yield(pool) if block_given? $stdout.flush end stop_pager(ppid) else if pool.pool_name == "VM_POOL" && extended rc = pool.info_all_extended else rc = pool.info end return -1, rc.message if OpenNebula.is_error?(rc) yield(pool) if block_given? end return 0 end
# File lib/one_helper.rb, line 650 def list_pool_table(table, pool, options, filter_flag) if $stdout.isatty and (!options.key?:no_pager) size = $stdout.winsize[0] - 1 # ----------- First page, check if pager is needed ------------- rc = pool.get_page(size, 0, false, options[:state]) ps = "" return -1, rc.message if OpenNebula.is_error?(rc) elements, hash = print_page(pool, options) ppid = -1 if elements >= size ppid = start_pager end table.show(hash, options) if elements < size return 0 elsif !pool.is_paginated? stop_pager(ppid) return 0 end # ------- Rest of the pages in the pool, piped to pager -------- current = size options[:no_header] = true loop do rc = pool.get_page(size, current, false, options[:state]) return -1, rc.message if OpenNebula.is_error?(rc) current += size begin Process.waitpid(ppid, Process::WNOHANG) rescue Errno::ECHILD break end elements, hash = print_page(pool, options) table.show(hash, options) $stdout.flush break if elements < size end stop_pager(ppid) else rc = pool.info return -1, rc.message if OpenNebula.is_error?(rc) elements, hash = print_page(pool, options) if options[:ids] && elements hash = [hash[pool.pool_name][pool.element_name]].flatten hash.reject! do |element| !options[:ids].include?(element['ID'].to_i) end end table.show(hash, options) end return 0 end
# File lib/one_helper.rb, line 888 def list_pool_top(table, pool, options) table.top(options) { array = pool.get_hash return -1, array.message if OpenNebula.is_error?(array) array } return 0 end
# File lib/one_helper.rb, line 728 def list_pool_xml(pool, options, filter_flag) extended = options.include?(:extended) && options[:extended] if $stdout.isatty and (!options.key?:no_pager) size = $stdout.winsize[0] - 1 # ----------- First page, check if pager is needed ------------- rc = pool.get_page(size, 0, extended, options[:state]) ps = "" return -1, rc.message if OpenNebula.is_error?(rc) pname = pool.pool_name elements, page = print_page(pool, options) ppid = -1 if elements >= size ppid = start_pager end puts "<#{pname}>" puts page if elements < size puts "</#{pname}>" return 0 end if elements < size return 0 elsif !pool.is_paginated? stop_pager(ppid) return 0 end # ------- Rest of the pages in the pool, piped to pager -------- current = size loop do rc = pool.get_page(size, current, extended, options[:state]) return -1, rc.message if OpenNebula.is_error?(rc) current += size begin Process.waitpid(ppid, Process::WNOHANG) rescue Errno::ECHILD break end elements, page = print_page(pool, options) puts page $stdout.flush break if elements < size end puts "</#{pname}>" stop_pager(ppid) else if pool.pool_name == "VM_POOL" && extended rc = pool.info_all_extended else rc = pool.info end return -1, rc.message if OpenNebula.is_error?(rc) puts pool.to_xml(true) end return 0 end
# File lib/one_helper.rb, line 1062 def list_to_id(names) rc = get_pool return rc if rc.first != 0 pool = rc[1] poolname = self.class.rname result = names.split(',').collect { |name| if name.match(/^[0123456789]+$/) name.to_i else rc = OneHelper.name_to_id(name, pool, poolname) if rc.first == -1 return rc[0], rc[1] end rc[1] end } return 0, result end
# File lib/one_helper.rb, line 996 def perform_action(id, options, verbose, &block) resource = retrieve_resource(id) rc = block.call(resource) if OpenNebula.is_error?(rc) return -1, rc.message else if options[:verbose] puts "#{self.class.rname} #{id}: #{verbose}" end return 0 end end
# File lib/one_helper.rb, line 1010 def perform_actions(ids,options,verbose,&block) exit_code = 0 ids.each do |id| rc = perform_action(id,options,verbose,&block) unless rc[0]==0 STDERR.puts rc[1] exit_code=rc[0] end end exit_code end
# File lib/one_helper.rb, line 614 def print_page(pool, options) elements = 0 page = "" if options[:xml] elements += 1 page << pool.to_xml(true) else pname = pool.pool_name ename = pool.element_name if options[:decrypt] page = pool.map do |element| element.info(true) element.to_hash[ename] end else page = pool.to_hash elems = page[pname][ename] end if elems.class == Array elements = elems.length else elements = 1 end end return elements, page end
# File lib/one_helper.rb, line 1154 def retrieve_resource(id) factory(id) end
# File lib/one_helper.rb, line 549 def set_client(options, client=nil) if client.nil? @client=OpenNebulaHelper::OneHelper.get_client(options, true) else @client = client end end
# File lib/one_helper.rb, line 966 def show_resource(id, options) resource = retrieve_resource(id) if !options.key? :decrypt rc = resource.info else rc = resource.info(true) end return -1, rc.message if OpenNebula.is_error?(rc) if options[:xml] return 0, resource.to_xml(true) elsif options[:json] # If body is set, the resource contains a JSON inside if options[:body] return 0, check_resource_xsd(resource) else return 0, ::JSON.pretty_generate( check_resource_xsd(resource) ) end elsif options[:yaml] return 0, check_resource_xsd(resource).to_yaml(:indent => 4) else format_resource(resource, options) return 0 end end
# File lib/one_helper.rb, line 572 def start_pager pager = ENV['ONE_PAGER'] || 'more' # Start pager, defaults to less p_r, p_w = IO.pipe Signal.trap('PIPE', 'SIG_IGN') Signal.trap('PIPE', 'EXIT') lpid = fork do $stdin.reopen(p_r) p_r.close p_w.close Kernel.select [$stdin] exec([pager, pager]) end # Send listing to pager pipe $stdout.close $stdout = p_w.dup p_w.close p_r.close return lpid end
# File lib/one_helper.rb, line 602 def stop_pager(lpid) $stdout.close begin Process.wait(lpid) rescue Interrupt Process.kill("TERM", lpid) Process.wait(lpid) rescue Errno::ECHILD end end
Formatters for arguments
# File lib/one_helper.rb, line 1046 def to_id(name) return 0, name.to_i if name.match(/^[0123456789]+$/) rc = get_pool return rc if rc.first != 0 pool = rc[1] poolname = self.class.rname OneHelper.name_to_id(name, pool, poolname) end
Id translation
# File lib/one_helper.rb, line 1027 def user_name(resource, options={}) if options[:numeric] resource['UID'] else resource['UNAME'] end end
Private Instance Methods
Check XSD values for a single resource
@param resource [OpenNebula::Object] Resource to check @param ename [String] Resource name
@return [Object] Hash with correct values
# File lib/one_helper.rb, line 1221 def check_resource_xsd(resource, ename = nil) hash = resource.to_hash ename = hash.keys.first unless ename xsd = read_xsd(ename) return hash unless xsd if xsd.keys.include?('complexType') xsd = xsd['complexType']['sequence']['element'] else xsd = xsd['element'] end xsd = [ xsd ] unless xsd.is_a? Array check_xsd(hash[ename], xsd) hash end
Recursively traverse the OpenNebula resource (in Hash) and it's XSD Where array is required in XSD, there encapsulate the entry into [ ] Typically usefull for single disk, snapshots etc.
@param hash [Hash] Resource information in hash format @param xsd [Hash] XSD of the resource, transformed into hash
# File lib/one_helper.rb, line 1340 def check_xsd(hash, xsd) return unless hash or hash.empty? hash.each do |k, v| # find the elem definition in xsd array xsd_elem = xsd.select { |e| e['name'] == k }.first unless xsd.nil? if xsd_complex_sequence?(xsd_elem) || xsd_complex_all?(xsd_elem) # go deeper in xsd, xsd is ehter complex sequence or all begin inner_xsd = xsd_elem['complexType']['sequence']['element'] rescue inner_xsd = xsd_elem['complexType']['all']['element'] end # recursively traverse resource - hash if v.is_a? Hash hash[k] = check_xsd(v, inner_xsd) # recursively traverse resource - array elsif v.is_a? Array hash[k] = [] v.each do |e| hash[k] << check_xsd(e, inner_xsd) end end end # if XSD requires array, do so in resource if missing if is_array?(xsd_elem) && (! v.is_a? Array) hash[k] = [ v ] end end end
# File lib/one_helper.rb, line 1200 def get_format_size(pool, options) if options[:json] ::JSON.pretty_generate(pool.to_hash).split("\n").size elsif options[:yaml] pool.to_hash.to_yaml.split("\n").size else STDERR.puts 'ERROR: Format not found' exit(-1) end end
# File lib/one_helper.rb, line 1183 def get_pool user_flag = OpenNebula::Pool::INFO_ALL pool = factory_pool(user_flag) rc = pool.info if OpenNebula.is_error?(rc) if rc.message.empty? return -1, "OpenNebula #{self.class.rname} name not " << "found, use the ID instead" else return -1,rc.message end end return 0, pool end
Decides if given xsd definiton should be array in xml Must be hash and contain either 'maxOccurs' => unbounded'
or 'maxOccurs' => >1
@param e [Hash] XSD definition transfomred in hash
@return [Boolean]
# File lib/one_helper.rb, line 1301 def is_array?(e) return false if e.nil? return false unless e.is_a? Hash e['maxOccurs'] == 'unbounded' || e['maxOccurs'].to_i > 1 end
# File lib/one_helper.rb, line 1160 def pool_to_array(pool) if !pool.instance_of?(Hash) phash = pool.to_hash else phash = pool end rname = self.class.rname if phash["#{rname}_POOL"] && phash["#{rname}_POOL"]["#{rname}"] if phash["#{rname}_POOL"]["#{rname}"].instance_of?(Array) phash = phash["#{rname}_POOL"]["#{rname}"] else phash = [phash["#{rname}_POOL"]["#{rname}"]] end else phash = Array.new end phash end
Read XSD file and parse to XML
@param ename [String] Element name to read XSD
@return [Hash] XSD in hash format, nil if not found
# File lib/one_helper.rb, line 1268 def read_xsd(ename) require 'active_support/core_ext/hash/conversions' # Try GEM directory file = File.expand_path( "../share/schemas/xsd/#{ename.downcase}.xsd", File.dirname(__FILE__) ) file = "#{XSD_PATH}/#{ename.downcase}.xsd" unless File.exist?(file) unless File.exist?(file) STDERR.puts "WARNING: XSD for #{ename} not found, skipping check" return nil end hash = Hash.from_xml(Nokogiri::XML(File.read(file)).to_s) hash = hash['schema']['element'] hash = replace_refs(hash) hash end
Replaces refs in xsd definition limited func: only traverse hashes (not arrays), but works well for pools
@param h [Hash] XSD in hash format
@return [Object] XSD but where ref were, there inner XSD is loaded
# File lib/one_helper.rb, line 1248 def replace_refs(h) return h unless h.is_a? Hash if h.keys.include? 'ref' ref_xsd = read_xsd(h['ref']) return ref_xsd unless ref_xsd.nil? return h else h.each do |k,v| h[k] = replace_refs(v) end end end
Decides if given xsd definiton is complex type all Must be hash and contain nested hash
['complexType']['all']['element']
@param [Hash] XSD definition transfomred in hash
@return [Boolean]
# File lib/one_helper.rb, line 1328 def xsd_complex_all?(x) x['complexType']['all']['element'] rescue return false true end
Decides if given xsd definiton is complex type sequence Must be hash and contain nested hash
['complexType']['sequence']['element']
@param [Hash] XSD definition transfomred in hash
@return [Boolean]
# File lib/one_helper.rb, line 1315 def xsd_complex_sequence?(x) x['complexType']['sequence']['element'] rescue return false true end