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

F #2427: Add support to NICs with NETWORK_MODE=auto. This commits includes

logic in oned to delay NIC/context resolution till deployment time. Also
scheduler has been extended to use the match-making algorithm to networks.
Sunstone interface changes to select auto networks.
This commit is contained in:
Ruben S. Montero 2018-10-09 11:42:17 +02:00
parent 2bf147f74e
commit 2123afc890
35 changed files with 1807 additions and 181 deletions

View File

@ -33,12 +33,13 @@ class RankScheduler : public Scheduler
{ {
public: public:
RankScheduler():Scheduler(),rp_host(0),rp_ds(0),rp_vm(0){}; RankScheduler():Scheduler(),rp_host(0),rp_ds(0),rp_nics(0), rp_vm(0){};
~RankScheduler() ~RankScheduler()
{ {
delete rp_host; delete rp_host;
delete rp_ds; delete rp_ds;
delete rp_nics;
delete rp_vm; delete rp_vm;
}; };
@ -56,11 +57,16 @@ public:
rp_vm = new UserPriorityPolicy(vmpool, 1.0); rp_vm = new UserPriorityPolicy(vmpool, 1.0);
add_vm_policy(rp_vm); add_vm_policy(rp_vm);
rp_nics = new RankNetworkPolicy(vnetpool, conf.get_nics_policy(), 1.0);
add_nic_policy(rp_nics);
}; };
private: private:
RankPolicy * rp_host; RankPolicy * rp_host;
RankPolicy * rp_ds; RankPolicy * rp_ds;
RankPolicy * rp_nics;
UserPriorityPolicy * rp_vm; UserPriorityPolicy * rp_vm;
}; };

View File

@ -104,6 +104,8 @@ protected:
RequestAttributes& att); RequestAttributes& att);
VirtualMachine * get_vm(int id, RequestAttributes& att); VirtualMachine * get_vm(int id, RequestAttributes& att);
VirtualMachine * get_vm_ro(int id, RequestAttributes& att);
}; };
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@ -133,7 +135,7 @@ public:
VirtualMachineDeploy(): VirtualMachineDeploy():
RequestManagerVirtualMachine("one.vm.deploy", RequestManagerVirtualMachine("one.vm.deploy",
"Deploys a virtual machine", "Deploys a virtual machine",
"A:siibi") "A:siibis")
{ {
auth_op = Nebula::instance().get_vm_auth_op(History::DEPLOY_ACTION); auth_op = Nebula::instance().get_vm_auth_op(History::DEPLOY_ACTION);
}; };

View File

@ -1159,6 +1159,8 @@ public:
* @param files space separated list of paths to be included in the CBD * @param files space separated list of paths to be included in the CBD
* @param disk_id CONTEXT/DISK_ID attribute value * @param disk_id CONTEXT/DISK_ID attribute value
* @param password Password to encrypt the token, if it is set * @param password Password to encrypt the token, if it is set
* @param only_auto boolean to generate context only for vnets
* with NETWORK_MODE = auto
* @return -1 in case of error, 0 if the VM has no context, 1 on success * @return -1 in case of error, 0 if the VM has no context, 1 on success
*/ */
int generate_context(string &files, int &disk_id, const string& password); int generate_context(string &files, int &disk_id, const string& password);
@ -1616,6 +1618,14 @@ public:
disks.clear_cloning_image_id(image_id, source); disks.clear_cloning_image_id(image_id, source);
} }
/**
* Get network leases with NETWORK_MODE = auto for this Virtual Machine
* @pram tmpl with the scheduling results for the auto NICs
* @param estr description if any
* @return 0 if success
*/
int get_auto_network_leases(VirtualMachineTemplate * tmpl, string &estr);
private: private:
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -1948,9 +1958,12 @@ private:
* netowrking updates. * netowrking updates.
* @param context attribute of the VM * @param context attribute of the VM
* @param error string if any * @param error string if any
* @param only_auto boolean to generate context only for vnets
* with NETWORK_MODE = auto
* @return 0 on success * @return 0 on success
*/ */
int generate_network_context(VectorAttribute * context, string& error); int generate_network_context(VectorAttribute * context, string& error,
bool only_auto);
/** /**
* Deletes the NETWORK related CONTEXT section for the given nic, i.e. * Deletes the NETWORK related CONTEXT section for the given nic, i.e.
@ -1979,9 +1992,11 @@ private:
* Parse the "CONTEXT" attribute of the template by substituting * Parse the "CONTEXT" attribute of the template by substituting
* $VARIABLE, $VARIABLE[ATTR] and $VARIABLE[ATTR, ATTR = VALUE] * $VARIABLE, $VARIABLE[ATTR] and $VARIABLE[ATTR, ATTR = VALUE]
* @param error_str Returns the error reason, if any * @param error_str Returns the error reason, if any
* @param only_auto boolean to parse only the context for vnets
* with NETWORK_MODE = auto
* @return 0 on success * @return 0 on success
*/ */
int parse_context(string& error_str); int parse_context(string& error_str, bool all_nics);
/** /**
* Parses the current contents of the context vector attribute, without * Parses the current contents of the context vector attribute, without
@ -1998,7 +2013,7 @@ private:
// Management helpers: NIC, DISK and VMGROUP // Management helpers: NIC, DISK and VMGROUP
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
/** /**
* Get all network leases for this Virtual Machine * Get network leases (no auto NICs, NETWORK_MODE != auto) for this VM
* @return 0 if success * @return 0 if success
*/ */
int get_network_leases(string &error_str); int get_network_leases(string &error_str);

View File

@ -256,6 +256,9 @@ public:
VectorAttribute * nic_default, std::vector<VectorAttribute *>& sgs, VectorAttribute * nic_default, std::vector<VectorAttribute *>& sgs,
std::string& estr); std::string& estr);
int get_auto_network_leases(int vm_id, int uid, VectorAttribute * nic_default,
vector<VectorAttribute*>& sgs, std::string& error_str);
/** /**
* Release all the network leases and SG associated to the set * Release all the network leases and SG associated to the set
* @param vmid of the VM * @param vmid of the VM

View File

@ -246,7 +246,8 @@ EOT
:description => "Networks to attach. To use a network owned by"<< :description => "Networks to attach. To use a network owned by"<<
" other user use user[network]. Additional"<< " other user use user[network]. Additional"<<
" attributes are supported like with the --disk"<< " attributes are supported like with the --disk"<<
" option.", " option. Also you can use auto if you want that" <<
" OpenNebula select automatically the network",
:format => Array :format => Array
}, },
{ {
@ -1241,15 +1242,19 @@ EOT
user, object=*res user, object=*res
template<<"#{section.upcase}=[\n" template<<"#{section.upcase}=[\n"
template<<" #{name.upcase}_UNAME=\"#{user}\",\n" if user if object.casecmp? "auto"
extra_attributes.each do |extra_attribute| template<<" NETWORK_MODE=\"#{object}\"\n"
key, value = extra_attribute.split("=")
template<<" #{key.upcase}=\"#{value}\",\n"
end
if object.match(/^\d+$/)
template<<" #{name.upcase}_ID=#{object}\n"
else else
template<<" #{name.upcase}=\"#{object}\"\n" template<<" #{name.upcase}_UNAME=\"#{user}\",\n" if user
extra_attributes.each do |extra_attribute|
key, value = extra_attribute.split("=")
template<<" #{key.upcase}=\"#{value}\",\n"
end
if object.match(/^\d+$/)
template<<" #{name.upcase}_ID=#{object}\n"
else
template<<" #{name.upcase}=\"#{object}\"\n"
end
end end
template<<"]\n" template<<"]\n"
end if objects end if objects

View File

@ -483,15 +483,21 @@ cmd=CommandParser::CmdParser.new(ARGV) do
EOT EOT
command :deploy, deploy_desc, [:range,:vmid_list], :hostid, [:datastoreid,nil], command :deploy, deploy_desc, [:range,:vmid_list], :hostid, [:datastoreid,nil],
:options=>[ENFORCE] do :options=>[ENFORCE, OneVMHelper::FILE] do
host_id = args[1] host_id = args[1]
verbose = "deploying in host #{host_id}" verbose = "deploying in host #{host_id}"
enforce = options[:enforce].nil? ? false : options[:enforce] enforce = options[:enforce].nil? ? false : options[:enforce]
ds_id = args[2].nil? ? -1 : args[2] ds_id = args[2].nil? ? -1 : args[2]
extra_template = nil
if options[:file]
extra_template = File.read(options[:file])
end
helper.perform_actions(args[0],options,verbose) do |vm| helper.perform_actions(args[0],options,verbose) do |vm|
vm.deploy(host_id, enforce, ds_id) vm.deploy(host_id, enforce, ds_id, extra_template)
end end
end end

View File

@ -645,9 +645,9 @@ public class VirtualMachine extends PoolElement{
* default, set it to -1 * default, set it to -1
* @return If an error occurs the error message contains the reason. * @return If an error occurs the error message contains the reason.
*/ */
public OneResponse deploy(int hostId, boolean enforce, int dsId) public OneResponse deploy(int hostId, boolean enforce, int dsId, String extra_template)
{ {
return client.call(DEPLOY, id, hostId, enforce, dsId); return client.call(DEPLOY, id, hostId, enforce, dsId, extra_template);
} }
/** /**
@ -659,7 +659,7 @@ public class VirtualMachine extends PoolElement{
*/ */
public OneResponse deploy(int hostId) public OneResponse deploy(int hostId)
{ {
return deploy(hostId, false, -1); return deploy(hostId, false, -1, "");
} }
/** /**

View File

@ -341,9 +341,10 @@ module OpenNebula
# #
# @return [nil, OpenNebula::Error] nil in case of success, Error # @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise # otherwise
def deploy(host_id, enforce=false, ds_id=-1) def deploy(host_id, enforce=false, ds_id=-1, extra_template="")
enforce ||= false enforce ||= false
ds_id ||= -1 ds_id ||= -1
extra_template ||= ""
self.info self.info
@ -351,7 +352,8 @@ module OpenNebula
@pe_id, @pe_id,
host_id.to_i, host_id.to_i,
enforce, enforce,
ds_id.to_i) ds_id.to_i,
extra_template)
end end
# Shutdowns an already deployed VM # Shutdowns an already deployed VM

View File

@ -420,7 +420,24 @@ VirtualMachine * RequestManagerVirtualMachine::get_vm(int id,
{ {
VirtualMachine * vm; VirtualMachine * vm;
vm = static_cast<VirtualMachine *>(pool->get(id)); vm = static_cast<VirtualMachinePool *>(pool)->get(id);
if ( vm == 0 )
{
att.resp_id = id;
failure_response(NO_EXISTS, att);
return 0;
}
return vm;
}
VirtualMachine * RequestManagerVirtualMachine::get_vm_ro(int id,
RequestAttributes& att)
{
VirtualMachine * vm;
vm = static_cast<VirtualMachinePool *>(pool)->get_ro(id);
if ( vm == 0 ) if ( vm == 0 )
{ {
@ -735,6 +752,7 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
DatastorePool * dspool = nd.get_dspool(); DatastorePool * dspool = nd.get_dspool();
VirtualMachine * vm; VirtualMachine * vm;
VirtualMachineTemplate tmpl;
string hostname; string hostname;
string vmm_mad; string vmm_mad;
@ -745,13 +763,14 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
PoolObjectAuth * auth_ds_perms; PoolObjectAuth * auth_ds_perms;
string tm_mad; string tm_mad;
string error_str;
bool auth = false; bool auth = false;
bool check_nic_auto = false;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Get request parameters and information about the target host // Get request parameters and information about the target host
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
int id = xmlrpc_c::value_int(paramList.getInt(1)); int id = xmlrpc_c::value_int(paramList.getInt(1));
int hid = xmlrpc_c::value_int(paramList.getInt(2)); int hid = xmlrpc_c::value_int(paramList.getInt(2));
bool enforce = false; bool enforce = false;
@ -767,6 +786,21 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
ds_id = xmlrpc_c::value_int(paramList.getInt(4)); ds_id = xmlrpc_c::value_int(paramList.getInt(4));
} }
if ( paramList.size() > 5 ) // Template with network scheduling results
{
std::string str_tmpl = xmlrpc_c::value_string(paramList.getString(5));
check_nic_auto = !str_tmpl.empty();
int rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg);
if ( rc != 0 )
{
failure_response(INTERNAL, att);
return;
}
}
if (get_host_information(hid, if (get_host_information(hid,
hostname, hostname,
vmm_mad, vmm_mad,
@ -778,11 +812,11 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
return; return;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Get information about the system DS to use (tm_mad & permissions) // Get information about the system DS to use (tm_mad & permissions)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
if ((vm = get_vm_ro(id, att)) == 0)
if ((vm = get_vm(id, att)) == 0)
{ {
return; return;
} }
@ -793,8 +827,13 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
vm->get_action() == History::UNDEPLOY_HARD_ACTION)) vm->get_action() == History::UNDEPLOY_HARD_ACTION))
{ {
ds_id = vm->get_ds_id(); ds_id = vm->get_ds_id();
check_nic_auto = false;
} }
int uid = vm->get_uid();
int gid = vm->get_gid();
vm->unlock(); vm->unlock();
if (is_public_cloud) // Set ds_id to -1 and tm_mad empty(). This is used by if (is_public_cloud) // Set ds_id to -1 and tm_mad empty(). This is used by
@ -867,8 +906,37 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Authorize request // Authorize request
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
if ( check_nic_auto ) //Authorize network schedule and quotas
{
RequestAttributes att_quota(uid, gid, att);
auth = vm_authorization(id, 0, 0, att, &host_perms, auth_ds_perms, 0, auth_op); if (!att.is_admin())
{
string aname;
if (tmpl.check_restricted(aname))
{
att.resp_msg = "NIC includes a restricted attribute " + aname;
failure_response(AUTHORIZATION, att);
return;
}
}
if (!quota_authorization(&tmpl, Quotas::NETWORK, att_quota, att.resp_msg))
{
failure_response(AUTHORIZATION, att);
return;
}
auth = vm_authorization(id, 0, &tmpl, att, &host_perms, auth_ds_perms,0,
auth_op);
}
else
{
auth = vm_authorization(id, 0, 0, att, &host_perms, auth_ds_perms, 0,
auth_op);
}
if (auth == false) if (auth == false)
{ {
@ -907,6 +975,17 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
return; return;
} }
if ( check_nic_auto && vm->get_auto_network_leases(&tmpl, error_str) != 0 )
{
att.resp_msg = error_str;
failure_response(ACTION, att);
vm->unlock();
return;
}
static_cast<VirtualMachinePool *>(pool)->update(vm);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Add deployment dependent attributes to VM // Add deployment dependent attributes to VM
// - volatile disk (selected system DS driver) // - volatile disk (selected system DS driver)

View File

@ -118,14 +118,14 @@ private:
const vector<Resource *> get_match_resources(ObjectXML *obj) const vector<Resource *> get_match_resources(ObjectXML *obj)
{ {
VirtualMachineXML * vm = dynamic_cast<VirtualMachineXML *>(obj); VirtualMachineXML * vm = static_cast<VirtualMachineXML *>(obj);
return vm->get_match_hosts(); return vm->get_match_hosts();
}; };
const string& get_rank(ObjectXML *obj) const string& get_rank(ObjectXML *obj)
{ {
VirtualMachineXML * vm = dynamic_cast<VirtualMachineXML *>(obj); VirtualMachineXML * vm = static_cast<VirtualMachineXML *>(obj);
if (vm->get_rank().empty()) if (vm->get_rank().empty())
{ {
@ -150,14 +150,14 @@ private:
const vector<Resource *> get_match_resources(ObjectXML *obj) const vector<Resource *> get_match_resources(ObjectXML *obj)
{ {
VirtualMachineXML * vm = dynamic_cast<VirtualMachineXML *>(obj); VirtualMachineXML * vm = static_cast<VirtualMachineXML *>(obj);
return vm->get_match_datastores(); return vm->get_match_datastores();
}; };
const string& get_rank(ObjectXML *obj) const string& get_rank(ObjectXML *obj)
{ {
VirtualMachineXML * vm = dynamic_cast<VirtualMachineXML *>(obj); VirtualMachineXML * vm = static_cast<VirtualMachineXML *>(obj);
if (vm->get_ds_rank().empty()) if (vm->get_ds_rank().empty())
{ {
@ -168,4 +168,37 @@ private:
}; };
}; };
class RankNetworkPolicy : public RankPolicy
{
public:
RankNetworkPolicy(VirtualNetworkPoolXML * pool, const string& dr,float w=1.0):
RankPolicy(pool, dr, w){};
~RankNetworkPolicy(){};
private:
const vector<Resource *> get_match_resources(ObjectXML *obj)
{
VirtualMachineNicXML * nic = static_cast<VirtualMachineNicXML *>(obj);
return nic->get_match_networks();
};
const string& get_rank(ObjectXML *obj)
{
VirtualMachineNicXML * nic = static_cast<VirtualMachineNicXML *>(obj);
const std::string& nr = nic->get_rank();
if (nr.empty())
{
return default_rank;
}
return nr;
};
};
#endif /*RANK_POLICY_H_*/ #endif /*RANK_POLICY_H_*/

View File

@ -24,6 +24,7 @@
#include "ClusterPoolXML.h" #include "ClusterPoolXML.h"
#include "DatastorePoolXML.h" #include "DatastorePoolXML.h"
#include "VirtualMachinePoolXML.h" #include "VirtualMachinePoolXML.h"
#include "VirtualNetworkPoolXML.h"
#include "SchedulerPolicy.h" #include "SchedulerPolicy.h"
#include "ActionManager.h" #include "ActionManager.h"
#include "AclXML.h" #include "AclXML.h"
@ -74,6 +75,7 @@ protected:
img_dspool(0), img_dspool(0),
vmpool(0), vmpool(0),
vm_roles_pool(0), vm_roles_pool(0),
vnetpool(0),
vmgpool(0), vmgpool(0),
vmapool(0), vmapool(0),
timer(0), timer(0),
@ -93,6 +95,7 @@ protected:
delete vmpool; delete vmpool;
delete vm_roles_pool; delete vm_roles_pool;
delete vnetpool;
delete vmapool; delete vmapool;
delete dspool; delete dspool;
@ -119,6 +122,8 @@ protected:
VirtualMachinePoolXML * vmpool; VirtualMachinePoolXML * vmpool;
VirtualMachineRolePoolXML * vm_roles_pool; VirtualMachineRolePoolXML * vm_roles_pool;
VirtualNetworkPoolXML * vnetpool;
VMGroupPoolXML * vmgpool; VMGroupPoolXML * vmgpool;
VirtualMachineActionsPoolXML* vmapool; VirtualMachineActionsPoolXML* vmapool;
@ -142,6 +147,11 @@ protected:
vm_policies.push_back(policy); vm_policies.push_back(policy);
} }
void add_nic_policy(SchedulerPolicy *policy)
{
nic_policies.push_back(policy);
}
// --------------------------------------------------------------- // ---------------------------------------------------------------
// Scheduler main methods // Scheduler main methods
// --------------------------------------------------------------- // ---------------------------------------------------------------
@ -182,6 +192,7 @@ private:
vector<SchedulerPolicy *> host_policies; vector<SchedulerPolicy *> host_policies;
vector<SchedulerPolicy *> ds_policies; vector<SchedulerPolicy *> ds_policies;
vector<SchedulerPolicy *> vm_policies; vector<SchedulerPolicy *> vm_policies;
vector<SchedulerPolicy *> nic_policies;
// --------------------------------------------------------------- // ---------------------------------------------------------------
// Configuration attributes // Configuration attributes

View File

@ -34,6 +34,8 @@ public:
string get_ds_policy() const; string get_ds_policy() const;
string get_nics_policy() const;
private: private:
/** /**
* Name for the configuration file, oned.conf * Name for the configuration file, oned.conf

View File

@ -59,8 +59,9 @@ public:
* @param vid the VM id * @param vid the VM id
* @param hid the id of the target host * @param hid the id of the target host
* @param resched the machine is going to be rescheduled * @param resched the machine is going to be rescheduled
* @param extra template with result nics
*/ */
int dispatch(int vid, int hid, int dsid, bool resched) const; int dispatch(int vid, int hid, int dsid, bool resched, const string& extra_template) const;
/** /**
* Update the VM template * Update the VM template

View File

@ -31,6 +31,80 @@ class ImageDatastorePoolXML;
using namespace std; using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class VirtualMachineNicXML : public ObjectXML
{
public:
/**
* Returns a vector of matched datastores
*/
const vector<Resource *>& get_match_networks()
{
return match_networks.get_resources();
}
/**
* Adds a matching network
* @param oid of the network
*/
void add_match_network(int oid)
{
match_networks.add_resource(oid);
}
/**
* Sort the matched networks for the VM
*/
void sort_match_networks()
{
match_networks.sort_resources();
}
/**
* Removes the matched networks
*/
void clear_match_networks()
{
match_networks.clear();
}
//--------------------------------------------------------------------------
// Rank & requirements set & get
//--------------------------------------------------------------------------
const string& get_rank()
{
return rank;
};
void set_rank(const string& r)
{
rank = r;
}
const string& get_requirements()
{
return requirements;
};
void set_requirements(const string& r)
{
requirements = r;
}
private:
ResourceMatch match_networks;
string rank;
string requirements;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class VirtualMachineXML : public ObjectXML class VirtualMachineXML : public ObjectXML
{ {
public: public:
@ -106,6 +180,20 @@ public:
return ds_rank; return ds_rank;
}; };
const string& get_nic_rank(int nic_id)
{
static std::string es;
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
if ( it != nics.end() )
{
return it->second->get_rank();
}
return es;
};
const string& get_requirements() const string& get_requirements()
{ {
return requirements; return requirements;
@ -116,6 +204,20 @@ public:
return ds_requirements; return ds_requirements;
} }
const string& get_nic_requirements(int nic_id)
{
static std::string es;
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
if ( it != nics.end() )
{
return it->second->get_requirements();
}
return es;
}
/** /**
* Return VM usage requirments * Return VM usage requirments
*/ */
@ -204,6 +306,20 @@ public:
match_datastores.add_resource(oid); match_datastores.add_resource(oid);
} }
/**
* Adds a matching network
* @param oid of the network
*/
void add_match_network(int oid, int nic_id)
{
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
if ( it != nics.end() )
{
it->second->add_match_network(oid);
}
}
/** /**
* Returns a vector of matched hosts * Returns a vector of matched hosts
*/ */
@ -220,6 +336,40 @@ public:
return match_datastores.get_resources(); return match_datastores.get_resources();
} }
/**
* Returns a vector of matched networks
*/
const vector<Resource *>& get_match_networks(int nic_id)
{
static std::vector<Resource *> ev;
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
if ( it != nics.end() )
{
return it->second->get_match_networks();
}
return ev;
}
/**
* Returns a VirtualMachineNicXML
*/
VirtualMachineNicXML * get_nic(int nic_id)
{
VirtualMachineNicXML * n = 0;
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
if ( it != nics.end() )
{
n = it->second;
}
return n;
}
/** /**
* Sort the matched hosts for the VM * Sort the matched hosts for the VM
*/ */
@ -236,6 +386,19 @@ public:
match_datastores.sort_resources(); match_datastores.sort_resources();
} }
/**
* Sort the matched networks for the VM
*/
void sort_match_networks(int nic_id)
{
std::map<int, VirtualMachineNicXML *>::iterator it = nics.find(nic_id);
if ( it != nics.end() )
{
it->second->sort_match_networks();
}
}
/** /**
* Removes the matched hosts * Removes the matched hosts
*/ */
@ -252,6 +415,19 @@ public:
match_datastores.clear(); match_datastores.clear();
} }
/**
* Removes the matched networks
*/
void clear_match_networks()
{
map<int, VirtualMachineNicXML *>::iterator it;
for (it = nics.begin(); it != nics.end(); it++ )
{
it->second->clear_match_networks();
}
}
/** /**
* Marks the VM to be only deployed on public cloud hosts * Marks the VM to be only deployed on public cloud hosts
*/ */
@ -368,6 +544,14 @@ public:
*/ */
bool clear_log(); bool clear_log();
/**
* Return ids of NICs with NETWORK_MODE=auto (i.e. need to schedule networks)
*/
set<int> get_nics_ids()
{
return nics_ids_auto;
}
protected: protected:
/** /**
@ -383,6 +567,7 @@ protected:
ResourceMatch match_datastores; ResourceMatch match_datastores;
bool only_public_cloud; bool only_public_cloud;
set<int> affined_vms; set<int> affined_vms;
@ -415,9 +600,12 @@ protected:
string ds_requirements; string ds_requirements;
string ds_rank; string ds_rank;
set<int> nics_ids_auto;
map<int, VirtualMachineNicXML *> nics;
VirtualMachineTemplate * vm_template; /**< The VM template */ VirtualMachineTemplate * vm_template; /**< The VM template */
VirtualMachineTemplate * user_template; /**< The VM user template */ VirtualMachineTemplate * user_template; /**< The VM user template */
}; };
#endif /* VM_XML_H_ */ #endif /* VM_XML_H_ */

View File

@ -0,0 +1,59 @@
/* -------------------------------------------------------------------------- */
/* 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. */
/* -------------------------------------------------------------------------- */
#ifndef VNET_POOL_XML_H_
#define VNET_POOL_XML_H_
#include "PoolXML.h"
#include "VirtualNetworkXML.h"
using namespace std;
class VirtualNetworkPoolXML : public PoolXML
{
public:
VirtualNetworkPoolXML(Client* client):PoolXML(client) {};
~VirtualNetworkPoolXML(){};
int set_up();
/**
* Gets an object from the pool
* @param oid the object unique identifier
*
* @return a pointer to the object, 0 in case of failure
*/
VirtualNetworkXML * get(int oid) const
{
return static_cast<VirtualNetworkXML *>(PoolXML::get(oid));
};
protected:
int get_suitable_nodes(vector<xmlNodePtr>& content)
{
return get_nodes("/VNET_POOL/VNET", content);
};
void add_object(xmlNodePtr node);
int load_info(xmlrpc_c::value &result);
};
#endif /* VNET_POOL_XML_H_ */

View File

@ -0,0 +1,122 @@
/* -------------------------------------------------------------------------- */
/* 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. */
/* -------------------------------------------------------------------------- */
#ifndef VNET_XML_H_
#define VNET_XML_H_
#include "ObjectXML.h"
#include "PoolObjectAuth.h"
using namespace std;
class VirtualNetworkXML : public ObjectXML
{
public:
VirtualNetworkXML(const string &xml_doc):ObjectXML(xml_doc)
{
init_attributes();
};
VirtualNetworkXML(const xmlNodePtr node):ObjectXML(node)
{
init_attributes();
};
/**
* Tests whether a new NIC can be attached to a vnet
* @param error error message
* @return true if the VNET can host the VM
*/
bool test_leases(string & error) const;
/**
* Tests whether a new NIC can be attached to a vnet
* @param num_leases num leases needs by VM
* @return true if the VNET can host the VM
*/
bool test_leases() const
{
string tmp_st;
return test_leases(tmp_st);
}
/**
* Adds a new lease to the VNET
*/
void add_lease()
{
free_leases--;
};
void rollback_leases(int num_leases)
{
free_leases += num_leases;
}
int get_oid() const
{
return oid;
};
bool is_in_cluster(int cid) const
{
return cluster_ids.count(cid) != 0;
};
/**
* Fills a auth class to perform an authZ/authN request based on the object
* attributes
* @param auths to be filled
*/
void get_permissions(PoolObjectAuth& auth);
/**
* Prints the Virtual Network information to an output stream. This function is used
* for logging purposes.
*/
friend ostream& operator<<(ostream& o, const VirtualNetworkXML& p);
private:
int oid;
set<int> cluster_ids;
int uid;
int gid;
int owner_u;
int owner_m;
int owner_a;
int group_u;
int group_m;
int group_a;
int other_u;
int other_m;
int other_a;
int free_leases;
static const char *net_paths[]; /**< paths for search function */
static int net_num_paths; /**< number of paths*/
void init_attributes();
};
#endif /* VNET_XML_H_ */

View File

@ -31,7 +31,9 @@ source_files=[
'VMGroupPoolXML.cc', 'VMGroupPoolXML.cc',
'VMGroupXML.cc', 'VMGroupXML.cc',
'DatastorePoolXML.cc', 'DatastorePoolXML.cc',
'DatastoreXML.cc'] 'DatastoreXML.cc',
'VirtualNetworkPoolXML.cc',
'VirtualNetworkXML.cc']
# Build library # Build library
sched_env.StaticLibrary(lib_name, source_files) sched_env.StaticLibrary(lib_name, source_files)

View File

@ -148,7 +148,7 @@ int VirtualMachinePoolXML::load_info(xmlrpc_c::value &result)
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
int VirtualMachinePoolXML::dispatch(int vid, int hid, int dsid, bool resched) const int VirtualMachinePoolXML::dispatch(int vid, int hid, int dsid, bool resched,const string& extra_template) const
{ {
xmlrpc_c::value deploy_result; xmlrpc_c::value deploy_result;
@ -174,12 +174,13 @@ int VirtualMachinePoolXML::dispatch(int vid, int hid, int dsid, bool resched) co
else else
{ {
client->call("one.vm.deploy", // methodName client->call("one.vm.deploy", // methodName
"iibi", // arguments format "iibis", // arguments format
&deploy_result, // resultP &deploy_result, // resultP
vid, // argument 1 (VM) vid, // argument 1 (VM)
hid, // argument 2 (HOST) hid, // argument 2 (HOST)
false, // argument 3 (ENFORCE) false, // argument 3 (ENFORCE)
dsid); // argument 5 (SYSTEM SD) dsid, // argument 5 (SYSTEM SD)
extra_template.c_str()); // argument 6 (EXTRA TEMPLATE)
} }
} }
catch (exception const& e) catch (exception const& e)

View File

@ -99,6 +99,55 @@ void VirtualMachineXML::init_attributes()
ds_requirements = automatic_ds_requirements; ds_requirements = automatic_ds_requirements;
} }
// ------------------- NIC REQUIREMENTS -------------------------------------
if (get_nodes("/VM/TEMPLATE/NIC", nodes) > 0)
{
std::string net_mode;
vector<xmlNodePtr>::iterator it_nodes;
for (it_nodes = nodes.begin(); it_nodes != nodes.end(); ++it_nodes)
{
VirtualMachineTemplate * nic_template = new VirtualMachineTemplate;
nic_template->from_xml_node(*it_nodes);
bool rc = nic_template->get("NETWORK_MODE", net_mode);
one_util::toupper(net_mode);
if ( rc && net_mode == "AUTO" )
{
std::string requirements, rank;
int nic_id;
nic_template->get("NIC_ID", nic_id);
nics_ids_auto.insert(nic_id);
VirtualMachineNicXML * the_nic = new VirtualMachineNicXML();
nics.insert(make_pair(nic_id, the_nic));
if ( nic_template->get("SCHED_REQUIREMENTS", requirements) )
{
the_nic->set_requirements(requirements);
}
if ( nic_template->get("SCHED_RANK", rank) )
{
the_nic->set_rank(rank);
}
}
delete nic_template;
}
free_nodes(nodes);
}
nodes.clear();
// ---------------- HISTORY HID, DSID, RESCHED & TEMPLATE ------------------ // ---------------- HISTORY HID, DSID, RESCHED & TEMPLATE ------------------
xpath(hid, "/VM/HISTORY_RECORDS/HISTORY/HID", -1); xpath(hid, "/VM/HISTORY_RECORDS/HISTORY/HID", -1);
@ -200,6 +249,25 @@ ostream& operator<<(ostream& os, VirtualMachineXML& vm)
os << endl; os << endl;
set<int> nics_ids = vm.get_nics_ids();
for (set<int>::iterator it = nics_ids.begin(); it != nics_ids.end(); it++)
{
os << "\tNIC_ID: "<< *it << endl
<< "\t-----------------------------------" << endl;
os << "\tPRI\tID - NETWORKS"<< endl
<< "\t------------------------" << endl;
const vector<Resource *> net_resources = vm.nics[*it]->get_match_networks();
for (i = net_resources.rbegin(); i != net_resources.rend() ; i++)
{
os << "\t" << (*i)->priority << "\t" << (*i)->oid << endl;
}
os << endl;
}
return os; return os;
}; };

View File

@ -0,0 +1,102 @@
/* -------------------------------------------------------------------------- */
/* 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. */
/* -------------------------------------------------------------------------- */
#include "VirtualNetworkPoolXML.h"
#include <iomanip>
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetworkPoolXML::set_up()
{
ostringstream oss;
int rc;
rc = PoolXML::set_up();
if ( rc == 0 )
{
if (NebulaLog::log_level() >= Log::DDDEBUG)
{
oss << "Discovered VNETS:" << endl;
oss << right << setw(8) << "ID" << " "
<< right << setw(8) << "Leases" << " " << endl
<< setw(20) << setfill('-') << "-" << setfill(' ') << endl;
map<int, ObjectXML*>::iterator it;
for (it=objects.begin();it!=objects.end();it++)
{
VirtualNetworkXML * n = dynamic_cast<VirtualNetworkXML *>(it->second);
oss << *n << endl;
}
}
else
{
oss << "Discovered " << objects.size() << " vnets.";
}
NebulaLog::log("VNET",Log::DEBUG,oss);
}
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualNetworkPoolXML::add_object(xmlNodePtr node)
{
if ( node == 0 || node->children == 0 )
{
NebulaLog::log("VNET",Log::ERROR,
"XML Node does not represent a valid VNET");
return;
}
VirtualNetworkXML* vnet = new VirtualNetworkXML(node);
objects.insert(pair<int,ObjectXML*>(vnet->get_oid(), vnet));
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetworkPoolXML::load_info(xmlrpc_c::value &result)
{
try
{
client->call("one.vnpool.info", "iii", &result, -2, -1, -1);
return 0;
}
catch (exception const& e)
{
ostringstream oss;
oss << "Exception raised: " << e.what();
NebulaLog::log("VNET", Log::ERROR, oss);
return -1;
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -0,0 +1,146 @@
/* -------------------------------------------------------------------------- */
/* 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. */
/* -------------------------------------------------------------------------- */
#include <sstream>
#include <iomanip>
#include "VirtualNetworkXML.h"
#include "NebulaUtil.h"
#include "NebulaLog.h"
#include "ObjectCollection.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetworkXML::net_num_paths = 2;
const char * VirtualNetworkXML::net_paths[] = {
"/VNET/TEMPLATE/",
"/VNET/"
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualNetworkXML::init_attributes()
{
xpath(oid, "/VNET/ID", -1);
ObjectCollection cluster_collection("CLUSTERS");
cluster_collection.from_xml(this, "/VNET/");
cluster_ids = cluster_collection.clone();
xpath(uid, "/VNET/UID", -1);
xpath(gid, "/VNET/GID", -1);
xpath(owner_u, "/VNET/PERMISSIONS/OWNER_U", 0);
xpath(owner_m, "/VNET/PERMISSIONS/OWNER_M", 0);
xpath(owner_a, "/VNET/PERMISSIONS/OWNER_A", 0);
xpath(group_u, "/VNET/PERMISSIONS/GROUP_U", 0);
xpath(group_m, "/VNET/PERMISSIONS/GROUP_M", 0);
xpath(group_a, "/VNET/PERMISSIONS/GROUP_A", 0);
xpath(other_u, "/VNET/PERMISSIONS/OTHER_U", 0);
xpath(other_m, "/VNET/PERMISSIONS/OTHER_M", 0);
xpath(other_a, "/VNET/PERMISSIONS/OTHER_A", 0);
//-------------------- AR_POOL used leases ------------------------------
vector<string> ar_size;
vector<string> ar_used_leases;
xpaths(ar_size,"/VNET/AR_POOL/AR/SIZE");
xpaths(ar_used_leases,"/VNET/AR_POOL/AR/USED_LEASES");
int used_leases;
free_leases = 0;
for (size_t i = 0; i < ar_size.size() ; i++)
{
free_leases += atoi(ar_size[i].c_str());
}
xpath(used_leases, "/VNET/USED_LEASES", 0);
free_leases -= used_leases;
ObjectXML::paths = net_paths;
ObjectXML::num_paths = net_num_paths;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool VirtualNetworkXML::test_leases(string & error) const
{
bool fits = (free_leases > 0);
if (!fits)
{
if (NebulaLog::log_level() >= Log::DDEBUG)
{
ostringstream oss;
oss << "Not enough free leases. "
<< "Requested: 1 LEASES, "
<< "Available: " << free_leases << " LEASES";
error = oss.str();
}
else
{
error = "Not enough free leases.";
}
}
return fits;
}
void VirtualNetworkXML::get_permissions(PoolObjectAuth& auth)
{
auth.obj_type = PoolObjectSQL::NET;
auth.oid = oid;
auth.uid = uid;
auth.gid = gid;
auth.cids = cluster_ids;
auth.owner_u = owner_u;
auth.owner_m = owner_m;
auth.owner_a = owner_a;
auth.group_u = group_u;
auth.group_m = group_m;
auth.group_a = group_a;
auth.other_u = other_u;
auth.other_m = other_m;
auth.other_a = other_a;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ostream& operator<<(ostream& o, const VirtualNetworkXML& p)
{
o << right << setw(8) << p.oid << " "
<< right << setw(8) << p.free_leases << " ";
return o;
}

View File

@ -325,6 +325,8 @@ void Scheduler::start()
vm_roles_pool = new VirtualMachineRolePoolXML(client, machines_limit); vm_roles_pool = new VirtualMachineRolePoolXML(client, machines_limit);
vmpool = new VirtualMachinePoolXML(client, machines_limit, live_rescheds==1); vmpool = new VirtualMachinePoolXML(client, machines_limit, live_rescheds==1);
vnetpool = new VirtualNetworkPoolXML(client);
vmgpool = new VMGroupPoolXML(client); vmgpool = new VMGroupPoolXML(client);
vmapool = new VirtualMachineActionsPoolXML(client, machines_limit); vmapool = new VirtualMachineActionsPoolXML(client, machines_limit);
@ -482,6 +484,13 @@ int Scheduler::set_up_pools()
return rc; return rc;
} }
rc = vnetpool->set_up();
if ( rc != 0 )
{
return rc;
}
return 0; return 0;
}; };
@ -716,6 +725,107 @@ static bool match_system_ds(AclXML * acls, UserPoolXML * upool,
return true; return true;
} }
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* Match network for this VM that:
* 1. Meet user/policy requirements
* 2. Have enough leases to host the VM
*
* @param acl pool
* @param users the user pool
* @param vm the virtual machine
* @param vdisk vm requirement
* @param net to evaluate vm assgiment
* @param n_auth number of nets authorized for the user, incremented if needed
* @param n_error number of requirement errors, incremented if needed
* @param n_matched number of networks that fullfil VM sched_requirements
* @param n_fits number of networks with leases that fits the VM requirements
* @param error, string describing why the host is not valid
* @return true for a positive match
*/
static bool match_network(AclXML * acls, UserPoolXML * upool,
VirtualMachineXML* vm, int nic_id, VirtualNetworkXML * net, int& n_auth,
int& n_error, int& n_fits, int &n_matched, string &error)
{
// -------------------------------------------------------------------------
// Check if user is authorized
// -------------------------------------------------------------------------
if ( vm->get_uid() != 0 && vm->get_gid() != 0 )
{
PoolObjectAuth netperms;
net->get_permissions(netperms);
UserXML * user = upool->get(vm->get_uid());
if (user == 0)
{
error = "User does not exists.";
return false;
}
const vector<int> vgids = user->get_gids();
set<int> gids(vgids.begin(), vgids.end());
if ( !acls->authorize(vm->get_uid(), gids, netperms, AuthRequest::USE))
{
error = "Permission denied.";
return false;
}
}
n_auth++;
if ( !net->test_leases(error) )
{
return false;
}
n_fits++;
// -------------------------------------------------------------------------
// Evaluate VM requirements for NICS
// -------------------------------------------------------------------------
if (!vm->get_nic_requirements(nic_id).empty())
{
char * estr;
bool matched = true;
if (net->eval_bool(vm->get_nic_requirements(nic_id), matched, &estr) != 0)
{
ostringstream oss;
n_error++;
oss << "Error in REQUIREMENTS - NIC_ID(" << nic_id <<"): '"
<< vm->get_nic_requirements(nic_id) << "', error: " << estr;
vm->log(oss.str());
error = oss.str();
free(estr);
return false;
}
if (matched == false)
{
error = "It does not fulfill NIC REQUIREMENTS.";
return false;
}
}
n_matched++;
return true;
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
static void log_match(int vid, const string& msg) static void log_match(int vid, const string& msg)
@ -747,6 +857,7 @@ void Scheduler::match_schedule()
HostXML * host; HostXML * host;
DatastoreXML *ds; DatastoreXML *ds;
VirtualNetworkXML *net;
string m_error; string m_error;
@ -759,12 +870,15 @@ void Scheduler::match_schedule()
const map<int, ObjectXML*> hosts = hpool->get_objects(); const map<int, ObjectXML*> hosts = hpool->get_objects();
const map<int, ObjectXML*> datastores = dspool->get_objects(); const map<int, ObjectXML*> datastores = dspool->get_objects();
const map<int, ObjectXML*> users = upool->get_objects(); const map<int, ObjectXML*> users = upool->get_objects();
const map<int, ObjectXML*> nets = vnetpool->get_objects();
double total_cl_match_time = 0; double total_cl_match_time = 0;
double total_host_match_time = 0; double total_host_match_time = 0;
double total_host_rank_time = 0; double total_host_rank_time = 0;
double total_ds_match_time = 0; double total_ds_match_time = 0;
double total_ds_rank_time = 0; double total_ds_rank_time = 0;
double total_net_match_time = 0;
double total_net_rank_time = 0;
time_t stime = time(0); time_t stime = time(0);
@ -1014,6 +1128,117 @@ void Scheduler::match_schedule()
vm->sort_match_datastores(); vm->sort_match_datastores();
total_ds_rank_time += profile(false); total_ds_rank_time += profile(false);
// ---------------------------------------------------------------------
// Match Networks for this VM
// ---------------------------------------------------------------------
profile(true);
set<int>::iterator it_nic;
set<int> nics_ids = vm->get_nics_ids();
bool not_matched = false;
for (it_nic = nics_ids.begin(); it_nic != nics_ids.end(); ++it_nic)
{
n_resources = 0;
n_auth = 0;
n_matched = 0;
n_error = 0;
n_fits = 0;
int nic_id = *it_nic;
for (obj_it = nets.begin(); obj_it != nets.end(); ++obj_it)
{
net = static_cast<VirtualNetworkXML *>(obj_it->second);
if (match_network(acls, upool, vm, nic_id, net, n_auth, n_error,
n_fits, n_matched, m_error))
{
vm->add_match_network(net->get_oid(), nic_id);
n_resources++;
}
else
{
if (n_error > 0)
{
log_match(vm->get_oid(), "Cannot schedule VM. " + m_error);
break;
}
else if (NebulaLog::log_level() >= Log::DDEBUG)
{
ostringstream oss;
oss << "Network " << net->get_oid() << " discarded for VM "
<< vm->get_oid() << " and NIC " << nic_id << ". " << m_error;
NebulaLog::log("SCHED", Log::DDEBUG, oss);
}
}
}
if (n_resources == 0)
{
if (n_error == 0)//No syntax error
{
if (nets.size() == 0)
{
vm->log("No networks found to run VMs");
}
else if (n_auth == 0)
{
vm->log("User is not authorized to use any network");
}
else if (n_fits == 0)
{
vm->log("No network with enough capacity for the VM");
}
else if (n_matched == 0)
{
ostringstream oss;
oss << "No network meet leases "
<< "and SCHED_NIC_REQUIREMENTS: "
<< vm->get_nic_requirements(nic_id);
vm->log(oss.str());
}
}
vm->clear_match_hosts();
vm->clear_match_datastores();
vmpool->update(vm);
log_match(vm->get_oid(), "Cannot schedule VM, there is no "
"suitable network.");
break;
not_matched = true;
}
profile(true);
for (it = nic_policies.begin() ; it != nic_policies.end() ; it++)
{
(*it)->schedule(vm->get_nic(nic_id));
}
vm->sort_match_networks(nic_id);
total_net_rank_time += profile(false);
}
if ( not_matched )
{
continue;
}
total_net_match_time += profile(false);
} }
if (NebulaLog::log_level() >= Log::DDEBUG) if (NebulaLog::log_level() >= Log::DDEBUG)
@ -1021,20 +1246,24 @@ void Scheduler::match_schedule()
ostringstream oss; ostringstream oss;
oss << "Match Making statistics:\n" oss << "Match Making statistics:\n"
<< "\tNumber of VMs: " << "\tNumber of VMs: "
<< pending_vms.size() << endl << pending_vms.size() << endl
<< "\tTotal time: " << "\tTotal time: "
<< one_util::float_to_str(time(0) - stime) << "s" << endl << one_util::float_to_str(time(0) - stime) << "s" << endl
<< "\tTotal Cluster Match time: " << "\tTotal Cluster Match time: "
<< one_util::float_to_str(total_cl_match_time) << "s" << endl << one_util::float_to_str(total_cl_match_time) << "s" << endl
<< "\tTotal Host Match time: " << "\tTotal Host Match time: "
<< one_util::float_to_str(total_host_match_time) << "s" << endl << one_util::float_to_str(total_host_match_time) << "s" << endl
<< "\tTotal Host Ranking time: " << "\tTotal Host Ranking time: "
<< one_util::float_to_str(total_host_rank_time) << "s" << endl << one_util::float_to_str(total_host_rank_time) << "s" << endl
<< "\tTotal DS Match time: " << "\tTotal DS Match time: "
<< one_util::float_to_str(total_ds_match_time) << "s" << endl << one_util::float_to_str(total_ds_match_time) << "s" << endl
<< "\tTotal DS Ranking time: " << "\tTotal DS Ranking time: "
<< one_util::float_to_str(total_ds_rank_time) << "s" << endl; << one_util::float_to_str(total_ds_rank_time) << "s" << endl
<< "\tTotal Network Match time: "
<< one_util::float_to_str(total_net_match_time) << "s" << endl
<< "\tTotal Network Ranking time:"
<< one_util::float_to_str(total_net_rank_time) << "s" << endl;
NebulaLog::log("SCHED", Log::DDEBUG, oss); NebulaLog::log("SCHED", Log::DDEBUG, oss);
} }
@ -1064,6 +1293,7 @@ void Scheduler::dispatch()
{ {
HostXML * host; HostXML * host;
DatastoreXML * ds; DatastoreXML * ds;
VirtualNetworkXML * net;
VirtualMachineXML * vm; VirtualMachineXML * vm;
ostringstream dss; ostringstream dss;
@ -1073,16 +1303,18 @@ void Scheduler::dispatch()
long long dsk; long long dsk;
vector<VectorAttribute *> pci; vector<VectorAttribute *> pci;
int hid, dsid, cid; int hid, dsid, cid, netid;
unsigned int dispatched_vms = 0; unsigned int dispatched_vms = 0;
bool dispatched, matched; bool dispatched, matched;
char * estr; char * estr;
vector<Resource *>::const_reverse_iterator i, j, k; vector<Resource *>::const_reverse_iterator i, j, k, n;
vector<SchedulerPolicy *>::iterator sp_it; vector<SchedulerPolicy *>::iterator sp_it;
ostringstream extra;
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Schedule pending VMs according to the VM policies (e.g. User priority) // Schedule pending VMs according to the VM policies (e.g. User priority)
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@ -1282,11 +1514,111 @@ void Scheduler::dispatch()
continue; continue;
} }
//------------------------------------------------------------------
// Get the highest ranked network
//------------------------------------------------------------------
extra.clear();
set<int> nics_ids = vm->get_nics_ids();
map<int, int> matched_networks;
unsigned int num_mached_networks = 0;
set<int>::iterator it;
for(it = nics_ids.begin(); it != nics_ids.end(); ++it)
{
int nic_id = *it;
const vector<Resource *> net_resources = vm->get_match_networks(nic_id);
netid = -1;
for (n = net_resources.rbegin() ; n != net_resources.rend(); n++)
{
net = vnetpool->get((*n)->oid);
if ( net == 0 )
{
continue;
}
//--------------------------------------------------------------
// Test cluster membership for datastore and selected host
//--------------------------------------------------------------
if (! net->is_in_cluster(cid))
{
continue;
}
//--------------------------------------------------------------
// Test network leases
//--------------------------------------------------------------
if ( !net->test_leases() )
{
continue;
}
net->add_lease();
//--------------------------------------------------------------
//Select this DS to dispatch VM
//--------------------------------------------------------------
netid = (*n)->oid;
break;
}
if ( netid == -1 )
{
break;
}
if ( matched_networks.find(netid) != matched_networks.end() )
{
matched_networks[netid] += 1;
}
else
{
matched_networks[netid] = 1;
}
num_mached_networks++;
extra << "NIC=[NIC_ID=\"" << nic_id
<< "\", NETWORK_MODE=\"auto\" , NETWORK_ID=\"" << netid
<< "\"]";
}
if ( num_mached_networks < nics_ids.size())
{
map<int,int>::iterator it;
for (it = matched_networks.begin(); it != matched_networks.end(); it++)
{
net = vnetpool->get(it->first);
net->rollback_leases(it->second);
}
continue;
}
//------------------------------------------------------------------ //------------------------------------------------------------------
// Dispatch and update host and DS capacity, and dispatch counters // Dispatch and update host and DS capacity, and dispatch counters
//------------------------------------------------------------------ //------------------------------------------------------------------
if (vmpool->dispatch((*k)->oid, hid, dsid, vm->is_resched()) != 0) if (vmpool->dispatch((*k)->oid, hid, dsid, vm->is_resched(), extra.str()) != 0)
{ {
map<int,int>::iterator it;
for ( it = matched_networks.begin(); it != matched_networks.end(); it++)
{
net = vnetpool->get(it->first);
net->rollback_leases(it->second);
}
continue; continue;
} }
@ -1356,8 +1688,8 @@ void Scheduler::dispatch()
if (!dispatched) if (!dispatched)
{ {
vm->log("Cannot dispatch VM to any Host. Possible reasons: Not " vm->log("Cannot dispatch VM to any Host. Possible reasons: Not "
"enough capacity in Host or System DS, or dispatch limit " "enough capacity in Host or System DS, dispatch limit "
"reached"); "reached, or limit of free leases reached.");
vmpool->update(vm); vmpool->update(vm);
} }
} }

View File

@ -109,6 +109,13 @@ void SchedulerTemplate::set_conf_default()
vattribute = new VectorAttribute("DEFAULT_DS_SCHED",vvalue); vattribute = new VectorAttribute("DEFAULT_DS_SCHED",vvalue);
conf_default.insert(make_pair(vattribute->name(),vattribute)); conf_default.insert(make_pair(vattribute->name(),vattribute));
//DEFAULT_NIC_SCHED
vvalue.clear();
vvalue.insert(make_pair("POLICY","1"));
vattribute = new VectorAttribute("DEFAULT_NIC_SCHED",vvalue);
conf_default.insert(make_pair(vattribute->name(),vattribute));
//"MEMORY_SYSTEM_DS_SCALE" //"MEMORY_SYSTEM_DS_SCALE"
value = "0"; value = "0";
@ -217,3 +224,48 @@ string SchedulerTemplate::get_ds_policy() const
return rank; return rank;
} }
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string SchedulerTemplate::get_nics_policy() const
{
int policy;
string rank;
istringstream iss;
const VectorAttribute * sched = get("DEFAULT_NIC_SCHED");
if (sched == 0)
{
return "";
}
iss.str(sched->vector_value("POLICY"));
iss >> policy;
switch (policy)
{
case 0: //Packing
rank = "- USED_LEASES";
break;
case 1: //Striping
rank = "USED_LEASES";
break;
case 2: //Custom
rank = sched->vector_value("RANK");
break;
case 3: //Fixed
rank = "PRIORITY";
break;
default:
rank = "";
}
return rank;
}

View File

@ -91,6 +91,7 @@ define(function(require) {
* @param {Object} context jquery selector * @param {Object} context jquery selector
* @param {Object} options * @param {Object} options
* options.hide_pci {bool} true to disable the pci checkbox * options.hide_pci {bool} true to disable the pci checkbox
* options.hide_auto {bool} true to disable the selection mode auto checkbox
*/ */
function _setup(context, options) { function _setup(context, options) {
var that = this; var that = this;
@ -99,6 +100,10 @@ define(function(require) {
$("input.pci-type-nic", context).attr('disabled', 'disabled'); $("input.pci-type-nic", context).attr('disabled', 'disabled');
} }
if (options != undefined && options.hide_auto == true){
$(".only_create", context).hide();
}
that.vnetsTable.initialize({ that.vnetsTable.initialize({
'selectOptions': { 'selectOptions': {
'select_callback': function(aData, options) { 'select_callback': function(aData, options) {
@ -156,6 +161,20 @@ define(function(require) {
if (!Config.isAdvancedEnabled("show_attach_nic_advanced")){ if (!Config.isAdvancedEnabled("show_attach_nic_advanced")){
$("#nic_values", context).hide(); $("#nic_values", context).hide();
} }
$("input#"+this.nicTabId+"_network_mode", context).on("change", function(){
var network_mode_on = $(this).prop("checked");
if(network_mode_on){
$(".no_auto", context).hide();
$(".auto", context).show();
} else {
$(".auto", context).hide();
$(".no_auto", context).show();
}
});
$(".auto", context).hide();
} }
function _retrieve(context) { function _retrieve(context) {
@ -184,6 +203,20 @@ define(function(require) {
nicJSON["NIC_PCI"] = true; nicJSON["NIC_PCI"] = true;
} }
if( $("input#"+this.nicTabId+"_network_mode", context).prop("checked") ){
nicJSON["NETWORK_MODE"] = "auto";
var req = $("input#"+this.nicTabId+"_SCHED_REQUIREMENTS", context).val();
var rank = $("input#"+this.nicTabId+"_SCHED_RANK", context).val();
if ( req !== "" ){
nicJSON["SCHED_REQUIREMENTS"] = req;
}
if ( rank !== "" ){
nicJSON["SCHED_RANK"] = rank;
}
}
return nicJSON; return nicJSON;
} }
@ -247,6 +280,20 @@ define(function(require) {
$("input.pci-type-nic", context).click(); $("input.pci-type-nic", context).click();
} }
if ( templateJSON["NETWORK_MODE"] && templateJSON["NETWORK_MODE"] === "auto" ) {
$("input#"+this.nicTabId+"_network_mode", context).prop("checked", true);
$(".no_auto", context).hide();
$(".auto", context).show();
if ( templateJSON["SCHED_REQUIREMENTS"] ) {
$("input#"+this.nicTabId+"_SCHED_REQUIREMENTS", context).val(templateJSON["SCHED_REQUIREMENTS"]);
}
if ( templateJSON["SCHED_RANK"] ) {
$("input#"+this.nicTabId+"_SCHED_RANK", context).val(templateJSON["SCHED_RANK"]);
}
}
WizardFields.fill(context, templateJSON); WizardFields.fill(context, templateJSON);
} }
}); });

View File

@ -13,12 +13,49 @@
{{! See the License for the specific language governing permissions and }} {{! See the License for the specific language governing permissions and }}
{{! limitations under the License. }} {{! limitations under the License. }}
{{! -------------------------------------------------------------------------- }} {{! -------------------------------------------------------------------------- }}
{{!-- {{#isFeatureEnabled "automatic_selection_vnet"}} --}}
{{{vnetsTableSelectHTML}}} <div class="only_create">
<div class="row autoContainer">
<div class="large-12 large-centered columns">
<div class="switch left">
<input class="switch-input" id="{{nicTabId}}_network_mode" type="checkbox">
<label class="switch-paddle" for="{{nicTabId}}_network_mode">
</label>
</div>
<label class="left">
&nbsp;&nbsp;
{{tr "Automatic selection"}}
{{{tip (tr "The Schedule will decide which is the bets virtual network")}}}
</label>
</div>
</div>
<div class="auto">
<div class="row autoContainer">
<div class="large-12 large-centered columns">
<label for="{{nicTabId}}_SCHED_REQUIREMENTS">
{{tr "Requirements"}}
</label>
<input type="text" id="{{nicTabId}}_SCHED_REQUIREMENTS" name="SCHED_REQUIREMENTS"/>
</div>
</div>
<div class="row autoContainer">
<div class="large-12 large-centered columns">
<label for="{{nicTabId}}_SCHED_RANK">
{{tr "Rank"}}
</label>
<input type="text" id="{{nicTabId}}_SCHED_RANK" name="SCHED_RANK"/>
</div>
</div>
</div>
</div>
{{!-- {{/isFeatureEnabled}} --}}
<div class="no_auto">
{{{vnetsTableSelectHTML}}}
</div>
<br> <br>
<div id="nic_values"> <div id="nic_values">
{{#advancedSection (tr "Advanced options") }} {{#advancedSection (tr "Advanced options") }}
<fieldset> <fieldset class="no_auto">
<legend>{{tr "Choose Network"}}</legend> <legend>{{tr "Choose Network"}}</legend>
<div class="row"> <div class="row">
<div class="medium-6 columns"> <div class="medium-6 columns">
@ -57,7 +94,7 @@
</div> </div>
</div> </div>
</fieldset> </fieldset>
<fieldset> <fieldset class="no_auto">
<legend>{{tr "Override Network Values IPv4"}}</legend> <legend>{{tr "Override Network Values IPv4"}}</legend>
<div class="row"> <div class="row">
<div class="medium-6 columns"> <div class="medium-6 columns">
@ -110,7 +147,7 @@
</div> </div>
</div> </div>
</fieldset> </fieldset>
<fieldset> <fieldset class="no_auto">
<legend>{{tr "Override Network Values IPv6"}}</legend> <legend>{{tr "Override Network Values IPv6"}}</legend>
<div class="row"> <div class="row">
<div class="medium-6 columns"> <div class="medium-6 columns">

View File

@ -44,7 +44,7 @@
</span> </span>
</label> </label>
<input type="text" name="vm_name" id="vm_name" /> <input type="text" name="vm_name" id="vm_name" />
</div> </div>
<div class="medium-4 columns"> <div class="medium-4 columns">
<label for="vm_n_times"> <label for="vm_n_times">
{{tr "Number of instances"}} {{tr "Number of instances"}}

View File

@ -69,7 +69,7 @@ define(function(require) {
function _setup(context) { function _setup(context) {
var that = this; var that = this;
that.nicTab.setup(context, {hide_pci: true}); that.nicTab.setup(context, {hide_pci: true, hide_auto: true});
Tips.setup(context); Tips.setup(context);

View File

@ -94,6 +94,7 @@ define(function(require) {
forceIPv6:true, forceIPv6:true,
forceIPv4:true, forceIPv4:true,
management: true, management: true,
hide_auto_button: true,
securityGroups: Config.isFeatureEnabled("secgroups")}); securityGroups: Config.isFeatureEnabled("secgroups")});
$(".vr_attributes #name", context).on("input", function(){ $(".vr_attributes #name", context).on("input", function(){

View File

@ -75,7 +75,8 @@ define(function(require) {
management: true, management: true,
securityGroups: Config.isFeatureEnabled("secgroups"), securityGroups: Config.isFeatureEnabled("secgroups"),
hide_add_button:true, hide_add_button:true,
click_add_button:true click_add_button:true,
hide_auto_button: true
}); });
$('#' + DIALOG_ID + 'Form', context).submit(function() { $('#' + DIALOG_ID + 'Form', context).submit(function() {

View File

@ -112,62 +112,83 @@ define(function(require) {
nic = {}; nic = {};
} }
var val = $(this).data("vnetsTable").retrieveResourceTableSelect(); var that = this;
if (val == undefined || val == ""){ if( $("input#"+that.id+"_network_mode", $(this)).prop("checked") ){
if (nic["NETWORK"] == undefined && nic["NETWORK_ID"] == undefined ){ nic = {};
// No network name or id in original NIC, and no selection done nic["NETWORK_MODE"] = "auto";
return true; //continue var req = $("input#"+that.id+"_SCHED_REQUIREMENTS", $(this)).val();
} else { var rank = $("input#"+that.id+"_SCHED_RANK", $(this)).val();
return nic;
if ( req !== "" ){
nic["SCHED_REQUIREMENTS"] = req;
}
if ( rank !== "" ){
nic["SCHED_RANK"] = rank;
} }
} }
delete nic["NETWORK"]; if ( !nic["NETWORK_MODE"] || ( nic["NETWORK_MODE"] && nic["NETWORK_MODE"] !== "auto" ) )
delete nic["NETWORK_ID"]; {
delete nic["NETWORK_UNAME"];
delete nic["NETWORK_UID"];
nic["NETWORK_ID"] = val;
delete nic["FLOATING_IP"]; var val = $(this).data("vnetsTable").retrieveResourceTableSelect();
if ($("input.floating_ip", $(this)).prop("checked")){
nic["FLOATING_IP"] = "YES";
}
var ip4 = $("input.manual_ip4", $(this)).val(); if (val == undefined || val == ""){
if (nic["NETWORK"] == undefined && nic["NETWORK_ID"] == undefined ){
if (ip4 != undefined){ // No network name or id in original NIC, and no selection done
delete nic["IP"]; return true; //continue
} else {
if (ip4 != ""){ return nic;
nic["IP"] = ip4; }
} }
}
var ip6 = $("input.manual_ip6", $(this)).val(); delete nic["NETWORK"];
delete nic["NETWORK_ID"];
delete nic["NETWORK_UNAME"];
delete nic["NETWORK_UID"];
if (ip6 != undefined){ nic["NETWORK_ID"] = val;
delete nic["IP6"];
if (ip6 != ""){ delete nic["FLOATING_IP"];
nic["IP6"] = ip6; if ($("input.floating_ip", $(this)).prop("checked")){
nic["FLOATING_IP"] = "YES";
} }
}
delete nic["VROUTER_MANAGEMENT"];
if ($("input.management", $(this)).prop("checked")){ var ip4 = $("input.manual_ip4", $(this)).val();
nic["VROUTER_MANAGEMENT"] = "YES";
}
var sgTable = $(this).data("sgTable"); if (ip4 != undefined){
delete nic["IP"];
if (sgTable){ if (ip4 != ""){
delete nic["SECURITY_GROUPS"]; nic["IP"] = ip4;
}
}
var secgroups = sgTable.retrieveResourceTableSelect(); var ip6 = $("input.manual_ip6", $(this)).val();
if (secgroups != undefined && secgroups.length != 0) {
nic["SECURITY_GROUPS"] = secgroups.join(","); if (ip6 != undefined){
delete nic["IP6"];
if (ip6 != ""){
nic["IP6"] = ip6;
}
}
delete nic["VROUTER_MANAGEMENT"];
if ($("input.management", $(this)).prop("checked")){
nic["VROUTER_MANAGEMENT"] = "YES";
}
var sgTable = $(this).data("sgTable");
if (sgTable){
delete nic["SECURITY_GROUPS"];
var secgroups = sgTable.retrieveResourceTableSelect();
if (secgroups != undefined && secgroups.length != 0) {
nic["SECURITY_GROUPS"] = secgroups.join(",");
}
} }
} }
@ -225,6 +246,38 @@ define(function(require) {
$(".nic-section-entry", dd_context).data("template_nic", options.nic); $(".nic-section-entry", dd_context).data("template_nic", options.nic);
$(".nic-section-entry", dd_context).data("vnetsTable", vnetsTable); $(".nic-section-entry", dd_context).data("vnetsTable", vnetsTable);
$(".nic-section-entry", dd_context).data("sgTable", sgTable); $(".nic-section-entry", dd_context).data("sgTable", sgTable);
$(".auto", dd_context).hide();
$(".no_auto", dd_context).show();
if ( options.hide_auto_button && options.hide_auto_button === true ){
$(".only_template", dd_context).hide();
}
$("input#provision_accordion_dd_"+provision_nic_accordion_dd_id+"_network_mode", dd_context).on("change", function(){
var network_mode_on = $(this).prop("checked");
if(network_mode_on){
$(".no_auto", dd_context).hide();
$(".auto", dd_context).show();
} else {
$(".auto", dd_context).hide();
$(".no_auto", dd_context).show();
}
});
if ( options.nic && options.nic["NETWORK_MODE"] && options.nic["NETWORK_MODE"] === "auto" ) {
$("input#provision_accordion_dd_"+provision_nic_accordion_dd_id+"_network_mode", dd_context).prop("checked", true);
$(".no_auto", dd_context).hide();
$(".auto", dd_context).show();
if ( options.nic["SCHED_REQUIREMENTS"] ) {
$("input#provision_accordion_dd_"+provision_nic_accordion_dd_id+"_SCHED_REQUIREMENTS", dd_context).val(options.nic["SCHED_REQUIREMENTS"]);
}
if ( options.nic["SCHED_RANK"] ) {
$("input#provision_accordion_dd_"+provision_nic_accordion_dd_id+"_SCHED_RANK", dd_context).val(options.nic["SCHED_RANK"]);
}
}
Tips.setup(dd_context); Tips.setup(dd_context);
Foundation.reInit(context); Foundation.reInit(context);

View File

@ -21,75 +21,111 @@
<i class="right fas fa-times-circle remove-tab provision_remove_nic"></i> <i class="right fas fa-times-circle remove-tab provision_remove_nic"></i>
</a> </a>
<div id="provision_accordion_dd_{{provision_nic_accordion_dd_id}}" class="accordion-content nic-section-entry" data-tab-content> <div id="provision_accordion_dd_{{provision_nic_accordion_dd_id}}" class="accordion-content nic-section-entry" data-tab-content>
<div class="row collapse"> <div class="only_template">
{{{vnetsTableHTML}}} <div class="row autoContainer">
</div> <div class="large-12 large-centered columns">
<div class="row"> <div class="switch left">
{{#if options.forceIPv4}} <input class="switch-input" id="provision_accordion_dd_{{provision_nic_accordion_dd_id}}_network_mode" type="checkbox">
<div class="medium-6 columns"> <label class="switch-paddle" for="provision_accordion_dd_{{provision_nic_accordion_dd_id}}_network_mode">
<label> </label>
{{tr "Force IPv4:"}} </div>
<span class="tip"> <label class="left">
{{tr "Optionally, you can force the IP assigned to the network interface."}} &nbsp;&nbsp;
</span> {{tr "Automatic selection"}}
{{#if options.nic.IP}} {{{tip (tr "The Schedule will decide which is the bets virtual network")}}}
<input type="text" class="manual_ip4" value="{{options.nic.IP}}"/>
{{else}}
<input type="text" class="manual_ip4"/>
{{/if}}
</label> </label>
</div> </div>
{{/if}}
{{#if options.floatingIP}}
<div class="medium-6 columns">
<label class="inline">
<input type="checkbox" class="floating_ip" />
{{tr "Floating IP"}}
<span class="tip">
{{tr "If checked, each Virtual Machine will have a floating IP added to its network interface."}}
</span>
</label>
</div> </div>
{{/if}} <div class="auto">
{{#if options.management}} <div class="row autoContainer">
<div class="medium-6 columns"> <div class="large-12 large-centered columns">
<label> <label for="provision_accordion_dd_{{provision_nic_accordion_dd_id}}_SCHED_REQUIREMENTS">
<input type="checkbox" class="management" /> {{tr "Requirements"}}
{{tr "Management Interface"}} </label>
<input type="text" id="provision_accordion_dd_{{provision_nic_accordion_dd_id}}_SCHED_REQUIREMENTS" name="SCHED_REQUIREMENTS"/>
</div>
</div>
<div class="row autoContainer">
<div class="large-12 large-centered columns">
<label for="provision_accordion_dd_{{provision_nic_accordion_dd_id}}_SCHED_RANK">
{{tr "Rank"}}
</label>
<input type="text" id="provision_accordion_dd_{{provision_nic_accordion_dd_id}}_SCHED_RANK" name="SCHED_RANK"/>
</div>
</div>
</div>
</div>
<div class="no_auto">
<div class="row collapse">
{{{vnetsTableHTML}}}
</div>
<div class="row">
{{#if options.forceIPv4}}
<div class="medium-6 columns">
<label>
{{tr "Force IPv4:"}}
<span class="tip">
{{tr "Optionally, you can force the IP assigned to the network interface."}}
</span>
{{#if options.nic.IP}}
<input type="text" class="manual_ip4" value="{{options.nic.IP}}"/>
{{else}}
<input type="text" class="manual_ip4"/>
{{/if}}
</label>
</div>
{{/if}}
{{#if options.floatingIP}}
<div class="medium-6 columns">
<label class="inline">
<input type="checkbox" class="floating_ip" />
{{tr "Floating IP"}}
<span class="tip">
{{tr "If checked, each Virtual Machine will have a floating IP added to its network interface."}}
</span>
</label>
</div>
{{/if}}
{{#if options.management}}
<div class="medium-6 columns">
<label>
<input type="checkbox" class="management" />
{{tr "Management Interface"}}
<span class="tip">
{{tr "If checked, this network interface will be a Virtual Router management interface. Traffic will not be forwarded."}}
</span>
</label>
</div>
{{/if}}
</div>
<div class="row">
{{#if options.forceIPv6}}
<div class="medium-6 columns">
<label>
{{tr "Force IPv6:"}}
<span class="tip">
{{tr "Optionally, you can force the IP assigned to the network interface."}}
</span>
{{#if options.nic.IP6}}
<input type="text" class="manual_ip6" value="{{options.nic.IP6}}"/>
{{else}}
<input type="text" class="manual_ip6"/>
{{/if}}
</label>
</div>
{{/if}}
</div>
{{#if options.securityGroups}}
<div class="row collapse">
<h6>
{{tr "Security Groups"}}&nbsp;
<span class="tip"> <span class="tip">
{{tr "If checked, this network interface will be a Virtual Router management interface. Traffic will not be forwarded."}} {{tr "You can add Security Groups to this network interface. These IDs do not overwrite the ones defined in the Virtual Network. All the Security Group IDs are combined, and applied to the Virtual Machine instance."}}
</span> </span>
</label> </h6>
{{{securityGroupsTableHTML}}}
</div> </div>
{{/if}} {{/if}}
</div> </div>
<div class="row">
{{#if options.forceIPv6}}
<div class="medium-6 columns">
<label>
{{tr "Force IPv6:"}}
<span class="tip">
{{tr "Optionally, you can force the IP assigned to the network interface."}}
</span>
{{#if options.nic.IP6}}
<input type="text" class="manual_ip6" value="{{options.nic.IP6}}"/>
{{else}}
<input type="text" class="manual_ip6"/>
{{/if}}
</label>
</div>
{{/if}}
</div>
{{#if options.securityGroups}}
<div class="row collapse">
<h6>
{{tr "Security Groups"}}&nbsp;
<span class="tip">
{{tr "You can add Security Groups to this network interface. These IDs do not overwrite the ones defined in the Virtual Network. All the Security Group IDs are combined, and applied to the Virtual Machine instance."}}
</span>
</h6>
{{{securityGroupsTableHTML}}}
</div>
{{/if}}
</div> </div>
</dd> </dd>

View File

@ -32,7 +32,6 @@ bool QuotaNetwork::check(PoolObjectSQL::ObjectType otype, Template * tmpl,
{ {
vector<VectorAttribute*> nic; vector<VectorAttribute*> nic;
string net_id;
int num; int num;
bool uses_lease; bool uses_lease;
@ -44,7 +43,15 @@ bool QuotaNetwork::check(PoolObjectSQL::ObjectType otype, Template * tmpl,
for (int i = 0 ; i < num ; i++) for (int i = 0 ; i < num ; i++)
{ {
net_id = nic[i]->vector_value("NETWORK_ID"); std::string net_mode = nic[i]->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
std::string net_id = nic[i]->vector_value("NETWORK_ID");
if ( net_mode == "AUTO" && net_id.empty() )
{
continue;
}
uses_lease = true; uses_lease = true;

View File

@ -1002,7 +1002,7 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
// Parse the context & requirements // Parse the context & requirements
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
rc = parse_context(error_str); rc = parse_context(error_str, false); //Don't generate context for auto NICs
if ( rc != 0 ) if ( rc != 0 )
{ {
@ -2908,7 +2908,7 @@ int VirtualMachine::updateconf(VirtualMachineTemplate& tmpl, string &err)
obj_template->remove(context_bck); obj_template->remove(context_bck);
obj_template->set(context_new); obj_template->set(context_new);
if ( parse_context(err) != 0 ) if ( parse_context(err, true) != 0 )
{ {
obj_template->erase("CONTEXT"); obj_template->erase("CONTEXT");
obj_template->set(context_bck); obj_template->set(context_bck);
@ -3161,10 +3161,83 @@ int VirtualMachine::clear_saveas_state()
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* VirtualMachine Nic interface */ /* VirtualMachine Nic interface */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
int VirtualMachine::get_auto_network_leases(VirtualMachineTemplate * tmpl,
string& estr)
{
vector<VectorAttribute *> vnics;
vector<VectorAttribute*>::iterator it;
int nic_id;
/* ---------------------------------------------------------------------- */
/* Update auto NICs with the scheduling resulti */
/* ---------------------------------------------------------------------- */
tmpl->get("NIC", vnics);
for (it = vnics.begin(); it != vnics.end(); ++it)
{
std::string net_mode;
(*it)->vector_value("NIC_ID", nic_id);
VirtualMachineNic * nic = get_nic(nic_id);
net_mode = nic->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
string network_id = nic->vector_value("NETWORK_ID");
if (nic == 0 || net_mode != "AUTO" || !network_id.empty())
{
std::ostringstream oss;
oss << "NIC_ID "<< nic_id << " not found or not AUTO";
estr = oss.str();
return -1;
}
nic->replace("NETWORK_ID", (*it)->vector_value("NETWORK_ID"));
}
/* ---------------------------------------------------------------------- */
/* Get the network leases & security groups for NICs in auto mode */
/* ---------------------------------------------------------------------- */
vector<VectorAttribute*> sgs;
vector<Attribute *> anics;
VectorAttribute * nic_default = obj_template->get("NIC_DEFAULT");
if (nics.get_auto_network_leases(oid, uid, nic_default, sgs, estr) == -1)
{
return -1;
}
obj_template->set(sgs);
/* ---------------------------------------------------------------------- */
/* Generate the CONTEXT for NICs in auto mode */
/* ---------------------------------------------------------------------- */
VectorAttribute * context = obj_template->get("CONTEXT");
if ( context == 0 )
{
return 0;
}
if ( generate_network_context(context, estr, true) != 0 )
{
return -1;
}
return 0;
}
int VirtualMachine::get_network_leases(string& estr) int VirtualMachine::get_network_leases(string& estr)
{ {
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -3172,7 +3245,7 @@ int VirtualMachine::get_network_leases(string& estr)
/* * NIC */ /* * NIC */
/* * PCI + TYPE = NIC */ /* * PCI + TYPE = NIC */
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
vector<Attribute * > anics; vector<Attribute *> anics;
user_obj_template->remove("NIC", anics); user_obj_template->remove("NIC", anics);

View File

@ -106,7 +106,14 @@ int VirtualMachine::generate_context(string &files, int &disk_id,
} }
//Generate dynamic context attributes //Generate dynamic context attributes
if ( generate_network_context(context, error_str) != 0 ) int rc = generate_network_context(context, error_str, false); //no AUTO mode
if ( rc == 0 )
{
rc = generate_network_context(context, error_str, true); //AUTO mode
}
if ( rc != 0 )
{ {
ostringstream oss; ostringstream oss;
@ -274,11 +281,16 @@ static void parse_context_network(const std::vector<ContextVariable>& cvars,
} }
} }
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::generate_network_context(VectorAttribute* context, int VirtualMachine::generate_network_context(VectorAttribute* context,
string& error_str) string& error_str, bool only_auto)
{ {
bool net_context; bool net_context;
string net_mode = "";
bool parse_vnets = false; //VNETs needs parse, NIC context generated
context->vector_value("NETWORK", net_context); context->vector_value("NETWORK", net_context);
@ -304,8 +316,23 @@ int VirtualMachine::generate_network_context(VectorAttribute* context,
for(int i=0; i<num_vatts; i++) for(int i=0; i<num_vatts; i++)
{ {
std::string net_mode = vatts[i]->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
if ( net_mode == "AUTO" && !only_auto )
{
continue;
}
parse_context_network(NETWORK_CONTEXT, &tmp_context, vatts[i]); parse_context_network(NETWORK_CONTEXT, &tmp_context, vatts[i]);
parse_context_network(NETWORK6_CONTEXT, &tmp_context, vatts[i]); parse_context_network(NETWORK6_CONTEXT, &tmp_context, vatts[i]);
parse_vnets = true;
}
if (!parse_vnets)
{
return 0;
} }
str = tmp_context.marshall(); str = tmp_context.marshall();
@ -437,7 +464,7 @@ int VirtualMachine::generate_token_context(VectorAttribute * context, string& e)
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
int VirtualMachine::parse_context(string& error_str) int VirtualMachine::parse_context(string& error_str, bool all_nics)
{ {
VectorAttribute * context = obj_template->get("CONTEXT"); VectorAttribute * context = obj_template->get("CONTEXT");
@ -453,8 +480,21 @@ int VirtualMachine::parse_context(string& error_str)
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Add network context and parse variables // Add network context and parse variables
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
if (parse_context_variables(&context, error_str) == -1 || if ( parse_context_variables(&context, error_str) == -1 )
generate_network_context(context, error_str) == -1 ) {
return -1;
}
int rc;
rc = generate_network_context(context, error_str, false);
if ( rc != -1 && all_nics )
{
rc = generate_network_context(context, error_str, true);
}
if ( rc == -1 )
{ {
return -1; return -1;
} }

View File

@ -130,6 +130,16 @@ void VirtualMachineNic::authorize(PoolObjectSQL::ObjectType ot, int uid,
set<int> sgroups; set<int> sgroups;
string net_mode = "";
net_mode = this->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
if ( net_mode == "AUTO" )
{
return;
}
get_security_groups(sgroups); get_security_groups(sgroups);
vnpool->authorize_nic(ot, this, uid, ar, sgroups, check_lock); vnpool->authorize_nic(ot, this, uid, ar, sgroups, check_lock);
@ -170,6 +180,10 @@ void VirtualMachineNic::to_xml_short(std::ostringstream& oss) const
std::string ip6 = vector_value("IP6"); std::string ip6 = vector_value("IP6");
std::string ip6_ula = vector_value("IP6_ULA"); std::string ip6_ula = vector_value("IP6_ULA");
std::string reqs = vector_value("SCHED_REQUIREMENTS");
std::string rank = vector_value("SCHED_RANK");
std::string mode = vector_value("NETWORK_MODE");
oss << "<NIC>"; oss << "<NIC>";
if (!ip.empty()) if (!ip.empty())
@ -187,6 +201,22 @@ void VirtualMachineNic::to_xml_short(std::ostringstream& oss) const
oss << "<IP6_ULA>" << one_util::escape_xml(ip6_ula) << "</IP6_ULA>"; oss << "<IP6_ULA>" << one_util::escape_xml(ip6_ula) << "</IP6_ULA>";
} }
if (!mode.empty())
{
oss << "<NETWORK_MODE>" << one_util::escape_xml(mode) << "</NETWORK_MODE>";
}
if (!reqs.empty())
{
oss << "<SCHED_REQUIREMENTS>" << one_util::escape_xml(reqs)
<< "</SCHED_REQUIREMENTS>";
}
if (!rank.empty())
{
oss << "<SCHED_RANK>" << one_util::escape_xml(rank) << "</SCHED_RANK>";
}
XML_NIC_ATTR(oss, "MAC"); XML_NIC_ATTR(oss, "MAC");
XML_NIC_ATTR(oss, "NETWORK"); XML_NIC_ATTR(oss, "NETWORK");
XML_NIC_ATTR(oss, "NETWORK_ID"); XML_NIC_ATTR(oss, "NETWORK_ID");
@ -216,6 +246,7 @@ int VirtualMachineNics::get_network_leases(int vm_id, int uid,
vector<VectorAttribute*>& sgs, std::string& error_str) vector<VectorAttribute*>& sgs, std::string& error_str)
{ {
Nebula& nd = Nebula::instance(); Nebula& nd = Nebula::instance();
VirtualNetworkPool * vnpool = nd.get_vnpool(); VirtualNetworkPool * vnpool = nd.get_vnpool();
SecurityGroupPool * sgpool = nd.get_secgrouppool(); SecurityGroupPool * sgpool = nd.get_secgrouppool();
@ -232,20 +263,83 @@ int VirtualMachineNics::get_network_leases(int vm_id, int uid,
VectorAttribute * vnic = static_cast<VectorAttribute *>(*it); VectorAttribute * vnic = static_cast<VectorAttribute *>(*it);
VirtualMachineNic * nic = new VirtualMachineNic(vnic, nic_id); VirtualMachineNic * nic = new VirtualMachineNic(vnic, nic_id);
if ( nic_default != 0 ) std::string net_mode = vnic->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
if (net_mode != "AUTO" )
{ {
nic->merge(nic_default, false); if ( nic_default != 0 )
{
nic->merge(nic_default, false);
}
if ( vnpool->nic_attribute(PoolObjectSQL::VM, nic, nic_id, uid,
vm_id, error_str) == -1 )
{
return -1;
}
nic->get_security_groups(sg_ids);
}
else
{
nic->replace("NIC_ID", nic_id);
} }
if ( vnpool->nic_attribute(PoolObjectSQL::VM, nic, nic_id, uid, add_attribute(nic, nic->get_nic_id());
}
/* ---------------------------------------------------------------------- */
/* Get the secutiry groups */
/* ---------------------------------------------------------------------- */
sgpool->get_security_group_rules(vm_id, sg_ids, sgs);
return 0;
}
int VirtualMachineNics::get_auto_network_leases(int vm_id, int uid,
VectorAttribute * nic_default, vector<VectorAttribute*>& sgs,
std::string& error_str)
{
Nebula& nd = Nebula::instance();
VirtualNetworkPool * vnpool = nd.get_vnpool();
SecurityGroupPool * sgpool = nd.get_secgrouppool();
set<int> sg_ids;
/* ---------------------------------------------------------------------- */
/* Get the interface network information */
/* ---------------------------------------------------------------------- */
for ( nic_iterator nic = begin() ; nic != end() ; ++nic )
{
int nic_id;
std::string net_mode = (*nic)->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
if ( net_mode != "AUTO" )
{
continue;
}
if ( (*nic)->vector_value("NIC_ID", nic_id) != 0 )
{
continue;
}
if ( nic_default != 0 )
{
(*nic)->merge(nic_default, false);
}
if ( vnpool->nic_attribute(PoolObjectSQL::VM, *nic, nic_id, uid,
vm_id, error_str) == -1 ) vm_id, error_str) == -1 )
{ {
return -1; return -1;
} }
nic->get_security_groups(sg_ids); (*nic)->get_security_groups(sg_ids);
add_attribute(nic, nic->get_nic_id());
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */