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:
parent
af0c109c1b
commit
5c4331a4dd
@ -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
|
||||
//--------------------------------------------------------------------------
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
std::string method;
|
||||
std::string method;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
246
include/VirtualMachinePCI.h
Normal 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_*/
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -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
|
||||
########################################################################
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user