B #6162: Use stdin for datastore drivers in marketplace

The import action in the marketplace requires to execute the export
datastore action. This commits enables to use stdin to for datastore
action with -i options (same as DATASTORE_MAD)

(cherry picked from commit dc91241f05)
This commit is contained in:
Ruben S. Montero committed 2023-03-29 12:44:02 +02:00
1 parent 0c5ee5927c
commit 70296e8b75
1 file changed
+98 -62
+98 -62
View File
@@ -53,7 +53,7 @@ end
$LOAD_PATH << RUBY_LIB_LOCATION
require "OpenNebulaDriver"
require 'OpenNebulaDriver'
require 'getoptlong'
require 'base64'
require 'rexml/document'
@@ -66,11 +66,11 @@ class MarketPlaceDriver < OpenNebulaDriver
# Market Driver Protocol constants
ACTION = {
:import => "IMPORT",
:delete => "DELETE",
:log => "LOG",
:monitor => "MONITOR",
:export => "EXPORT" #For Datastore export action
:import => 'IMPORT',
:delete => 'DELETE',
:log => 'LOG',
:monitor => 'MONITOR',
:export => 'EXPORT' # For Datastore export action
}
# XPATHs for driver messages
@@ -78,11 +78,12 @@ class MarketPlaceDriver < OpenNebulaDriver
MARKETPLACEAPP_XPATH = '/MARKET_DRIVER_ACTION_DATA/MARKETPLACEAPP'
# Register default actions for the protocol
def initialize(market_type, options={})
def initialize(market_type, options = {})
@options={
:concurrency => 10,
:threaded => true,
:retries => 0,
:stdin => false,
:local_actions => {
ACTION[:import] => nil,
ACTION[:delete] => nil,
@@ -91,9 +92,9 @@ class MarketPlaceDriver < OpenNebulaDriver
}
}.merge!(options)
super("market/", @options)
super('market/', @options)
if market_type == nil
if market_type.nil?
@types = Dir["#{@local_scripts_path}/*/"].map do |d|
d.split('/')[-1]
end
@@ -105,11 +106,11 @@ class MarketPlaceDriver < OpenNebulaDriver
@local_ds_scripts_path = File.join(@local_scripts_base_path, 'datastore/')
@one = OpenNebula::Client.new()
@one = OpenNebula::Client.new
register_action(ACTION[:import].to_sym, method("import"))
register_action(ACTION[:delete].to_sym, method("delete"))
register_action(ACTION[:monitor].to_sym,method("monitor"))
register_action(ACTION[:import].to_sym, method('import'))
register_action(ACTION[:delete].to_sym, method('delete'))
register_action(ACTION[:monitor].to_sym, method('monitor'))
end
############################################################################
@@ -123,7 +124,7 @@ class MarketPlaceDriver < OpenNebulaDriver
xml = decode(drv_message)
if xml.nil?
failure(:import, id, "Cannot decode driver message")
failure(:import, id, 'Cannot decode driver message')
return
end
@@ -132,7 +133,7 @@ class MarketPlaceDriver < OpenNebulaDriver
mp_mad = xml['MARKETPLACE/MARKET_MAD']
if type.nil? || origin.nil? || mp_mad.nil?
failure(:import, id, "Wrong driver message format")
failure(:import, id, 'Wrong driver message format')
return
end
@@ -140,26 +141,29 @@ class MarketPlaceDriver < OpenNebulaDriver
#-----------------------------------------------------------------------
# Export marketplace origin to a file path, IMAGE
#-----------------------------------------------------------------------
when "IMAGE" then
when 'IMAGE'
# ------------ Execute export action from Datastore ----------------
ds_mad = xml['DATASTORE/DS_MAD']
if ds_mad.nil?
failure(:import, id, "Wrong driver message format")
failure(:import, id, 'Wrong driver message format')
return
end
ds_msg = "<DS_DRIVER_ACTION_DATA>"\
ds_msg = '<DS_DRIVER_ACTION_DATA>'\
"#{xml.element_xml('IMAGE')}"\
"#{xml.element_xml('DATASTORE')}"\
"</DS_DRIVER_ACTION_DATA>"
'</DS_DRIVER_ACTION_DATA>'
ds_msg64 = Base64::strict_encode64(ds_msg)
result, info = do_action(id,
nil,
ds_mad,
:export,
Base64.strict_encode64(ds_msg),
false,
@options[:stdin])
result, info = do_action(id, nil, ds_mad, :export,
"#{ds_msg64} #{id}", false)
if ( result == RESULT[:failure] )
if result == RESULT[:failure]
failure(:import, id, "Error exporting image to file: #{info}")
return
end
@@ -177,6 +181,7 @@ class MarketPlaceDriver < OpenNebulaDriver
end
# --------------- Import image app into the marketplace ----------------
# rubocop:disable Style/RedundantInterpolation
xml.add_element('/MARKET_DRIVER_ACTION_DATA',
'IMPORT_SOURCE' => "#{info_doc['IMPORT_SOURCE']}",
'MD5' => "#{info_doc['MD5']}",
@@ -184,10 +189,15 @@ class MarketPlaceDriver < OpenNebulaDriver
'FORMAT' => "#{info_doc['FORMAT']}",
'DISPOSE' => "#{info_doc['DISPOSE']}",
'DISPOSE_CMD' => "#{info_doc['DISPOSE_CMD']}")
# rubocop:enable Style/RedundantInterpolation
mp_msg64 = Base64::strict_encode64(xml.to_xml)
rc, info = do_action(id, mp_mad, nil, :import, "#{mp_msg64} #{id}",true)
rc, info = do_action(id,
mp_mad,
nil,
:import,
Base64.strict_encode64(xml.to_xml),
true,
false)
send_message(ACTION[:import], rc, id, info)
end
@@ -199,14 +209,14 @@ class MarketPlaceDriver < OpenNebulaDriver
xml = decode(drv_message)
if xml.nil?
failure(:import, id, "Cannot decode driver message")
failure(:import, id, 'Cannot decode driver message')
return
end
mp_mad = xml['MARKETPLACE/MARKET_MAD']
if mp_mad.nil?
failure(:delete, id, "Wrong driver message format")
failure(:delete, id, 'Wrong driver message format')
return
end
@@ -217,7 +227,8 @@ class MarketPlaceDriver < OpenNebulaDriver
mp_mad,
nil,
:delete,
"#{drv_message} #{id}",
drv_message,
false,
false)
send_message(ACTION[:delete], rc, id, info)
@@ -233,18 +244,24 @@ class MarketPlaceDriver < OpenNebulaDriver
xml = decode(drv_message)
if xml.nil?
failure(:monitor, id, "Cannot decode driver message")
failure(:monitor, id, 'Cannot decode driver message')
return
end
mp_mad = xml['MARKETPLACE/MARKET_MAD']
if mp_mad.nil?
failure(:monitor, id, "Wrong driver message format")
failure(:monitor, id, 'Wrong driver message format')
return
end
rc, info = do_action(id,mp_mad,nil,:monitor,"#{drv_message} #{id}",true)
rc, info = do_action(id,
mp_mad,
nil,
:monitor,
drv_message,
true,
false)
send_message(ACTION[:monitor], rc, id, info)
end
@@ -252,43 +269,55 @@ class MarketPlaceDriver < OpenNebulaDriver
private
# Check if the selected marketplace driver is enabled in the configuration
def is_available?(market, id, action)
def available?(market, id, action)
if @types.include?(market)
return true
true
else
send_message(ACTION[action], RESULT[:failure], id,
"Marketplace driver '#{market}' not available")
return false
"Marketplace driver '#{market}' not available")
false
end
end
#Execute marketplace or datastore actions for
# Execute marketplace or datastore actions for
# @param id of the app
# @param market driver to use
# @param datastore driver to use
# @param action to invoke from the driver
# @param arguments for the action
# @param drv_action message for the driver, it will be append with id
# @param encode base64 encode returning info
# @param stdin use stdin to pass drv_action and not command line argument
#
# @return result and info of the action
def do_action(id, market, datastore, action, arguments, encode)
# rubocop:disable Metric/ParameterLists
def do_action(id, market, datastore, action, drv_action, encode, stdin)
if !datastore.nil?
path = File.join(@local_ds_scripts_path, datastore)
else
return if not is_available?(market, id, action)
return unless available?(market, id, action)
path = File.join(@local_scripts_path, market)
end
cmd = File.join(path, ACTION[action].downcase)
cmd << " " << arguments
if stdin
arguments = " - #{id}"
else
arguments = " #{drv_action} #{id}"
drv_action = nil
end
rc = LocalCommand.run(cmd, log_method(id))
cmd = File.join(path, ACTION[action].downcase)
cmd << arguments
rc = LocalCommand.run(cmd, log_method(id), drv_action)
result, info = get_info_from_execution(rc)
info = Base64::strict_encode64(info) if encode && result != RESULT[:failure]
info = Base64.strict_encode64(info) if encode && result != RESULT[:failure]
return result, info
[result, info]
end
# rubocop:enable Metric/ParameterLists
# Decodes the core message and returns the app and market information as
# xml documents
@@ -299,12 +328,13 @@ class MarketPlaceDriver < OpenNebulaDriver
doc = nil if doc.xml_nil?
return doc
doc
end
def failure(asym, id, message)
send_message(ACTION[asym], RESULT[:failure], id, message)
end
end
################################################################################
@@ -314,34 +344,40 @@ end
################################################################################
opts = GetoptLong.new(
[ '--threads', '-t', GetoptLong::OPTIONAL_ARGUMENT ],
[ '--market-types', '-m', GetoptLong::OPTIONAL_ARGUMENT ],
[ '--timeout', '-w', GetoptLong::OPTIONAL_ARGUMENT ],
[ '--proxy' '-p', GetoptLong::OPTIONAL_ARGUMENT ]
['--threads', '-t', GetoptLong::OPTIONAL_ARGUMENT],
['--market-types', '-m', GetoptLong::OPTIONAL_ARGUMENT],
['--timeout', '-w', GetoptLong::OPTIONAL_ARGUMENT],
['--proxy', '-p', GetoptLong::OPTIONAL_ARGUMENT],
['--stdin', '-i', GetoptLong::NO_ARGUMENT]
)
mp_type = nil
threads = 15
timeout = nil
stdin = false
begin
opts.each do |opt, arg|
case opt
when '--threads'
threads = arg.to_i
when '--market-types'
mp_type = arg.split(',').map {|a| a.strip }
when '--timeout'
timeout = arg.to_i
when '--proxy'
ENV['http_proxy'] = arg
when '--threads'
threads = arg.to_i
when '--market-types'
mp_type = arg.split(',').map {|a| a.strip }
when '--timeout'
timeout = arg.to_i
when '--proxy'
ENV['http_proxy'] = arg
when '--stdin'
stdin = true
end
end
rescue
rescue StandardError
exit(-1)
end
mp_driver = MarketPlaceDriver.new(mp_type,
:concurrency => threads,
:timeout => timeout)
:timeout => timeout,
:stdin => stdin)
mp_driver.start_driver