1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-23 17:33:56 +03:00

Squashed commit of the following:

commit 4ebd4ebe55
Author: semedi <sergio.semedi@gmail.com>
Date:   Fri Mar 23 11:17:55 2018 +0100

    F #1808: vCenter cli helper added to install sh

commit 84e3b94621
Author: abelCoronado93 <acoronado@opennebula.org>
Date:   Thu Mar 22 14:57:39 2018 +0100

    F #1808: Waiting system for requests [Sunstone]

commit 7b75828a8d
Author: abelCoronado93 <acoronado@opennebula.org>
Date:   Thu Mar 22 12:49:19 2018 +0100

    F #1808: Added feedback for DS importations [Sunstone]

commit 9c8f6e1674
Author: abelCoronado93 <acoronado@opennebula.org>
Date:   Thu Mar 22 12:48:20 2018 +0100

    F #1808: Broken importer output [vCenter]

commit dc5be2aa1e
Author: abelCoronado93 <acoronado@opennebula.org>
Date:   Thu Mar 22 12:46:39 2018 +0100

    F #1808: Removed bindings [Sinatra]

commit 1bea93e644
Author: semedi <sergio.semedi@gmail.com>
Date:   Wed Mar 21 12:52:29 2018 +0100

    F #1808: vCenter importer added to install sh

commit b5debcf606
Author: semedi <sergio.semedi@gmail.com>
Date:   Tue Mar 20 16:35:12 2018 +0100

    F #1808: vCenter importer feedback and class variables

    F #1808: code restructure and output

commit 4e6d6a891b
Author: abelCoronado93 <acoronado@opennebula.org>
Date:   Mon Mar 19 16:35:37 2018 +0100

    F #1808: Global path for ajax [Sunstone]

commit 110156a5b1
Author: abelCoronado93 <acoronado@opennebula.org>
Date:   Mon Mar 19 13:20:07 2018 +0100

    F #1808: vCenter DS importation makeover [Sunstone]

commit d9b86e8fe8
Author: abelCoronado93 <acoronado@opennebula.org>
Date:   Thu Mar 15 15:27:39 2018 +0100

    F #1808: Importation vCenter DS [Sinatra]

commit 58e59de065
Author: abelCoronado93 <acoronado@opennebula.org>
Date:   Thu Mar 15 15:27:07 2018 +0100

    F #1808: Importation vCenter DS [Sunstone]

commit c81b2662cb
Author: semedi <sergio.semedi@gmail.com>
Date:   Fri Mar 9 11:59:39 2018 +0100

    F #1804: datastore importer basic functionality [COMPLETE]

    F #1804: created new files and code restructure

    F #1804: datastore list functionality added

    F #1804: onevcenter list with ref

    F #1804: vCenter datastore importation works with key refs

    F #1804: vCenter importer->datastore
This commit is contained in:
Tino Vazquez 2018-03-23 15:10:20 +01:00
parent c3b113c5f2
commit ae033f992d
16 changed files with 621 additions and 312 deletions

View File

@ -685,6 +685,7 @@ VMM_EXEC_LIB_FILES="src/vmm_mad/remotes/lib/poll_common.rb"
VMM_EXEC_LIB_VCENTER_FILES="src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb
src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb \
src/vmm_mad/remotes/lib/vcenter_driver/vcenter_importer.rb \
src/vmm_mad/remotes/lib/vcenter_driver/importer.rb \
src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb \
src/vmm_mad/remotes/lib/vcenter_driver/host.rb \
@ -1587,6 +1588,7 @@ ONE_CLI_LIB_FILES="src/cli/one_helper/onegroup_helper.rb \
src/cli/one_helper/onevmgroup_helper.rb \
src/cli/one_helper/onevrouter_helper.rb \
src/cli/one_helper/onemarketapp_helper.rb \
src/cli/one_helper/onevcenter_helper.rb \
src/cli/one_helper/onemarket_helper.rb"
CLI_BIN_FILES="src/cli/onevm \

View File

@ -0,0 +1,82 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
require 'one_helper'
class OneVcenterHelper < OpenNebulaHelper::OneHelper
def connection_options(object_name, options)
if options[:vuser].nil? || options[:vcenter].nil?
raise "vCenter connection parameters are mandatory to import"\
" #{object_name}:\n"\
"\t --vcenter vCenter hostname\n"\
"\t --vuser username to login in vcenter"
end
password = options[:vpass] || OpenNebulaHelper::OneHelper.get_password
{
:user => options[:vuser],
:password => password,
:host => options[:vcenter]
}
end
TABLE = {
"datastores" => ["DATASTORE_LIST", "DATASTORE"],
"networks" => ["NETWORK_LIST", "NETWORK"],
"templates" => ["TEMPLATE_LIST", "TEMPLATE"]
}
def cli_format(o, hash)
{TABLE[o].first => {TABLE[o].last => hash.values}}
end
def list_object(options, list)
list = cli_format(options[:object], list)
table = format_list(options)
table.show(list)
end
def format_list(options)
table = CLIHelper::ShowTable.new() do
column :IMID, "identifier for ...", :size=>4 do |d|
d[:import_id]
end
column :REF, "ref", :left, :size=>15 do |d|
d[:ref]
end
column :VCENTER, "vCenter", :left, :size=>20 do |d|
d[:vcenter]
end
column :NAME, "Name", :left, :size=>20 do |d|
d[:simple_name]
end
column :CLUSTERS, "CLUSTERS", :left, :size=>10 do |d|
d[:cluster].to_s
end
default :IMID, :REF, :VCENTER, :NAME, :CLUSTERS
end
table
end
end

View File

@ -31,46 +31,36 @@ $: << RUBY_LIB_LOCATION+"/cli"
$: << REMOTES_LOCATION+"vmm/vcenter/"
require 'command_parser'
require 'one_helper/onehost_helper'
require 'one_helper/onecluster_helper'
require 'one_helper/onevcenter_helper'
require 'vcenter_driver'
def connection_options(object_name, options)
if options[:vuser].nil? ||
options[:vcenter].nil?
STDERR.puts "vCenter connection parameters are mandatory to import"\
" #{object_name}:\n"\
"\t --vcenter vCenter hostname\n"\
"\t --vuser username to login in vcenter"
exit -1
end
password = options[:vpass] || OpenNebulaHelper::OneHelper.get_password
{
:user => options[:vuser],
:password => password,
:host => options[:vcenter]
}
end
cmd=CommandParser::CmdParser.new(ARGV) do
usage "`onevcenter` <command> [<args>] [<options>]"
version OpenNebulaHelper::ONE_VERSION
helper = OneHostHelper.new
helper = OneVcenterHelper.new
before_proc do
helper.set_client(options)
end
############################################################################
# Global Options
############################################################################
cmd_options=CommandParser::OPTIONS-[CommandParser::VERBOSE]
set :option, cmd_options+OpenNebulaHelper::CLIENT_OPTIONS
OBJECT = {
:name => "object",
:short => "-o object",
:large => "--object object ",
:format => String,
:description => "vCenter object"
}
HOST = {
:name => "host",
:short => "-h host_id",
:large => "--host host_id",
:format => String,
:description => "OpenNebula host used to authenticate the operation"
}
VCENTER = {
:name => "vcenter",
@ -101,14 +91,70 @@ cmd=CommandParser::CmdParser.new(ARGV) do
}
############################################################################
# Import clusters
# Global Options
############################################################################
hosts_desc = <<-EOT.unindent
Import vCenter clusters as OpenNebula hosts
cmd_options=CommandParser::OPTIONS-[CommandParser::VERBOSE]
set :option, cmd_options+OpenNebulaHelper::CLIENT_OPTIONS
#format :oid, "vCenter Object identifier" do |arg|
# puts arg
#end
############################################################################
# list resources
############################################################################
list_desc = <<-EOT.unindent
Show a list with unimported vCenter objects
EOT
command :hosts, hosts_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do
con_ops = connection_options("Hosts", options)
command :list, list_desc, :options=>[ OBJECT, HOST,VCENTER, USER, PASS ] do
if options[:host] && options[:object]
o = options[:object]
vi_client = VCenterDriver::VIClient.new_from_host(options[:host])
importer = VCenterDriver::VcImporter.new_child(helper.client, vi_client, o)
list = importer.get_list()
helper.list_object(options, list)
else
puts "for the moment is not supported without the proper authentication"
end
exit 0
end
import_desc = <<-EOT.unindent
Import the the desired vCenter object
EOT
command :import, import_desc, :oid, :options=>[ OBJECT, HOST,VCENTER, USER, PASS, USE_DEFAULTS ] do
indexes = args.first
if options[:host] && options[:object]
o = options[:object]
vi_client = VCenterDriver::VIClient.new_from_host(options[:host])
importer = VCenterDriver::VcImporter.new_child(helper.client, vi_client, o)
importer.get_list()
importer.process_import(indexes)
importer.stdout
else
puts "for the moment is not supported without the proper authentication"
end
exit 0
end
############################################################################
# Import clusters
############################################################################
host_desc = <<-EOT.unindent
Import vCenter clusters as OpenNebula hosts
EOT
command :hosts, host_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do
con_ops = helper.connection_options("Hosts", options)
VCenterDriver::Importer.import_clusters(con_ops, options)
@ -123,7 +169,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
EOT
command :templates, templates_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do
con_ops = connection_options("VM Templates", options)
con_ops = helper.connection_options("VM Templates", options)
VCenterDriver::Importer.import_templates(con_ops, options)
@ -151,7 +197,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
EOT
command :networks, network_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do
con_ops = connection_options("Networks", options)
con_ops = helper.connection_options("Networks", options)
VCenterDriver::Importer.import_networks(con_ops, options)
@ -166,7 +212,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
EOT
command :datastores, datastores_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do
con_ops = connection_options("Datastores", options)
con_ops = helper.connection_options("Datastores", options)
VCenterDriver::Importer.import_datastore(con_ops, options)
@ -188,7 +234,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
exit -1
end
con_ops = connection_options("Images", options)
con_ops = helper.connection_options("Images", options)
VCenterDriver::Importer.import_images(con_ops, ds_name, options)

View File

@ -24,6 +24,9 @@ define(function(require) {
var Sunstone = require('sunstone');
var Locale = require('utils/locale');
var VCenterDatastores = require('utils/vcenter/datastores');
var HostsTable = require('tabs/hosts-tab/datatable');
var UniqueId = require('utils/unique-id');
var Notifier = require('utils/notifier');
/*
TEMPLATES
@ -55,6 +58,15 @@ define(function(require) {
this.vCenterDatastores = new VCenterDatastores();
var options = {
'select': true,
'selectOptions': {
'multiple_choice': false,
"filter_fn": function(host) { return host.VM_MAD === "vcenter" && host.IM_MAD === "vcenter"; }
}
};
this.hostsTable = new HostsTable('HostsTable' + UniqueId.id(), options);
BaseFormPanel.call(this);
}
@ -75,38 +87,36 @@ define(function(require) {
function _htmlWizard() {
return TemplateHTML({
'formPanelId': this.formPanelId,
'vCenterHostsHTML': this.hostsTable.dataTableHTML,
'vCenterDatastoresHTML': this.vCenterDatastores.html()
});
}
function _setup(context) {
var that = this;
this.hostsTable.initialize();
this.hostsTable.refreshResourceTableSelect();
$("form.vcenter_credentials", context)
.off('forminvalid.zf.abide').off('formvalid.zf.abide').off("submit");
Foundation.reInit($("form.vcenter_credentials", context));
$("form.vcenter_credentials", context)
.on('forminvalid.zf.abide', function(ev, frm) {
})
.on('formvalid.zf.abide', function(ev, frm) {
Sunstone.enableFormPanelSubmit(TAB_ID);
var vcenter_user = $("#vcenter_user", context).val();
var vcenter_password = $("#vcenter_password", context).val();
var vcenter_host = $("#vcenter_host", context).val();
$(context).off("click", "#get-vcenter-ds");
$(context).on("click", "#get-vcenter-ds", function(){
var selectedHost = that.hostsTable.retrieveResourceTableSelect();
if (selectedHost !== ""){
that.vCenterDatastores.insert({
container: context,
vcenter_user: vcenter_user,
vcenter_password: vcenter_password,
vcenter_host: vcenter_host
selectedHost: selectedHost
});
})
.on("submit", function(ev) {
ev.preventDefault();
});
$("#import_vcenter_datastores", this.parentElement).prop("disabled", false);
}
else {
Notifier.notifyMessage("You need select a vCenter host first");
}
});
$(context).off("click", "#import_vcenter_datastores");
$(context).on("click", "#import_vcenter_datastores", function(){
that.vCenterDatastores.import(context);
return false;
});
return false;
}
@ -122,5 +132,6 @@ define(function(require) {
}
function _onShow(context) {
$("#datastores-tab .submit_button").hide();
}
});

View File

@ -15,30 +15,14 @@
{{! -------------------------------------------------------------------------- }}
<div id="import_datastores_form_wrapper">
<form data-abide novalidate id="{{formPanelId}}Wizard" class="custom creation">
</form>
<form data-abide novalidate class="vcenter_credentials" action="">
<div class="row">
<div class="large-3 medium-6 columns">
<label for="vcenter_host">{{tr "Hostname"}}</label>
<input type="text" name="vcenter_host" id="vcenter_host" required />
</div>
<div class="large-3 medium-6 columns">
<label for="vcenter_user">{{tr "User"}}</label>
<input type="text" name="vcenter_user" id="vcenter_user" required />
</div>
<div class="large-3 medium-6 columns">
<label for="vcenter_password">{{tr "Password"}}</label>
<input type="password" name="vcenter_password" id="vcenter_password" required />
</div>
<div class="large-3 medium-6 columns">
<label>&nbsp;</label>
<button type="submit" class="button radius">
{{tr "Get Datastores"}}
</button>
</div>
</div>
</form>
<div class="row collapse">
{{{vCenterHostsHTML}}}
</div>
<div style="float:left">
<button class="button radius" id="get-vcenter-ds"> {{tr "Get Datastores"}} </button>
<button class="button right success" id="import_vcenter_datastores" disabled>{{tr "Import"}}</button>
</div>
<br><br><br>
<div class="row collapse">
{{{vCenterDatastoresHTML}}}
</div>

View File

@ -17,6 +17,6 @@
<div class="vcenter_datacenter_list">
<span class="fa-stack fa-2x" style="color: #dfdfdf">
<i class="fas fa-cloud fa-stack-2x"></i>
<i class="fa fa-spinner fa-spin fa-stack-1x fa-inverse"></i>
<i class="fas fa-spinner fa-spin fa-stack-1x fa-inverse"></i>
</span>
</div>

View File

@ -16,28 +16,30 @@
define(function(require) {
// Dependencies
var Locale = require('utils/locale');
var OpenNebulaDatastore = require('opennebula/datastore');
var OpenNebulaError = require('opennebula/error');
var DomDataTable = require('utils/dom-datatable');
var Notifier = require('utils/notifier');
var UniqueId = require('utils/unique-id');
var VCenterCommon = require('./vcenter-common');
var Sunstone = require('sunstone');
var Locale = require("utils/locale");
var OpenNebulaDatastore = require("opennebula/datastore");
var OpenNebulaError = require("opennebula/error");
var DomDataTable = require("utils/dom-datatable");
var Notifier = require("utils/notifier");
var UniqueId = require("utils/unique-id");
var VCenterCommon = require("./vcenter-common");
var Sunstone = require("sunstone");
var TemplateHTML = require('hbs!./common/html');
var RowTemplate = require('hbs!./datastores/row');
var EmptyFieldsetHTML = require('hbs!./common/empty-fieldset');
var FieldsetTableHTML = require('hbs!./common/fieldset-table');
var TemplateHTML = require("hbs!./common/html");
var RowTemplate = require("hbs!./datastores/row");
var EmptyFieldsetHTML = require("hbs!./common/empty-fieldset");
var FieldsetTableHTML = require("hbs!./common/fieldset-table");
var path = "/vcenter/datastores";
function VCenterDatastores() {
return this;
}
VCenterDatastores.prototype = {
'html': VCenterCommon.html,
'insert': _fillVCenterDatastores,
'import': _import
"html": VCenterCommon.html,
"insert": _fillVCenterDatastores,
"import": _import
};
VCenterDatastores.prototype.constructor = VCenterDatastores;
@ -47,109 +49,93 @@ define(function(require) {
Retrieve the list of Datastores from vCenter and fill the container with them
opts = {
datacenter: "Datacenter Name",
cluster: "Cluster Name",
container: Jquery div to inject the html,
vcenter_user: vCenter Username,
vcenter_password: vCenter Password,
vcenter_host: vCenter Host
container: JQuery div to inject the html,
selectedHost: Host selected for vCenter credentials
}
*/
*/
function _fillVCenterDatastores(opts) {
this.opts = opts;
var path = '/vcenter/datastores';
var context = $(".vcenter_import", opts.container);
context.html( TemplateHTML({}) );
context.html(TemplateHTML());
context.show();
$.ajax({
url: path,
type: "GET",
data: {timeout: false},
data: { host: opts.selectedHost, timeout: false },
dataType: "json",
headers: {
"X-VCENTER-USER": opts.vcenter_user,
"X-VCENTER-PASSWORD": opts.vcenter_password,
"X-VCENTER-HOST": opts.vcenter_host
},
success: function(response){
$(".vcenter_datacenter_list", context).html("");
$.each(response, function(datacenter_name, elements){
var content;
if (elements.length == 0) {
content = EmptyFieldsetHTML({
title : datacenter_name + ' ' + Locale.tr("DataCenter"),
message : Locale.tr("No new datastores found in this DataCenter")
});
if (response.length === 0){
content = EmptyFieldsetHTML({
title : Locale.tr("vCenter Datastores"),
message : Locale.tr("No new datastores found")
});
$(".vcenter_datacenter_list", context).append(content);
}
$(".vcenter_datacenter_list", context).append(content);
} else {
var tableId = "vcenter_import_table" + UniqueId.id();
content = FieldsetTableHTML({
tableId : tableId,
title : datacenter_name + ' ' + Locale.tr("DataCenter"),
clearImported : Locale.tr("Clear Imported Datastores"),
toggleAdvanced : false,
columns : [
'<input type="checkbox" class="check_all"/>',
Locale.tr("Name"),
Locale.tr("Total MB"),
Locale.tr("Free MB"),
Locale.tr("OpenNebula Cluster IDs"),
""
]
});
else {
var tableId = "vcenter_import_table" + UniqueId.id();
content = FieldsetTableHTML({
title: Locale.tr("vCenter Datastores"),
tableId : tableId,
toggleAdvanced : false,
columns : [
"<input type=\"checkbox\" class=\"check_all\"/>",
Locale.tr("Name"),
Locale.tr("vCenter ref"),
Locale.tr("Datacenter"),
Locale.tr("Total MB"),
Locale.tr("Free MB"),
Locale.tr("OpenNebula Cluster IDs"),
""
]
});
var newdiv = $(content).appendTo($(".vcenter_datacenter_list", context));
var tbody = $('#' + tableId + ' tbody', context);
var newdiv = $(content).appendTo($(".vcenter_datacenter_list", context));
var tbody = $("#" + tableId + " tbody", context);
$.each(elements, function(id, element){
var opts = { name: element.simple_name, cluster: element.cluster, free_mb: element.free_mb, total_mb: element.total_mb };
$.each(response, function(datastore_name, element){
if (element.cluster.length !== 0){
var opts = { name: element.simple_name, vcenter_ref: element.ref, datacenter: element.datacenter, cluster: element.cluster, free_mb: element.free_mb, total_mb: element.total_mb };
var trow = $(RowTemplate(opts)).appendTo(tbody);
$(".check_item", trow).data("import_data", element);
}
});
$(".check_item", trow).data("one_template", element.ds)
$(".check_item", trow).data("one_clusters", element.cluster)
var elementsTable = new DomDataTable(
tableId,
{
actions: false,
info: false,
dataTableOptions: {
"bAutoWidth": false,
"bSortClasses" : false,
"bDeferRender": false,
"ordering": false,
"aoColumnDefs": [
{ "sWidth": "35px", "aTargets": [0] },
],
},
"customTrListener": function(tableObj, tr){ return false; }
});
var elementsTable = new DomDataTable(
tableId,
{
actions: false,
info: false,
dataTableOptions: {
"bAutoWidth": false,
"bSortClasses" : false,
"bDeferRender": false,
//"ordering": true,
"order": [],
"aoColumnDefs": [
{"bSortable": false, "aTargets": [0,3]},
{"bSortable": true, "aTargets": [1,2]},
{"sWidth": "35px", "aTargets": [0]},
]
}
});
elementsTable.initialize();
elementsTable.initialize();
VCenterCommon.setupTable({
context : newdiv,
allSelected : Locale.tr("All %1$s Datastores selected."),
selected: Locale.tr("%1$s Datastores selected.")
});
$("a.vcenter-table-select-all").text(Locale.tr("Select all %1$s Datastores", elements.length));
VCenterCommon.setupTable({
context : newdiv,
allSelected : Locale.tr("All %1$s Datastores selected."),
selected: Locale.tr("%1$s Datastores selected.")
});
context.off('click', '.clear_imported');
context.on('click', '.clear_imported', function() {
_fillVCenterDatastores(opts);
return false;
});
}
});
context.off("click", ".clear_imported");
context.on("click", ".clear_imported", function() {
_fillVCenterDatastores(opts);
return false;
});
}
},
error: function(response){
context.hide();
@ -160,62 +146,46 @@ define(function(require) {
function _import(context) {
var that = this;
$.each($("table.vcenter_import_table", context), function() {
$.each($(this).DataTable().$(".check_item:checked"), function() {
var row_context = $(this).closest("tr");
var vcenter_refs = [];
VCenterCommon.importLoading({context : row_context});
var one_template = $(this).data("one_template");
var one_clusters = $(this).data("one_clusters");
var datastore_ids = [];
if (one_clusters.length > 0) {
$.each(one_template, function(id, element){
var datastore_json = {
"datastore": {
"datastore_raw": this.one
},
"cluster_id" : -1
};
OpenNebulaDatastore.create({
timeout: true,
data: datastore_json,
success: function(request, response) {
datastore_ids.push(response.DATASTORE.ID);
VCenterCommon.importSuccess({
context : row_context,
message : Locale.tr("Datastores created successfully. IDs: %1$s", datastore_ids.join())
});
var table = $("table.vcenter_import_table", context);
$.each(table.DataTable().$(".check_item:checked"), function(){
vcenter_refs.push($(this).data("import_data").ref);
var row_context = $(this).closest("tr");
VCenterCommon.importLoading({context : row_context});
});
vcenter_refs = vcenter_refs.join(",");
var datastore_raw =
"VCENTER_USER=\"" + that.opts.vcenter_user + "\"\n" +
"VCENTER_PASSWORD=\"" + that.opts.vcenter_password + "\"\n" +
"VCENTER_HOST=\"" + that.opts.vcenter_host + "\"\n";
if (vcenter_refs.length === 0){
Notifier.notifyMessage("You must select at least one datastore");
return false;
}
Sunstone.runAction("Datastore.append_template", response.DATASTORE.ID, datastore_raw);
$.each(one_clusters, function(index, cluster_id){
Sunstone.runAction("Cluster.adddatastore",cluster_id,response.DATASTORE.ID);
});
if (one_clusters.length > 0) {
Sunstone.runAction("Cluster.deldatastore",0,response.DATASTORE.ID);
}
},
error: function (request, error_json) {
VCenterCommon.importFailure({
context : row_context,
message : (error_json.error.message || Locale.tr("Cannot contact server: is it running and reachable?"))
});
}
});
});
} else {
VCenterCommon.importFailure({
context : row_context,
message : Locale.tr("You need to import the associated vcenter cluster as one host first.")
$.ajax({
url: path,
type: "POST",
data: { datastores: vcenter_refs, timeout: false },
dataType: "json",
success: function(response){
var success = response.success;
if (success.length !== 0){
$.each(success, function(key, value){
var ds1 = Navigation.link(value.id[0], "datastores-tab", value.id[0]);
var ds2 = Navigation.link(value.id[1], "datastores-tab", value.id[1]);
Notifier.notifyMessage("Datastore " + value.name + " imported as " + ds1 + " " + ds2 + " successfully");
});
}
});
var error = response.error;
if (error.length !== 0){
$.each(error, function(key, value){
Notifier.notifyError("Datastore with ref " + value + " could not be imported");
});
}
$("#get-vcenter-ds").click();
},
error: function (request, error_json) {
Notifier.notifyError(request.responseJSON.error.message);
}
});
}
});

View File

@ -19,13 +19,12 @@
<input type="checkbox" class="check_item"/>
</td>
<td>{{name}}</td>
<td>{{vcenter_ref}}</td>
<td>{{datacenter}}</td>
<td>{{total_mb}}</td>
<td>{{free_mb}}</td>
<td>{{cluster}}</td>
<td>
<span class="vcenter_import_result">
</span>&nbsp;
<span class="vcenter_import_response">
</span>
<span class="vcenter_import_result"></span>
</td>
</tr>

View File

@ -96,7 +96,7 @@ define(function(require) {
$(".vcenter_import_result:not(.success)", opts.context).html(
'<span class="fa-stack" style="color: #dfdfdf">' +
'<i class="fas fa-cloud fa-stack-2x"></i>' +
'<i class="fa fa-spinner fa-spin fa-stack-1x fa-inverse"></i>' +
'<i class="fas fa-spinner fa-spin fa-stack-1x fa-inverse"></i>' +
'</span>');
$(".vcenter_import_result_row", opts.context).show();

View File

@ -27,6 +27,8 @@ MAX_VCENTER_PASSWORD_LENGTH = 22 #This is the maximum length for a vCenter passw
require 'vcenter_driver'
$importer = nil
helpers do
def vcenter_client
hpref = "HTTP-"
@ -86,6 +88,19 @@ helpers do
error code, error.to_json
end
def viclient_from_host
host_id = params["host"]
VCenterDriver::VIClient.new_from_host(host_id) if host_id
end
def new_vcenter_importer(type)
host_id = params["host"]
vi_client = VCenterDriver::VIClient.new_from_host(host_id) if host_id
one_client = OpenNebula::Client.new
$importer = VCenterDriver::VcImporter.new_child(one_client, vi_client, type)
end
# def af_format_response(resp)
# if CloudClient::is_error?(resp)
# logger.error("[OneFlow] " + resp.to_s)
@ -437,37 +452,21 @@ end
get '/vcenter/datastores' do
begin
dc_folder = VCenterDriver::DatacenterFolder.new(vcenter_client)
new_vcenter_importer("datastores")
dpool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool, false)
if dpool.respond_to?(:message)
msg = "Could not get OpenNebula DatastorePool: #{dpool.message}"
logger.error("[vCenter] " + msg)
error = Error.new(msg)
error 404, error.to_json
end
hpool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool, false)
if hpool.respond_to?(:message)
msg = "Could not get OpenNebula HostPool: #{hpool.message}"
logger.error("[vCenter] " + msg)
error = Error.new(msg)
error 404, error.to_json
end
# clean vcenterDriver cache
VCenterDriver::VIHelper.clean_ref_hash("TEMPLATE/VCENTER_CCR_REF")
datastores = dc_folder.get_unimported_datastores(dpool, vcenter_client.vim.host, hpool)
if datastores.nil?
msg = "No datacenter found"
logger.error("[vCenter] " + msg)
error = Error.new(msg)
error 404, error.to_json
end
[200, datastores.to_json]
[200, $importer.get_list.to_json]
rescue Exception => e
logger.error("[vCenter] " + e.message)
error = Error.new(e.message)
error 403, error.to_json
end
end
post '/vcenter/datastores' do
begin
$importer.process_import(params["datastores"])
[200, $importer.output.to_json]
rescue Exception => e
logger.error("[vCenter] " + e.message)
error = Error.new(e.message)

View File

@ -121,43 +121,48 @@ class DatacenterFolder
def get_unimported_datastores(dpool, vcenter_instance_name, hpool)
import_id = 0
ds_objects = {}
vcenter_uuid = get_vcenter_instance_uuid
fetch! if @items.empty? #Get datacenters
#Get datacenters
fetch! if @items.empty?
@items.values.each do |dc|
clusters_in_ds = {}
dc_name = dc.item.name
dc_ref = dc.item._ref
ds_objects[dc_name] = []
datastore_folder = dc.datastore_folder
datastore_folder.fetch!
datastore_folder.items.values.each do |ds|
name, capacity, freeSpace = ds.item.collect("name",
"summary.capacity",
"summary.freeSpace")
name, capacity, freeSpace = ds.item.collect("name", "summary.capacity", "summary.freeSpace")
ds_name = "#{name}"
ds_total_mb = ((capacity.to_i / 1024) / 1024)
ds_free_mb = ((freeSpace.to_i / 1024) / 1024)
ds_ref = ds['_ref']
ds_objects[ds_ref] = {}
ds_objects[ds_ref][:ref] = ds_ref
ds_objects[ds_ref][:import_id] = import_id
ds_objects[ds_ref][:datacenter] = dc_name
ds_objects[ds_ref][:vcenter] = vcenter_instance_name
ds_objects[ds_ref][:simple_name] = "#{ds_name}"
ds_objects[ds_ref][:total_mb] = ds_total_mb
ds_objects[ds_ref][:free_mb] = ds_free_mb
ds_objects[ds_ref][:ds] = []
ds_objects[ds_ref][:cluster] = []
if ds.instance_of? VCenterDriver::Datastore
ds_hash = {}
ds_hash[:simple_name] = "#{ds_name}"
ds_hash[:total_mb] = ds_total_mb
ds_hash[:free_mb] = ds_free_mb
ds_hash[:ds] = []
ds_hash[:cluster] = []
hosts = ds["host"]
hosts.each do |host|
cluster_ref = host.key.parent._ref
if !clusters_in_ds.key?(cluster_ref)
clusters_in_ds[cluster_ref] = nil
# Try to locate cluster ref in host's pool
one_cluster = VCenterDriver::VIHelper.find_by_ref(OpenNebula::HostPool,
"TEMPLATE/VCENTER_CCR_REF",
@ -165,44 +170,32 @@ class DatacenterFolder
vcenter_uuid,
hpool)
if one_cluster
ds_hash[:cluster] << one_cluster["CLUSTER_ID"].to_i
ds_objects[ds_ref][:cluster] << one_cluster["CLUSTER_ID"].to_i
clusters_in_ds[cluster_ref] = one_cluster["CLUSTER_ID"].to_i
end
else
ds_hash[:cluster] << clusters_in_ds[cluster_ref] if clusters_in_ds[cluster_ref] && !ds_hash[:cluster].include?(clusters_in_ds[cluster_ref])
ds_objects[ds_ref][:cluster] << clusters_in_ds[cluster_ref] if clusters_in_ds[cluster_ref] && !ds_objects[ds_ref][:cluster].include?(clusters_in_ds[cluster_ref])
end
end
already_image_ds = VCenterDriver::Storage.exists_one_by_ref_dc_and_type?(ds["_ref"], dc_ref, vcenter_uuid, "IMAGE_DS", dpool)
already_image_ds = VCenterDriver::Storage.exists_one_by_ref_dc_and_type?(ds_ref, dc_ref, vcenter_uuid, "IMAGE_DS", dpool)
if !already_image_ds
ds_hash[:name] = "#{ds_name} [#{vcenter_instance_name} - #{dc_name}] (IMG)"
object = ds.to_one_template(ds_hash, vcenter_uuid, dc_name, dc_ref, "IMAGE_DS")
ds_hash[:ds] << object if !object.nil?
ds_objects[ds_ref][:name] = "#{ds_name} [#{vcenter_instance_name} - #{dc_name}] (IMG)"
object = ds.to_one_template(ds_objects[ds_ref], vcenter_uuid, dc_name, dc_ref, "IMAGE_DS")
ds_objects[ds_ref][:ds] << object if !object.nil?
end
already_system_ds = VCenterDriver::Storage.exists_one_by_ref_dc_and_type?(ds["_ref"], dc_ref, vcenter_uuid, "SYSTEM_DS", dpool)
already_system_ds = VCenterDriver::Storage.exists_one_by_ref_dc_and_type?(ds_ref, dc_ref, vcenter_uuid, "SYSTEM_DS", dpool)
if !already_system_ds
ds_hash[:name] = "#{ds_name} [#{vcenter_instance_name} - #{dc_name}] (SYS)"
object = ds.to_one_template(ds_hash, vcenter_uuid, dc_name, dc_ref, "SYSTEM_DS")
ds_hash[:ds] << object if !object.nil?
ds_objects[ds_ref][:name] = "#{ds_name} [#{vcenter_instance_name} - #{dc_name}] (SYS)"
object = ds.to_one_template(ds_objects[ds_ref], vcenter_uuid, dc_name, dc_ref, "SYSTEM_DS")
ds_objects[ds_ref][:ds] << object if !object.nil?
end
ds_hash[:name] = "#{ds_name} [#{vcenter_instance_name} - #{dc_name}]"
ds_objects[dc_name] << ds_hash if !ds_hash[:ds].empty?
end
if ds.instance_of? VCenterDriver::StoragePod
ds_hash = {}
ds_hash[:simple_name] = "#{ds_name}"
ds_hash[:total_mb] = ds_total_mb
ds_hash[:free_mb] = ds_free_mb
ds_hash[:ds] = []
ds_hash[:cluster] = []
ds_objects[ds_ref][:name] = "#{ds_name} [#{vcenter_instance_name} - #{dc_name}]"
elsif ds.instance_of? VCenterDriver::StoragePod
ds['children'].each do |sp_ds|
hosts = sp_ds.host
hosts.each do |host|
@ -216,25 +209,30 @@ class DatacenterFolder
vcenter_uuid,
hpool)
if one_cluster
ds_hash[:cluster] << one_cluster["CLUSTER_ID"].to_i
ds_objects[ds_ref][:cluster] << one_cluster["CLUSTER_ID"].to_i
clusters_in_ds[cluster_ref] = one_cluster["CLUSTER_ID"].to_i
end
else
ds_hash[:cluster] << clusters_in_ds[cluster_ref] if clusters_in_ds[cluster_ref] && !ds_hash[:cluster].include?(clusters_in_ds[cluster_ref])
ds_objects[ds_ref][:cluster] << clusters_in_ds[cluster_ref] if clusters_in_ds[cluster_ref] && !ds_objects[ds_ref][:cluster].include?(clusters_in_ds[cluster_ref])
end
end
end
already_system_ds = VCenterDriver::Storage.exists_one_by_ref_dc_and_type?(ds["_ref"], dc_ref, vcenter_uuid, "SYSTEM_DS", dpool)
already_system_ds = VCenterDriver::Storage.exists_one_by_ref_dc_and_type?(ds_ref, dc_ref, vcenter_uuid, "SYSTEM_DS", dpool)
if !already_system_ds
ds_hash[:name] = "#{ds_name} [#{vcenter_instance_name} - #{dc_name}] (StorDRS)"
object = ds.to_one_template(ds_hash, vcenter_uuid, dc_name, dc_ref, "SYSTEM_DS")
ds_hash[:ds] << object if !object.nil?
ds_objects[ds_ref][:name] = "#{ds_name} [#{vcenter_instance_name} - #{dc_name}] (StorDRS)"
object = ds.to_one_template(ds_objects[ds_ref], vcenter_uuid, dc_name, dc_ref, "SYSTEM_DS")
ds_objects[ds_ref][:ds] << object if !object.nil?
end
ds_objects[dc_name] << ds_hash if !ds_hash[:ds].empty?
end
if ds_objects[ds_ref][:ds].empty?
ds_objects.delete(ds_ref)
else
import_id += 1
end
end
end
ds_objects

View File

@ -656,4 +656,79 @@ class Datastore < Storage
end
end # class Datastore
class DsImporter < VCenterDriver::VcImporter
def initialize(one_client, vi_client)
super(one_client, vi_client)
@one_class = OpenNebula::Datastore
end
def get_list(&block)
dc_folder = VCenterDriver::DatacenterFolder.new(@vi_client)
# one pool creation
dpool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool, false)
if dpool.respond_to?(:message)
raise "Could not get OpenNebula DatastorePool: #{dpool.message}"
end
# OpenNebula's HostPool
hpool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool, false)
if hpool.respond_to?(:message)
raise "Could not get OpenNebula HostPool: #{hpool.message}"
end
rs = dc_folder.get_unimported_datastores(dpool, @vi_client.vc_name, hpool)
@list = rs
end
def add_cluster(cid, eid)
one_cluster = @info[:clusters][cid]
raise "no cluster defined" unless one_cluster
rc = one_cluster.adddatastore(eid)
end
def remove_default(id)
cid = 0
@info[:clusters][cid] ||= VCenterDriver::VIHelper.one_item(OpenNebula::Cluster, cid.to_s, false)
@info[:clusters][cid].deldatastore(id.to_i)
end
def import(selected)
inner = ->(object, auth) {
one = ""
one << "VCENTER_HOST=\"#{auth[:host]}\"\n"
one << "VCENTER_USER=\"#{auth[:user]}\"\n"
one << "VCENTER_PASSWORD=\"#{auth[:pass]}\"\n"
rc = object.update(one, true)
}
# Datastore info comes in a pair (SYS, IMG)
pair = selected[:ds]
clusters = selected[:cluster]
res = {id: [], name: selected[:simple_name]}
@info[:rollback] = []
pair.each do |ds|
create(ds[:one]) do |one_object|
one_object.info
id = one_object['ID']
res[:id] << id
add_clusters(id, clusters)
inner.call(one_object, @vi_client.get_host_credentials)
end
end
return res
end
def rollback
# not implemented
end
end
end # module VCenterDriver

View File

@ -0,0 +1,124 @@
module VCenterDriver
class VcImporter
attr_accessor :list
protected
########################################
# ABSTRACT INTERFACE
########################################
MESS = "missing method from parent"
def get_list; raise MESS end
def add_cluster(cid, eid) raise MESS end
def remove_default(id) raise MESS end
def import(selected) raise MESS end
def rollback; raise MESS end
########################################
public
########################################
# Constructors
########################################
def initialize(one_client, vi_client)
@vi_client = vi_client
@one_client = one_client
@list = {}
@info = {}
@info[:clusters] = {}
end
def self.new_child(one_client, vi_client, type)
case type
when "datastores"
VCenterDriver::DsImporter.new(one_client, vi_client)
else
raise "unknown object type"
end
end
########################################
def one_str
return @one_class.to_s.split('::').last if @one_class
"OpenNebula object"
end
def stdout
@info[:success].each do |o|
puts "Datastore #{o[:name]} with ids: #{o[:id].join(' ')} created!"
puts
end
@info[:error].each do |index|
e = @info[index][:e]
puts "Error: Couldn't import #{index} due to #{e.message}!"
puts
end
end
def output
{ success: @info[:success], error: @info[:error] }
end
def process_import(indexes, opts = {})
raise "the list is empty" if list_empty?
indexes = indexes.gsub(/\s+/, "").split(",")
@info[:success] = []
@info[:error] = []
indexes.each do |index|
begin
@info[index] = {}
@info[index][:opts] = opts[index]
# select object from importer mem
selected = get_element(index)
@info[:success] << import(selected)
rescue Exception => e
@info[:error] << index
@info[index][:e] = e
rollback
end
end
end
protected
def create(info, &block)
resource = VCenterDriver::VIHelper.new_one_item(@one_class)
message = "Error creating the OpenNebula resource"
rc = resource.allocate(info)
VCenterDriver::VIHelper.check_error(rc, message)
rc = block.call(resource)
end
def list_empty?
@list == {}
end
def get_element(ref)
raise "the list is empty" if list_empty?
return @list[ref] if @list[ref]
raise "#{ref} not found!"
end
def add_clusters(one_id, clusters, &block)
clusters.each do |cid|
@info[:clusters][cid] ||= VCenterDriver::VIHelper.one_item(OpenNebula::Cluster, cid.to_s, false)
rc = add_cluster(cid.to_i, one_id.to_i)
VCenterDriver::VIHelper.check_error(rc, "add element to cluster")
end
remove_default(one_id)
end
end
end

View File

@ -5,10 +5,13 @@ module VCenterDriver
class VIClient
attr_accessor :vim
attr_accessor :rp
attr_accessor :vc_name
def initialize(opts)
def initialize(opts, host_id = -1)
opts = {:insecure => true}.merge(opts)
@host_id = host_id
@vim = RbVmomi::VIM.connect(opts)
@vc_name = opts[:host] if opts[:host]
# Get ccr and get rp
ccr_ref = opts.delete(:ccr)
@ -31,6 +34,21 @@ class VIClient
!!@rp
end
def get_host_credentials()
raise "no host id defined!" if @host_id == -1
host = OpenNebula::Host.new_with_id(@host_id, OpenNebula::Client.new)
rc = host.info
if OpenNebula.is_error?(rc)
raise "Could not get host info for ID: #{host_id} - #{rc.message}"
end
{pass: host["TEMPLATE/VCENTER_PASSWORD"],
user: host["TEMPLATE/VCENTER_USER"],
host: @vc_name }
end
def get_resource_pools(ccr, rp = nil, parent_prefix = "", rp_array = [])
current_rp = ""
@ -115,7 +133,7 @@ class VIClient
:password => password
}
self.new(connection)
self.new(connection, host_id)
rescue Exception => e
raise e

View File

@ -48,6 +48,7 @@ require 'openssl'
# vCenter Library #
# ---------------------------------------------------------------------------- #
require 'vcenter_importer.rb'
require 'memoize'
require 'vi_client'
require 'vi_helper'