class OpenNebulaHelper::OneHelper
Attributes
Public Class Methods
# File lib/one_helper.rb, line 641 def self.client if defined?(@@client) @@client else get_client end end
# File lib/one_helper.rb, line 1283 def self.filterflag_to_i_desc desc=<<~EOT a, all all the known #{rname}s m, mine the #{rname} belonging to the user in ONE_AUTH g, group 'mine' plus the #{rname} belonging to the groups the user is member of G, primary group the #{rname} owned the user's primary group uid #{rname} of the user identified by this uid user #{rname} of the user identified by the username EOT end
# File lib/one_helper.rb, line 602 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]||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 663 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 688 def self.list_layout_help "The default columns and their layout can be configured in #{conf_file}" end
# File lib/one_helper.rb, line 1243 def self.list_to_id_desc "Comma-separated list of OpenNebula #{rname} names or ids" end
# File lib/one_helper.rb, line 1247 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 } return -1, "#{ename} named #{name} not found." unless objects.length>0 return -1, "There are multiple #{ename}s with name #{name}." if objects.length>1 result = objects.first.id [0, result] end
# File lib/one_helper.rb, line 696 def initialize(_secret = nil, _endpoint = nil) @client=nil @translation_hash = nil end
# File lib/one_helper.rb, line 657 def self.set_endpoint(endpoint) @@endpoint=endpoint end
# File lib/one_helper.rb, line 653 def self.set_password(password) @@password=password end
# File lib/one_helper.rb, line 649 def self.set_user(user) @@user=user end
# File lib/one_helper.rb, line 1295 def self.table_conf(conf_file = self.conf_file) path = "#{ENV['HOME']}/.one/cli/#{conf_file}" if File.exist?(path) path else "#{TABLE_CONF_PATH}/#{conf_file}" end end
# File lib/one_helper.rb, line 692 def self.template_input_help(object_name) "#{TEMPLATE_INPUT}\nWhen using a template add only one #{object_name} instance." end
# File lib/one_helper.rb, line 1215 def self.to_id_desc "OpenNebula #{rname} name or id" end
Public Instance Methods
# File lib/one_helper.rb, line 722 def backup_mode_valid?(sus_backup_mode) BACKUP_MODES.each do |backup_mode| return true if backup_mode.casecmp?(sus_backup_mode) end false end
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 1109 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 710 def create_resource(_options, &block) resource = factory rc = block.call(resource) if OpenNebula.is_error?(rc) [-1, rc.message] else puts "ID: #{resource.id}" 0 end end
# File lib/one_helper.rb, line 1262 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') return rc if rc.first==-1 rc[1] end end [0, filter_flag] end
# File lib/one_helper.rb, line 1192 def group_name(resource, options = {}) if options[:numeric] resource['GID'] else resource['GNAME'] end end
# File lib/one_helper.rb, line 1058 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] return list_pool_format(pool, options, filter_flag) do |pool| hash = check_resource_xsd(pool, pname) puts ::JSON.pretty_generate(hash) end elsif options[:yaml] return 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 0 rescue SystemExit, Interrupt # Rescue ctrl + c when paginated 0 end
# File lib/one_helper.rb, line 970 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 0 end
# File lib/one_helper.rb, line 811 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 0 end
# File lib/one_helper.rb, line 1046 def list_pool_top(table, pool, options) table.top(options) do array = pool.get_hash return -1, array.message if OpenNebula.is_error?(array) array end 0 end
# File lib/one_helper.rb, line 889 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 page 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, 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 0 end
# File lib/one_helper.rb, line 1219 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 do |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 end [0, result] end
# File lib/one_helper.rb, line 1153 def perform_action(id, options, verbose, &block) resource = retrieve_resource(id) rc = block.call(resource) if OpenNebula.is_error?(rc) [-1, rc.message] else if options[:verbose] puts "#{self.class.rname} #{id}: #{verbose}" end 0 end end
# File lib/one_helper.rb, line 1167 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 775 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 [elements, page] end
# File lib/one_helper.rb, line 1305 def retrieve_resource(id) factory(id) end
# File lib/one_helper.rb, line 702 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 1123 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] [0, resource.to_xml(true)] elsif options[:json] # If body is set, the resource contains a JSON inside if options[:body] [0, check_resource_xsd(resource)] else [0, ::JSON.pretty_generate( check_resource_xsd(resource) )] end elsif options[:yaml] [0, check_resource_xsd(resource).to_yaml(:indent => 4)] else format_resource(resource, options) 0 end end
# File lib/one_helper.rb, line 733 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 lpid end
# File lib/one_helper.rb, line 763 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 1203 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 1184 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 1371 def check_resource_xsd(resource, ename = nil) hash = resource.to_hash ename ||= hash.keys.first 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 1489 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 StandardError 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 1350 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 1334 def get_pool user_flag = OpenNebula::Pool::INFO_ALL pool = factory_pool(user_flag) rc = pool.info if OpenNebula.is_error?(rc) return -1, rc.message unless rc.message.empty? return -1, "OpenNebula #{self.class.rname} name not " << 'found, use the ID instead' end [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 1449 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 1311 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 = [] 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 1417 def read_xsd(ename) require 'active_support' 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 end hash = Hash.from_xml(Nokogiri::XML(File.read(file)).to_s) hash = hash['schema']['element'] replace_refs(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 1397 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? 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 1477 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 1464 def xsd_complex_sequence?(x) x['complexType']['sequence']['element'] rescue return false true end