1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-08 21:17:43 +03:00

B #1666: Marketplace driver expects always an image to import

* Use VMTEMPLATE marketapp type
    * Modify the OCA, so if the type is VMTEMPLATE no image is created
    * Modify Sunstone, so if the type is VMTEMPLATE no ds is needed

(cherry picked from commit 0de8a405d7a06bc28eca0c7b82661ddb588bb399)
This commit is contained in:
Ruben S. Montero 2019-03-18 00:38:28 +01:00
parent 75c8a7dc9e
commit 2d40b708c4
8 changed files with 152 additions and 94 deletions

View File

@ -229,7 +229,6 @@ public:
return format;
}
State get_state() const
{
return state;

View File

@ -90,7 +90,18 @@ int MarketPlaceApp::parse_template(string& error_str)
regtime = time(NULL);
std::string str_type;
get_template_attribute("TYPE", str_type);
if (!str_type.empty())
{
type = str_to_type(str_type);
}
else
{
type = IMAGE;
}
//Known attributes
//ORIGIN_ID
@ -441,7 +452,19 @@ int MarketPlaceApp::from_template64(const std::string &info64, std::string& err)
state = READY;
std::string str_type;
get_template_attribute("TYPE", str_type);
if (!str_type.empty())
{
type = str_to_type(str_type);
}
else
{
type = IMAGE;
}
origin_id = -1;
remove_template_attribute("TYPE");

View File

@ -67,7 +67,6 @@ class OneMarket
def fetch_appliances
rc, body = get('/appliance')
if rc != 0
return rc, body
end
@ -81,11 +80,13 @@ class OneMarket
tmpl = ''
app['type'] = 'IMAGE' unless app['type']
print_var(tmpl, 'NAME', app['name'])
print_var(tmpl, 'SOURCE', source)
print_var(tmpl, 'IMPORT_ID', id)
print_var(tmpl, 'ORIGIN_ID', '-1')
print_var(tmpl, 'TYPE', 'IMAGE')
print_var(tmpl, 'TYPE', app['type'])
print_var(tmpl, 'PUBLISHER', app['publisher'])
print_var(tmpl, 'FORMAT', app['format'])
print_var(tmpl, 'DESCRIPTION', app['short_description'])

View File

@ -17,42 +17,45 @@
require 'opennebula/pool_element'
module OpenNebula
class MarketPlaceApp < PoolElement
#######################################################################
# Constants and Class Methods
#######################################################################
MARKETPLACEAPP_METHODS = {
:info => "marketapp.info",
:allocate => "marketapp.allocate",
:delete => "marketapp.delete",
:update => "marketapp.update",
:chown => "marketapp.chown",
:chmod => "marketapp.chmod",
:rename => "marketapp.rename",
:enable => "marketapp.enable",
:lock => "marketapp.lock",
:unlock => "marketapp.unlock"
:info => 'marketapp.info',
:allocate => 'marketapp.allocate',
:delete => 'marketapp.delete',
:update => 'marketapp.update',
:chown => 'marketapp.chown',
:chmod => 'marketapp.chmod',
:rename => 'marketapp.rename',
:enable => 'marketapp.enable',
:lock => 'marketapp.lock',
:unlock => 'marketapp.unlock'
}
MARKETPLACEAPP_STATES = %w{INIT READY LOCKED ERROR DISABLED}
SHORT_MARKETPLACEAPP_STATES={
"INIT" => "ini",
"READY" => "rdy",
"LOCKED" => "lck",
"ERROR" => "err",
"DISABLED" => "dis"
'INIT' => 'ini',
'READY' => 'rdy',
'LOCKED' => 'lck',
'ERROR' => 'err',
'DISABLED' => 'dis'
}
MARKETPLACEAPP_TYPES = %w{UNKNOWN IMAGE VMTEMPLATE SERVICE_TEMPLATE}
SHORT_MARKETPLACEAPP_TYPES = {
"UNKNOWN" => "unk",
"IMAGE" => "img",
"VMTEMPLATE" => "tpl",
"SERVICE_TEMPLATE" => "srv"
'UNKNOWN' => 'unk',
'IMAGE' => 'img',
'VMTEMPLATE' => 'tpl',
'SERVICE_TEMPLATE' => 'srv'
}
# Creates a MarketPlace description with just its identifier
# this method should be used to create plain MarketPlace objects.
# +id+ the id of the user
@ -64,7 +67,7 @@ module OpenNebula
if pe_id
app_xml = "<MARKETPLACEAPP><ID>#{pe_id}</ID></MARKETPLACEAPP>"
else
app_xml = "<MARKETPLACEAPP></MARKETPLACEAPP>"
app_xml = '<MARKETPLACEAPP></MARKETPLACEAPP>'
end
XMLElement.build_xml(app_xml, 'MARKETPLACEAPP')
@ -80,7 +83,7 @@ module OpenNebula
#######################################################################
# Retrieves the information of the given marketplace app
def info()
def info
super(MARKETPLACEAPP_METHODS[:info], 'MARKETPLACEAPP')
end
@ -98,7 +101,7 @@ module OpenNebula
end
# Deletes the marketplace app
def delete()
def delete
super(MARKETPLACEAPP_METHODS[:delete])
end
@ -152,7 +155,7 @@ module OpenNebula
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def rename(name)
return call(MARKETPLACEAPP_METHODS[:rename], @pe_id, name)
call(MARKETPLACEAPP_METHODS[:rename], @pe_id, name)
end
# Exports this app to a suitable OpenNebula object
@ -169,78 +172,79 @@ module OpenNebula
# :vmtemplate => [ vmtemplates ids/OpenNebula::Error ],
# :image => [ vm ids/OpenNebula::Error ] }
def export(options = {})
return Error.new("Missing datastore id") if options[:dsid].nil?
return Error.new("Missing name to export app") if options[:name].nil?
rc = info
return rc if OpenNebula.is_error?(rc)
return Error.new("App is not in READY state") if state_str!="READY"
return Error.new('App is not READY') if state_str != 'READY'
case type_str
when "IMAGE"
if !self['APPTEMPLATE64'].nil?
tmpl=Base64::decode64(self['APPTEMPLATE64'])
else
tmpl=""
if options[:dsid].nil? && type_str != 'VMTEMPLATE'
return Error.new('Missing datastore id')
end
name = options[:name] || "marketapp-#{self.id}"
return Error.new('Missing name to export app') if options[:name].nil?
if !self['APPTEMPLATE64'].nil?
tmpl = Base64.decode64(self['APPTEMPLATE64'])
else
tmpl = ''
end
name = options[:name] || "marketapp-#{id}"
options[:vmtemplate_name] = name unless options[:vmtemplate_name]
tmpl << "\n"
tmpl << "NAME=\"" << name << "\"\n"
tmpl << "FROM_APP=\"" << self['ID'] << "\"\n"
tmpl << 'NAME=\"' << name << '\"\n'
tmpl << 'FROM_APP=\"' << self['ID'] << '\"\n'
case type_str
when 'IMAGE'
image = Image.new(Image.build_xml, @client)
rc = image.allocate(tmpl, options[:dsid])
ds = OpenNebula::Datastore.new_with_id(options[:dsid], @client)
image.info
ds.info
rc_image = image.info
rc_ds = ds.info
image_error = OpenNebula.is_error?(rc_image)
ds_error = OpenNebula.is_error?(rc_ds)
xpath = 'TEMPLATE/DRIVER'
if ds[xpath] == 'vcenter' && self['FORMAT'] != 'iso' && self['FORMAT'] != 'vmdk'
image.replace({'FORMAT' => 'vmdk'})
elsif ds[xpath] && ds[xpath] != 'vcenter' && self['FORMAT'] == 'vmdk'
image.replace({'FORMAT' => ds[xpath] })
format = self['FORMAT']
type = ds[xpath]
if !image_error && !ds_error
if type == 'vcenter' && format != 'iso' && format != 'vmdk'
image.replace('FORMAT' => 'vmdk')
elsif type && type != 'vcenter' && format == 'vmdk'
image.replace('FORMAT' => type)
end
end
return { :image => [rc] } if OpenNebula.is_error?(rc)
image_id = image.id
vmtpl_id = -1
vmtpl_id = create_vmtemplate(options, image.id)
if !self['TEMPLATE/VMTEMPLATE64'].nil?
tmpl=Base64::decode64(self['TEMPLATE/VMTEMPLATE64'])
return { :image => [image.id], :vmtemplate => [vmtpl_id] }
tmpl_name = options[:vmtemplate_name] || name
when 'VMTEMPLATE'
# TODO import all the images associated to a VMTEMPLATE app
# current version only support no-image based apps (e.g. hybrid)
vmtpl_id = create_vmtemplate(options)
tmpl << "\nNAME=\"#{tmpl_name}\"\n"
tmpl << "DISK=[ IMAGE_ID = #{image.id} ]\n"
vmtpl = Template.new(Template.build_xml, @client)
rc = vmtpl.allocate(tmpl)
if OpenNebula.is_error?(rc)
return { :image => [image_id], :vmtemplate => [rc] }
end
vmtpl_id = vmtpl.id
end
return { :image => [image_id], :vmtemplate => [vmtpl_id] }
return { :image => [], :vmtemplate => [vmtpl_id] }
else
return Error.new("App type #{app.type_str} not supported")
return Error.new("App type #{type_str} not supported")
end
end
# Enables this app
def enable
return call(MARKETPLACEAPP_METHODS[:enable], @pe_id, true)
call(MARKETPLACEAPP_METHODS[:enable], @pe_id, true)
end
# Enables this app
def disable
return call(MARKETPLACEAPP_METHODS[:enable], @pe_id, false)
call(MARKETPLACEAPP_METHODS[:enable], @pe_id, false)
end
# ---------------------------------------------------------------------
@ -279,12 +283,35 @@ module OpenNebula
# Locked a MarketplaceApp
def lock(level)
return call(MARKETPLACEAPP_METHODS[:lock], @pe_id, level)
call(MARKETPLACEAPP_METHODS[:lock], @pe_id, level)
end
# Unlocked a MarketplaceApp
def unlock()
return call(MARKETPLACEAPP_METHODS[:unlock], @pe_id)
call(MARKETPLACEAPP_METHODS[:unlock], @pe_id)
end
private
# Creates a VM template based on the VMTEMPLATE64 attribute
# @return [Integer, OpenNebula::Error] template id or error
# TODO this method needs to be extended to support [image_ids]
def create_vmtemplate(options, image_id = nil)
return if self['TEMPLATE/VMTEMPLATE64'].nil?
tmpl = Base64.decode64(self['TEMPLATE/VMTEMPLATE64'])
tmpl << "\nNAME=\"#{options[:vmtemplate_name]}\"\n"
tmpl << "DISK=[ IMAGE_ID = #{image_id} ]\n" if image_id
vmtpl = Template.new(Template.build_xml, @client)
rc = vmtpl.allocate(tmpl)
return rc if OpenNebula.is_error?(rc)
vmtpl.id
end
end
end

View File

@ -51,11 +51,12 @@ define(function(require) {
}
var resourceId = "" + selected_nodes[0];
var type = Sunstone.getDataTable(TAB_ID).type;
Sunstone.resetFormPanel(TAB_ID, EXPORT_DIALOG_ID);
Sunstone.showFormPanel(TAB_ID, EXPORT_DIALOG_ID, "export",
function(formPanelInstance, context) {
formPanelInstance.setResourceId(context, resourceId);
formPanelInstance.setResourceId(context, resourceId, type);
});
}
},

View File

@ -136,6 +136,8 @@ define(function(require) {
this.totalApps++;
this.type = OpenNebulaMarketPlaceApp.typeStr(element.TYPE);
var search = {
NAME: element.NAME,
UNAME: element.UNAME,

View File

@ -26,6 +26,7 @@ define(function(require) {
var Tips = require('utils/tips');
var DataStoresTable = require('tabs/datastores-tab/datatable');
var DataStore = require('opennebula/datastore');
var OpenNebulaMarketPlaceApp = require('opennebula/marketplaceapp');
var Config = require('sunstone-config');
var OpenNebula = require('opennebula');
var TemplateUtils = require('utils/template-utils');
@ -87,6 +88,7 @@ define(function(require) {
function _htmlWizard() {
return TemplateWizardHTML({
'formPanelId': this.formPanelId,
'template': this.type == "VMTEMPLATE",
'datastoresTableHTML': this.datastoresTable.dataTableHTML
});
}
@ -119,8 +121,9 @@ define(function(require) {
});
}
function _setResourceId(context, resourceId) {
function _setResourceId(context, resourceId, type) {
this.resourceId = resourceId;
this.type = type;
OpenNebula.MarketPlaceApp.show({
data : {

View File

@ -36,8 +36,10 @@
<input id="VMNAME" type="text" wizard_field="VMNAME"/>
</div>
</div>
{{#unless template}}
<fieldset>
<legend>{{tr "Select the Datastore to store the resource"}}</legend>
{{{datastoresTableHTML}}}
</fieldset>
{{/unless}}
</form>