1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

F #6439: PCI attach/detach operation

* Adds 2 new API calls one.vm.attachpci and one.vm.detachpci
* The operation is only for POWEROFF VMs
* Adds 2 new actions to register the event in the VM history pci-detach/pci-attach
* Ruby OCA bindings
* onevm cli commands

TODO:
- JAVA and GO bindings
- Sunstone implementation
This commit is contained in:
Ruben S. Montero 2024-01-31 17:37:27 +01:00
parent af0c109c1b
commit 5c4331a4dd
No known key found for this signature in database
GPG Key ID: A0CEA6FA880A1D87
14 changed files with 1000 additions and 34 deletions

View File

@ -528,6 +528,32 @@ public:
int resize(int vid, float cpu, int vcpu, long memory,
const RequestAttributes& ra, std::string& error_str);
/**
* Attach a new PCI device
*
* @param vid the VM id
* @param pci attribute with the PCI device info
* @param ra information about the API call request
* @param error_str Error reason, if any
*
* @return 0 on success, -1 otherwise
*/
int attach_pci(int vid, VectorAttribute * pci, const RequestAttributes& ra,
std::string& err);
/**
* Detach an existing PCI device
*
* @param vid the VM id
* @param pci_id the PCI device ID
* @param pci attribute with the PCI device info
* @param ra information about the API call request
* @param error_str Error reason, if any
*
* @return 0 on success, -1 otherwise
*/
int detach_pci(int vid, int pci_id, const RequestAttributes& ra,
std::string& err);
//--------------------------------------------------------------------------
// DM Actions associated with a VM state transition
//--------------------------------------------------------------------------

View File

@ -44,7 +44,7 @@ public:
};
private:
std::string method;
std::string method;
};
#endif

View File

@ -350,6 +350,48 @@ protected:
RequestAttributes& ra) override;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class VirtualMachineAttachPCI : public RequestManagerVirtualMachine
{
public:
VirtualMachineAttachPCI():
RequestManagerVirtualMachine("one.vm.attachpci",
"Attaches a new PCI device to the virtual machine",
"A:sis")
{
vm_action = VMActions::PCI_ATTACH_ACTION;
}
~VirtualMachineAttachPCI() = default;
protected:
void request_execute(xmlrpc_c::paramList const& pl,
RequestAttributes& ra) override;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class VirtualMachineDetachPCI : public RequestManagerVirtualMachine
{
public:
VirtualMachineDetachPCI():
RequestManagerVirtualMachine("one.vm.detachpci",
"Detaches a PCI from a virtual machine",
"A:sii")
{
vm_action = VMActions::PCI_DETACH_ACTION;
}
~VirtualMachineDetachPCI() = default;
protected:
void request_execute(xmlrpc_c::paramList const& pl,
RequestAttributes& ra) override;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -86,6 +86,8 @@ public:
SCHED_DELETE_ACTION = 55, // "one.vm.scheddelete"
SG_ATTACH_ACTION = 56, // "one.vm.attachsg"
SG_DETACH_ACTION = 57, // "one.vm.detachsg"
PCI_ATTACH_ACTION = 58, // "one.vm.attachpci"
PCI_DETACH_ACTION = 59 // "one.vm.detachpci"
};
static std::string action_to_str(Action action);

View File

@ -1429,13 +1429,35 @@ public:
}
// ------------------------------------------------------------------------
// NIC Hotplug related functions
// NIC/PCI Hotplug related functions
// ------------------------------------------------------------------------
/**
* Checks the attributes of a PCI device
*/
int check_pci_attributes(VectorAttribute * pci, std::string& err);
static int check_pci_attributes(VectorAttribute * pci, std::string& err);
/**
* Get PCI attribute from VM (VectorAttribute form)
*
* @param pci_id of the PCI device
*
* @return pointer to the PCI Attribute
*/
VectorAttribute * get_pci(int pci_id);
/**
* Attach/Detach a PCI attribute to the VM it generates the PCI_ID and VM_BUS
* paratmeters.
*
* @param vpci attribute wih the PCI information
* @param err string
*
* @return 0 on success
*/
int attach_pci(VectorAttribute * vpci, std::string& err);
void detach_pci(VectorAttribute * vpci);
/**
* Generate and attach a new NIC attribute to the VM. This method check
@ -2100,6 +2122,20 @@ private:
*/
bool generate_pci_context(VectorAttribute * context);
/**
* Deletes the PCI (non NIC) related CONTEXT section for the given nic, i.e.
* PCI<id>_ADDRESS
* @param pciid the id of the PCI
*/
void clear_pci_context(VectorAttribute * pci);
/**
* Deletes the PCI (non NIC) related CONTEXT section for the given nic, i.e.
* PCI<id>_ADDRESS
* @param pci device to add context for
*/
void add_pci_context(VectorAttribute * pci);
/**
* Generate the ONE_GATE token & url
* @param context attribute of the VM

246
include/VirtualMachinePCI.h Normal file
View File

@ -0,0 +1,246 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, 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. */
/* -------------------------------------------------------------------------- */
#ifndef VIRTUAL_MACHINE_PCI_H_
#define VIRTUAL_MACHINE_PCI_H_
#include "VirtualMachineAttribute.h"
#include "PoolObjectSQL.h"
class AuthRequest;
/**
* The VirtualMachine PCI attribute
*/
class VirtualMachinePCI : public VirtualMachineAttribute
{
public:
VirtualMachinePCI(VectorAttribute *va, int id):
VirtualMachineAttribute(va, id){};
virtual ~VirtualMachinePCI(){};
/* ---------------------------------------------------------------------- */
/* PCI get/set functions for boolean disk flags */
/* ATTACH */
/* ---------------------------------------------------------------------- */
void set_attach()
{
set_flag("ATTACH");
};
/* ---------------------------------------------------------------------- */
/* PCI attributes */
/* ---------------------------------------------------------------------- */
/**
* Return the disk id ("PCI_ID")
*/
int get_pci_id() const
{
return get_id();
}
/**
* Check if a nic is alias or not
*/
bool is_alias() const
{
return name() == "NIC_ALIAS";
}
/**
* Check if a nic is a PCI
*/
bool is_nic() const
{
std::string type;
if (vector_value("TYPE", type) != 0)
{
return false;
}
one_util::toupper(type);
return type == "NIC";
}
};
/**
* Set of VirtualMachine NIC
*/
class VirtualMachinePCIs : public VirtualMachineAttributeSet
{
public:
/* ---------------------------------------------------------------------- */
/* Constructor and Initialization functions */
/* ---------------------------------------------------------------------- */
/**
* Creates the VirtualMachinePCI set from a Template with PCI=[...]
* attributes
* @param tmpl template with PCI
* @param has_id to use the ID's in PCI=[PCI_ID=...] or autogenerate
*/
VirtualMachinePCIs(Template * tmpl):
VirtualMachineAttributeSet(false)
{
std::vector<VectorAttribute *> pcis;
tmpl->get(PCI_NAME, pcis);
for (auto it = pcis.begin(); it != pcis.end(); )
{
if ( (*it)->vector_value("TYPE") != "NIC" )
{
it = pcis.erase(it);
}
else
{
++it;
}
}
init(pcis, false);
};
/**
* Creates the VirtualMachineNic set from a vector of NIC VectorAttribute
* @param va vector of NIC VectorAttribute
* @param has_id to use the ID's in NIC=[NIC_ID=...] or autogenerate
* @param dispose true to delete the VectorAttributes when the set is
* destroyed
*/
VirtualMachinePCIs(std::vector<VectorAttribute *>& va, bool has_id, bool dispose):
VirtualMachineAttributeSet(dispose)
{
init(va, has_id);
};
/**
* Creates an empty nic set
*/
VirtualMachinePCIs(bool dispose):
VirtualMachineAttributeSet(dispose){};
virtual ~VirtualMachinePCIs(){};
/**
* Function used to initialize the attribute map based on a vector of NIC
*/
void init(std::vector<VectorAttribute *>& vas, bool has_id)
{
if ( has_id )
{
init_attribute_map(PCI_ID_NAME, vas);
}
else
{
init_attribute_map("", vas);
}
}
/* ---------------------------------------------------------------------- */
/* Iterators */
/* ---------------------------------------------------------------------- */
/**
* Generic iterator for the nic set.
*/
class PCIIterator : public AttributeIterator
{
public:
PCIIterator():AttributeIterator(){};
PCIIterator(const AttributeIterator& dit):AttributeIterator(dit){};
virtual ~PCIIterator(){};
VirtualMachinePCI * operator*() const
{
return static_cast<VirtualMachinePCI *>(map_it->second);
}
};
PCIIterator begin()
{
PCIIterator it(ExtendedAttributeSet::begin());
return it;
}
PCIIterator end()
{
PCIIterator it(ExtendedAttributeSet::end());
return it;
}
typedef class PCIIterator pci_iterator;
/* ---------------------------------------------------------------------- */
/* NIC interface */
/* ---------------------------------------------------------------------- */
/**
* Returns the PCI attribute for a network interface
* @param pci_id of the PCI
* @return pointer to the attribute ir null if not found
*/
VirtualMachinePCI * get_pci(int pci_id) const
{
return static_cast<VirtualMachinePCI *>(get_attribute(pci_id));
}
/* ---------------------------------------------------------------------- */
/* Attach PCI interface */
/* ---------------------------------------------------------------------- */
/**
* Clear attach status from the attach PCI (ATTACH=YES) and removes PCI
* from the set
*/
VirtualMachinePCI * delete_attach()
{
return static_cast<VirtualMachinePCI *>(remove_attribute("ATTACH"));
}
/**
* Clear attach status from the attach PCI (ATTACH=YES)
*/
VirtualMachinePCI * clear_attach()
{
return static_cast<VirtualMachinePCI *>(clear_flag("ATTACH"));
}
/**
* Get the attach PCI (ATTACH=YES)
*/
VirtualMachinePCI * get_attach()
{
return static_cast<VirtualMachinePCI *>(get_attribute("ATTACH"));
}
protected:
VirtualMachineAttribute * attribute_factory(VectorAttribute * va,
int id) const
{
return new VirtualMachinePCI(va, id);
};
private:
static const char * PCI_NAME; //"PCI"
static const char * PCI_ID_NAME; //"PCI_ID"
};
#endif /*VIRTUAL_MACHINE_PCI_H_*/

View File

@ -1610,6 +1610,70 @@ CommandParser::CmdParser.new(ARGV) do
'-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
EOT
pci_attach_desc = <<-EOT.unindent
Attaches a PCI to a VM.
You can specify the PCI device with --pci (short_address) or
--pci_device (device ID), --pci_class (class ID) and/or --pci_vendor (vendor ID).
States: POWEROFF
EOT
command :"pci-attach", pci_attach_desc, :vmid,
:options => [
OpenNebulaHelper::FILE,
PCI,
PCI_CLASS,
PCI_VENDOR,
PCI_DEVICE
] do
pci_attrs = [:pci, :pci_device, :pci_vendor, :pci_class].any? do |o|
!options[o].nil?
end
if options[:file]
template = File.read(options[:file])
elsif !(stdin = self.read_stdin).empty?
template = stdin
elsif pci_attrs
pcia = options[:pci]
pcid = options[:pci_device]
pcic = options[:pci_class]
pciv = options[:pci_vendor]
pcis = []
pcis << "SHORT_ADDRESS = \"#{pcia}\"" if pcia
pcis << "DEVICE = \"#{pcid}\"" if pcid
pcis << "CLASS = \"#{pcic}\"" if pcic
pcis << "VENDOR = \"#{pciv}\"" if pciv
template = "PCI = [ #{pcis.join(',')} ]"
else
STDERR.puts 'Provide a PCI description file with --file or the relevant pci options:'
exit(-1)
end
helper.perform_action(args[0], options, 'Attaching PCI device') do |vm|
vm.pci_attach(template)
end
end
pci_detach_desc = <<-EOT.unindent
Detaches a PCI device from a VM
States: POWEROFF
EOT
command :"pci-detach", pci_detach_desc, :vmid, :pciid do
pciid = args[1].to_i
helper.perform_action(args[0], options, 'Detaching PCI') do |vm|
vm.pci_detach(pciid)
end
end
command :ssh,
ssh_desc,
:vmid,

View File

@ -3012,3 +3012,158 @@ int DispatchManager::resize(int vid, float cpu, int vcpu, long memory,
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int DispatchManager::attach_pci(int vid, VectorAttribute * pci,
const RequestAttributes& ra, string& error_str)
{
ostringstream oss;
auto vm = vmpool->get(vid);
if ( vm == nullptr )
{
error_str = "Virtual machine does not exist";
return -1;
}
if (vm->get_state() != VirtualMachine::POWEROFF ||
vm->get_lcm_state() != VirtualMachine::LCM_INIT)
{
error_str = "VM in wrong state, it has to be in poweroff";
return -1;
}
int hid;
if (vm->hasHistory())
{
hid = vm->get_hid();
}
else
{
error_str = "Could not find host information";
return -1;
}
HostShareCapacity sr;
sr.vmid = vid;
sr.pci.push_back(pci);
auto host = hpool->get(hid);
if ( host == nullptr )
{
error_str = "Could not find host information";
return -1;
}
if (!host->add_pci(sr))
{
error_str = "Cannot assign PCI device in host. Check address and free devices";
return -1;
}
if ( vm->attach_pci(pci, error_str) == -1 )
{
return -1;
}
hpool->update(host.get());
close_cp_history(vmpool, vm.get(), VMActions::PCI_ATTACH_ACTION, ra);
vm->log("DiM", Log::INFO, "PCI device successfully attached.");
vmpool->update_search(vm.get());
time_t the_time = time(0);
vm->set_running_etime(the_time);
vmpool->update_history(vm.get());
vmpool->update(vm.get());
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int DispatchManager::detach_pci(int vid, int pci_id, const RequestAttributes& ra,
string& error_str)
{
ostringstream oss;
auto vm = vmpool->get(vid);
if ( vm == nullptr )
{
error_str = "Virtual machine does not exist";
return -1;
}
if (vm->get_state() != VirtualMachine::POWEROFF ||
vm->get_lcm_state() != VirtualMachine::LCM_INIT)
{
error_str = "VM in wrong state, it has to be in poweroff";
return -1;
}
int hid = -1;
if (vm->hasHistory())
{
hid = vm->get_hid();
}
VectorAttribute * vpci = vm->get_pci(pci_id);
if (vpci == nullptr)
{
error_str = "PCI device not found";
return -1;
}
if ( vpci->vector_value("TYPE") == "NIC" )
{
error_str = "Use one.vm.detachnic to detach this PCI device";
return -1;
}
HostShareCapacity sr;
sr.vmid = vid;
sr.pci.push_back(vpci);
if (auto host = hpool->get(hid))
{
host->del_pci(sr);
hpool->update(host.get());
}
vm->detach_pci(vpci);
close_cp_history(vmpool, vm.get(), VMActions::PCI_DETACH_ACTION, ra);
vm->log("DiM", Log::INFO, "PCI device successfully deatached.");
vmpool->update_search(vm.get());
time_t the_time = time(0);
vm->set_running_etime(the_time);
vmpool->update_history(vm.get());
vmpool->update(vm.get());
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -61,7 +61,9 @@ module OpenNebula
:detachsg => 'vm.detachsg',
:backup => 'vm.backup',
:updatenic => 'vm.updatenic',
:backupcancel => 'vm.backupcancel'
:backupcancel => 'vm.backupcancel',
:attachpci => 'vm.attachpci',
:detachpci => 'vm.detachpci'
}
VM_STATE=['INIT', 'PENDING', 'HOLD', 'ACTIVE', 'STOPPED', 'SUSPENDED', 'DONE', 'FAILED',
@ -228,8 +230,68 @@ module OpenNebula
'BACKUP_POWEROFF' => 'back'
}
HISTORY_ACTION=['none', 'migrate', 'live-migrate', 'shutdown', 'shutdown-hard', 'undeploy',
'undeploy-hard', 'hold', 'release', 'stop', 'suspend', 'resume', 'boot', 'delete', 'delete-recreate', 'reboot', 'reboot-hard', 'resched', 'unresched', 'poweroff', 'poweroff-hard', 'disk-attach', 'disk-detach', 'nic-attach', 'nic-detach', 'disk-snapshot-create', 'disk-snapshot-delete', 'terminate', 'terminate-hard', 'disk-resize', 'deploy', 'chown', 'chmod', 'updateconf', 'rename', 'resize', 'update', 'snapshot-resize', 'snapshot-delete', 'snapshot-revert', 'disk-saveas', 'disk-snapshot-revert', 'recover', 'retry', 'monitor', 'disk-snapshot-rename', 'alias-attach', 'alias-detach', 'poweroff-migrate', 'poweroff-hard-migrate', 'backup', 'nic-update']
HISTORY_ACTION=[
'none',
'migrate',
'live-migrate',
'shutdown',
'shutdown-hard',
'undeploy',
'undeploy-hard',
'hold',
'release',
'stop',
'suspend',
'resume',
'boot',
'delete',
'delete-recreate',
'reboot',
'reboot-hard',
'resched',
'unresched',
'poweroff',
'poweroff-hard',
'disk-attach',
'disk-detach',
'nic-attach',
'nic-detach',
'disk-snapshot-create',
'disk-snapshot-delete',
'terminate',
'terminate-hard',
'disk-resize',
'deploy',
'chown',
'chmod',
'updateconf',
'rename',
'resize',
'update',
'snapshot-resize',
'snapshot-delete',
'snapshot-revert',
'disk-saveas',
'disk-snapshot-revert',
'recover',
'retry',
'monitor',
'disk-snapshot-rename',
'alias-attach',
'alias-detach',
'poweroff-migrate',
'poweroff-hard-migrate',
'backup',
'nic-update',
'backup-cancel',
'sched-add',
'sched-update',
'sched-delete',
'sg-attach',
'sg-detach',
'pci-attach',
'pci-detach'
]
EXTERNAL_IP_ATTRS = [
'GUEST_IP',
@ -811,6 +873,24 @@ module OpenNebula
@client.call(VM_METHODS[:backupcancel], @pe_id)
end
# Attaches a PCI to a VM
#
# @param pci [String] Template containing a PCI element
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def pci_attach(pci)
call(VM_METHODS[:attachpci], @pe_id, pci)
end
# Detaches a PCI from a VM
#
# @param nic_id [Integer] Id of the PCI to be detached
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def pci_detach(pci_id)
call(VM_METHODS[:detachpci], @pe_id, pci_id)
end
########################################################################
# Helpers to get VirtualMachine information
########################################################################

View File

@ -350,6 +350,8 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vm_detachsg(new VirtualMachineDetachSG());
xmlrpc_c::methodPtr vm_backup(new VirtualMachineBackup());
xmlrpc_c::methodPtr vm_backupcancel(new VirtualMachineBackupCancel());
xmlrpc_c::methodPtr vm_attachpci(new VirtualMachineAttachPCI());
xmlrpc_c::methodPtr vm_detachpci(new VirtualMachineDetachPCI());
xmlrpc_c::methodPtr vm_pool_acct(new VirtualMachinePoolAccounting());
xmlrpc_c::methodPtr vm_pool_monitoring(new VirtualMachinePoolMonitoring());
@ -615,6 +617,8 @@ void RequestManager::register_xml_methods()
RequestManagerRegistry.addMethod("one.vm.detachsg", vm_detachsg);
RequestManagerRegistry.addMethod("one.vm.backup", vm_backup);
RequestManagerRegistry.addMethod("one.vm.backupcancel", vm_backupcancel);
RequestManagerRegistry.addMethod("one.vm.attachpci", vm_attachpci);
RequestManagerRegistry.addMethod("one.vm.detachpci", vm_detachpci);
RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info);
RequestManagerRegistry.addMethod("one.vmpool.infoextended", vm_pool_info_extended);
@ -1176,23 +1180,23 @@ void RequestManager::register_xml_methods()
if (nebula.is_federation_slave())
{
marketapp_update_pt = new RequestManagerProxy("one.marketapp.update");
marketapp_chmod_pt = new RequestManagerProxy("one.marketapp.chmod");
marketapp_chown_pt = new RequestManagerProxy("one.marketapp.chown");
marketapp_enable_pt = new RequestManagerProxy("one.marketapp.enable");
marketapp_rename_pt = new RequestManagerProxy("one.marketapp.rename");
marketapp_update_pt = new RequestManagerProxy("one.marketapp.update");
marketapp_chmod_pt = new RequestManagerProxy("one.marketapp.chmod");
marketapp_chown_pt = new RequestManagerProxy("one.marketapp.chown");
marketapp_enable_pt = new RequestManagerProxy("one.marketapp.enable");
marketapp_rename_pt = new RequestManagerProxy("one.marketapp.rename");
marketapp_lock_pt = new RequestManagerProxy("one.marketapp.lock");
marketapp_unlock_pt = new RequestManagerProxy("one.marketapp.unlock");
marketapp_unlock_pt = new RequestManagerProxy("one.marketapp.unlock");
}
else
{
marketapp_update_pt = new MarketPlaceAppUpdateTemplate();
marketapp_chmod_pt = new MarketPlaceAppChmod();
marketapp_chown_pt = new MarketPlaceAppChown();
marketapp_enable_pt = new MarketPlaceAppEnable();
marketapp_rename_pt = new MarketPlaceAppRename();
marketapp_update_pt = new MarketPlaceAppUpdateTemplate();
marketapp_chmod_pt = new MarketPlaceAppChmod();
marketapp_chown_pt = new MarketPlaceAppChown();
marketapp_enable_pt = new MarketPlaceAppEnable();
marketapp_rename_pt = new MarketPlaceAppRename();
marketapp_lock_pt = new MarketPlaceAppLock();
marketapp_unlock_pt = new MarketPlaceAppUnlock();
marketapp_unlock_pt = new MarketPlaceAppUnlock();
xmlrpc_c::methodPtr marketapp_updatedb(new MarketPlaceAppUpdateDB());
xmlrpc_c::methodPtr marketapp_dropdb(new MarketPlaceAppDropDB());

View File

@ -4076,3 +4076,163 @@ void VirtualMachineBackupCancel::request_execute(
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachineAttachPCI::request_execute(
xmlrpc_c::paramList const& paramList, RequestAttributes& att)
{
int id = xmlrpc_c::value_int(paramList.getInt(1));
string stmpl = xmlrpc_c::value_string(paramList.getString(2));
// -------------------------------------------------------------------------
// Parse PCI template and check PCI attributes
// -------------------------------------------------------------------------
VirtualMachineTemplate tmpl;
int rc = tmpl.parse_str_or_xml(stmpl, att.resp_msg);
if ( rc != 0 )
{
failure_response(INTERNAL, att);
return;
}
VectorAttribute * pci = tmpl.get("PCI");
if ( pci == nullptr )
{
att.resp_msg = "PCI attribute not found";
failure_response(ACTION, att);
return;
}
else if ( pci->vector_value("TYPE") == "NIC" )
{
att.resp_msg = "Use one.vm.attachnic to attach this PCI device";
failure_response(ACTION, att);
return;
}
else if ( VirtualMachine::check_pci_attributes(pci, att.resp_msg) != 0)
{
failure_response(ACTION, att);
return;
}
// -------------------------------------------------------------------------
// Authorize the operation, restricted attributes
// -------------------------------------------------------------------------
PoolObjectAuth vm_perms;
if (auto vm = Nebula::instance().get_vmpool()->get_ro(id))
{
vm->get_permissions(vm_perms);
}
else
{
att.resp_id = id;
att.resp_obj = PoolObjectSQL::VM;
failure_response(NO_EXISTS, att);
return;
}
AuthRequest ar(att.uid, att.group_ids);
ar.add_auth(att.auth_op, vm_perms);
VirtualMachine::set_auth_request(att.uid, ar, &tmpl, true);
if (UserPool::authorize(ar) == -1)
{
att.resp_msg = ar.message;
failure_response(AUTHORIZATION, att);
return;
}
if (!att.is_admin())
{
string aname;
if (tmpl.check_restricted(aname))
{
att.resp_msg = "PCI includes a restricted attribute " + aname;
failure_response(AUTHORIZATION, att);
return;
}
}
// -------------------------------------------------------------------------
// Perform the attach
// -------------------------------------------------------------------------
rc = dm->attach_pci(id, pci, att, att.resp_msg);
if ( rc != 0 )
{
failure_response(ACTION, att);
}
else
{
success_response(id, att);
}
return;
}
// -----------------------------------------------------------------------------
void VirtualMachineDetachPCI::request_execute(
xmlrpc_c::paramList const& paramList, RequestAttributes& att)
{
int id = xmlrpc_c::value_int(paramList.getInt(1));
int pci_id = xmlrpc_c::value_int(paramList.getInt(2));
// -------------------------------------------------------------------------
// Authorize the operation, restricted attributes
// -------------------------------------------------------------------------
PoolObjectAuth vm_perms;
if (auto vm = Nebula::instance().get_vmpool()->get_ro(id))
{
vm->get_permissions(vm_perms);
}
else
{
att.resp_id = id;
att.resp_obj = PoolObjectSQL::VM;
failure_response(NO_EXISTS, att);
return;
}
AuthRequest ar(att.uid, att.group_ids);
ar.add_auth(att.auth_op, vm_perms);
if (UserPool::authorize(ar) == -1)
{
att.resp_msg = ar.message;
failure_response(AUTHORIZATION, att);
return;
}
// -------------------------------------------------------------------------
// Perform the detach
// -------------------------------------------------------------------------
int rc = dm->detach_pci(id, pci_id, att, att.resp_msg);
if ( rc != 0 )
{
failure_response(ACTION, att);
}
else
{
success_response(id, att);
}
return;
}

View File

@ -220,6 +220,11 @@ int VMActions::set_auth_ops(const string& ops_str,
ops_set.set(SG_ATTACH_ACTION);
ops_set.set(SG_DETACH_ACTION);
}
else if ( the_op == "pci-attach" )
{
ops_set.set(PCI_ATTACH_ACTION);
ops_set.set(PCI_DETACH_ACTION);
}
else
{
error = "Unknown vm operation: " + the_op;
@ -401,6 +406,12 @@ string VMActions::action_to_str(Action action)
case SG_DETACH_ACTION:
st = "sg-detach";
break;
case PCI_ATTACH_ACTION:
st = "pci-attach";
break;
case PCI_DETACH_ACTION:
st = "pci-detach";
break;
case NONE_ACTION:
st = "none";
break;
@ -627,6 +638,14 @@ int VMActions::action_from_str(const string& st, Action& action)
{
action = SG_DETACH_ACTION;
}
else if ( st == "pci-attach")
{
action = PCI_ATTACH_ACTION;
}
else if ( st == "pci-detach")
{
action = PCI_DETACH_ACTION;
}
else
{
action = NONE_ACTION;

View File

@ -3793,6 +3793,94 @@ void VirtualMachine::delete_attach_alias(VirtualMachineNic *nic)
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::attach_pci(VectorAttribute * vpci, string& err)
{
std::vector<const VectorAttribute*> pcis;
int max_pci_id = -1;
obj_template->get("PCI", pcis);
for (const auto& pci: pcis)
{
int pci_id;
pci->vector_value("PCI_ID", pci_id, -1);
if (pci_id > max_pci_id)
{
max_pci_id = pci_id;
}
}
// -------------------------------------------------------------------------
// Setup PCI attribute & Context
// -------------------------------------------------------------------------
Nebula& nd = Nebula::instance();
std::unique_ptr<VectorAttribute> _new_pci(vpci->clone());
string bus;
_new_pci->replace("PCI_ID", max_pci_id + 1);
nd.get_configuration_attribute("PCI_PASSTHROUGH_BUS", bus);
if ( HostSharePCI::set_pci_address(_new_pci.get(), bus, false) != 0 )
{
err = "Wrong BUS in PCI attribute";
return -1;
}
add_pci_context(_new_pci.get());
// -------------------------------------------------------------------------
// Add new nic to template
// -------------------------------------------------------------------------
obj_template->set(_new_pci.release());
return max_pci_id + 1;
}
// -----------------------------------------------------------------------------
VectorAttribute * VirtualMachine::get_pci(int pci_id)
{
std::vector<VectorAttribute*> pcis;
obj_template->get("PCI", pcis);
for (auto& pci: pcis)
{
int id;
pci->vector_value("PCI_ID", id, -1);
if (pci_id == id)
{
return pci;
}
}
return nullptr;
}
// -----------------------------------------------------------------------------
void VirtualMachine::detach_pci(VectorAttribute * pci)
{
// -------------------------------------------------------------------------
// Remove from Template & Context
// -------------------------------------------------------------------------
clear_pci_context(pci);
obj_template->remove(pci);
delete pci;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* VirtualMachine VMGroup interface */

View File

@ -405,7 +405,8 @@ int VirtualMachine::generate_network_context(VectorAttribute* context,
clear_nic_context(nic_id);
continue;
}
else if (get_nic(nic_id)->is_alias()) // If nic was detached and current is alias
// If nic was detached and current is alias
else if (get_nic(nic_id)->is_alias())
{
int parent_id;
@ -482,7 +483,7 @@ static void parse_pci_context_network(const std::vector<ContextVariable>& cvars,
for (const auto& con : cvars)
{
ostringstream cvar;
ostringstream cvar;
cvar << "PCI" << pci_id << "_" << con.context_name;
@ -495,7 +496,7 @@ static void parse_pci_context_network(const std::vector<ContextVariable>& cvars,
if (!cval.empty())
{
context->replace(cvar.str(), cval);
context->replace(cvar.str(), cval);
}
}
}
@ -517,27 +518,70 @@ bool VirtualMachine::generate_pci_context(VectorAttribute * context)
for(int i=0; i<num_vatts; i++)
{
if ( net_context && vatts[i]->vector_value("TYPE") == "NIC" )
{
parse_pci_context_network(NETWORK_CONTEXT, context, vatts[i]);
parse_pci_context_network(NETWORK6_CONTEXT, context, vatts[i]);
}
if ( net_context && vatts[i]->vector_value("TYPE") == "NIC" )
{
parse_pci_context_network(NETWORK_CONTEXT, context, vatts[i]);
parse_pci_context_network(NETWORK6_CONTEXT, context, vatts[i]);
}
ostringstream cvar;
ostringstream cvar;
cvar << "PCI" << vatts[i]->vector_value("PCI_ID") << "_ADDRESS";
cvar << "PCI" << vatts[i]->vector_value("PCI_ID") << "_ADDRESS";
string cval = vatts[i]->vector_value("VM_ADDRESS");
string cval = vatts[i]->vector_value("VM_ADDRESS");
if (!cval.empty())
{
context->replace(cvar.str(), cval);
}
if (!cval.empty())
{
context->replace(cvar.str(), cval);
}
}
return net_context;
}
/* -------------------------------------------------------------------------- */
void VirtualMachine::clear_pci_context(VectorAttribute * pci)
{
VectorAttribute * context = obj_template->get("CONTEXT");
if (context == 0)
{
return;
}
ostringstream att_name;
att_name << "PCI" << pci->vector_value("PCI_ID") << "_ADDRESS";
context->remove(att_name.str());
}
/* -------------------------------------------------------------------------- */
void VirtualMachine::add_pci_context(VectorAttribute * pci)
{
VectorAttribute * context = obj_template->get("CONTEXT");
if (context == 0)
{
return;
}
string addr = pci->vector_value("VM_ADDRESS");
if (addr.empty())
{
return;
}
ostringstream att_name;
att_name << "PCI" << pci->vector_value("PCI_ID") << "_ADDRESS";
context->replace(att_name.str(), addr);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -608,7 +652,7 @@ int VirtualMachine::parse_context(string& error_str, bool all_nics)
return -1;
}
generate_pci_context(context);
generate_pci_context(context);
// -------------------------------------------------------------------------
// Parse FILE_DS variables