Support physical network card config virtual function

Change-Id: Ib514009b0b6e845fd08b267275e7794fd1d59f68
This commit is contained in:
10112914 2017-02-21 10:44:30 +08:00
parent d73cf900ea
commit ec8fd35957
13 changed files with 4158 additions and 330 deletions

View File

@ -34,82 +34,60 @@ def get_pxe_mac(host_detail):
return pxe_macs
def check_keys_in_pairs(key1, key2, dict_data):
"""
key1,key2 in dict_data or key1,key2 not in dict_data return True
if key1 in dict_data but key2 not in dict_data or else return False
:param key1,key2, check keys
:param dict_data checked data
"""
if key1 and key2 and isinstance(dict_data, dict):
if key1 in dict_data and key2 not in dict_data:
return False
elif key2 in dict_data and key1 not in dict_data:
return False
return True
def is_value_in_range(value_min, value_max, range):
if (value_min >= range[0] and value_min <= range[1]) \
and (value_max >= range[0] and value_max <= range[1]):
if value_min < value_max:
return True
return False
def _valid_appointed_network_range(req, network_meta,
key_start, key_end, check_range):
if not check_keys_in_pairs(key_start, key_end, network_meta):
msg = "%s and %s must be appeared "\
"at the same time" % (key_start, key_end)
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
else:
value_min = network_meta.get(key_start, None)
value_max = network_meta.get(key_end, None)
if value_min is not None and value_max is not None:
value_min = int(value_min)
value_max = int(value_max)
if not is_value_in_range(value_min, value_max, check_range):
msg = "%s:%d and %s:%d must be in %d~%d and start:%d less than end:%d" \
% (key_start, value_min, key_end, value_max,
check_range[0], check_range[1], value_min, value_max)
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
def valid_network_range(req, network_meta):
if (('vlan_start' in network_meta and
'vlan_end' not in network_meta) or
('vlan_start' not in network_meta and
'vlan_end' in network_meta)):
msg = "vlan-start and vlan-end must be appeared "\
"at the same time"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if 'vlan_start' in network_meta:
if not (int(network_meta['vlan_start']) >= 1 and
int(network_meta['vlan_start']) <= 4094):
msg = "vlan_start must be a integer in 1~4096"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if 'vlan_end' in network_meta:
if not (int(network_meta['vlan_end']) >= 1 and
int(network_meta['vlan_end']) <= 4094):
msg = "vlan_end must be a integer in 1~4096"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if int(network_meta['vlan_start']) > int(network_meta['vlan_end']):
msg = "vlan_start must be less than vlan_end"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if (('vni_start' in network_meta and 'vni_end' not in
network_meta) or (
'vni_start' not in network_meta and
'vni_end' in network_meta)):
msg = "vni_start and vni_end must be appeared at the same time"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if 'vni_start' in network_meta:
if not (int(network_meta['vni_start']) >= 1 and
int(network_meta['vni_start']) <= 16777216):
msg = "vni_start must be a integer in 1~16777216"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if 'vni_end' in network_meta:
if not (int(network_meta['vni_end']) >= 1 and
int(network_meta['vni_end']) <= 16777216):
msg = "vni_end must be a integer in 1~16777216"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if int(network_meta['vni_start']) > int(network_meta['vni_end']):
msg = "vni_start must be less than vni_end"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if (('gre_id_start' in network_meta and
'gre_id_end' not in network_meta) or
('gre_id_start' not in network_meta and
'gre_id_end' in network_meta)):
msg = "gre_id_start and gre_id_end must"\
"be appeared at the same time"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if 'gre_id_start' in network_meta:
if not (int(network_meta['gre_id_start']) >= 1 and
int(network_meta['gre_id_start']) <= 4094):
msg = "gre_id_start must be a integer in 1~4094"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if 'gre_id_end' in network_meta:
if not (int(network_meta['gre_id_end']) >= 1 and
int(network_meta['gre_id_end']) <= 4094):
msg = "gre_id_end must be a integer in 1~4094"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
if int(network_meta['gre_id_start']) >\
int(network_meta['gre_id_end']):
msg = "gre_id_start must be less than gre_id_end"
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg, request=req)
default_range = [1, 4094]
_valid_appointed_network_range(req, network_meta,
'vlan_start', 'vlan_end', default_range)
_valid_appointed_network_range(req, network_meta,
'vni_start', 'vni_end', [1, 16777216])
_valid_appointed_network_range(req, network_meta,
'gre_id_start', 'gre_id_end', default_range)
_valid_appointed_network_range(req, network_meta,
'svlan_start', 'svlan_end', default_range)
def valid_ip_ranges(ip_ranges, cidr=None):

View File

@ -64,7 +64,9 @@ ML2_TYPE = [
'ovs,sriov(macvtap)',
'ovs,sriov(direct)',
'sriov(macvtap)',
'sriov(direct)']
'sriov(direct)',
'dvs,sriov(direct)']
NEED_VF_TYPE = ['dvs,sriov(direct)']
SUPPORT_HOST_PAGE_SIZE = ['2M', '1G']
config = ConfigParser.ConfigParser()
config.read(daisy_cmn.daisy_conf_file)
@ -1166,6 +1168,186 @@ class Controller(controller.BaseController):
LOG.error(msg)
raise HTTPForbidden(explanation=msg)
def _interface_has_vf(self, interface):
if interface and isinstance(interface, dict):
if interface.get('is_support_vf'):
return True
return False
def _get_interface_by_name(self, name, interfaces):
if not interfaces:
return None
if not isinstance(interfaces, list):
interfaces = eval(interfaces)
for interface in interfaces:
if name == interface.get('name'):
return interface
return None
def _check_vswitch_type(self, req, interface, interfaces):
vswitch_type = interface.get('vswitch_type')
if vswitch_type:
if vswitch_type not in ML2_TYPE:
msg = "vswitch_type (%s) is not supported" \
% vswitch_type
LOG.error(msg)
raise HTTPBadRequest(explanation=msg, request=req,
content_type="text/plain")
if vswitch_type in NEED_VF_TYPE:
if "bond" == interface.get('type'):
slave_names = interface.get('slaves')
if slave_names:
for slave_name in slave_names:
interface_slave = \
self._get_interface_by_name(slave_name,
interfaces)
if not self._interface_has_vf(interface_slave):
msg = "vswitch_type (%s) is "\
"not supported because slave %s"\
" of %s does not support VF" % \
(vswitch_type,
slave_name,
interface['name'])
LOG.error(msg)
raise HTTPBadRequest(
explanation=msg,
request=req,
content_type="text/plain")
else:
if not self._interface_has_vf(interface):
msg = "vswitch_type (%s) is not supported "\
"because interface %s does not support VF" %\
(vswitch_type, interface['name'])
LOG.error(msg)
raise HTTPBadRequest(explanation=msg, request=req,
content_type="text/plain")
def _check_interface_on_update_host(self, req, host_meta, orig_host_meta):
orig_mac_list = []
# get cluster id
cluster_id = host_meta.get('cluster')
if not cluster_id:
clusters = registry.get_clusters_detail(req.context)
orig_cluster_name = orig_host_meta.get('cluster', None)
orig_cluster_id = None
for cluster in clusters:
if cluster['name'] == orig_cluster_name:
orig_cluster_id = cluster['id']
break
cluster_id = orig_cluster_id
if 'interfaces' in host_meta:
host_meta_interfaces = list(eval(host_meta['interfaces']))
ether_nic_names_list = list()
bond_nic_names_list = list()
bond_slaves_lists = list()
interface_num = 0
assigned_networks_of_interfaces = []
for interface_param in host_meta_interfaces:
if not interface_param.get('pci', None) and \
interface_param.get('type', None) == 'ether':
msg = "The Interface need a non-null pci"
LOG.error(msg)
raise HTTPBadRequest(explanation=msg,
request=req,
content_type="text/plain")
self._check_vswitch_type(req,
interface_param,
host_meta_interfaces)
# check bond in pairs
if interface_param.get('name', None):
if 'type' in interface_param and \
interface_param['type'] == 'bond':
bond_nic_names_list.append(interface_param['name'])
slave_list = []
if interface_param.get('slaves', None):
bond_slaves_lists.append(interface_param['slaves'])
elif interface_param.get('slave1', None) and \
interface_param.get('slave2', None):
slave_list.append(interface_param['slave1'])
slave_list.append(interface_param['slave2'])
bond_slaves_lists.append(slave_list)
else:
msg = (
_("Slaves parameter can not be "
"None when nic type was bond."))
LOG.error(msg)
raise HTTPForbidden(msg)
else: # type == ether or interface without type field
ether_nic_names_list.append(interface_param['name'])
else:
msg = (_("Nic name can not be None."))
LOG.error(msg)
raise HTTPForbidden(msg)
# set is_deployment status
if 'is_deployment' in interface_param:
if interface_param['is_deployment'] == "True" or \
interface_param[
'is_deployment']:
interface_param['is_deployment'] = 1
else:
interface_param['is_deployment'] = 0
# check assigned networks
if ('assigned_networks' in interface_param and
interface_param['assigned_networks'] != [''] and
interface_param['assigned_networks']):
if cluster_id:
LOG.info(
"interface['assigned_networks']: %s" %
interface_param['assigned_networks'])
if interface_param.get('type', None) == "bond":
bond_type = interface_param.get("bond_type", None)
assigned_networks_of_one_interface = \
self._check_asged_net(
req, cluster_id,
interface_param['assigned_networks'],
bond_type)
else:
assigned_networks_of_one_interface = self. \
_check_asged_net(
req, cluster_id,
interface_param['assigned_networks'])
self._update_networks_phyname(
req, interface_param, cluster_id)
host_meta['cluster'] = cluster_id
else:
msg = "cluster must be given first " \
"when network plane is allocated"
LOG.error(msg)
raise HTTPBadRequest(explanation=msg,
request=req,
content_type="text/plain")
assigned_networks_of_interfaces.\
append(assigned_networks_of_one_interface)
else:
assigned_networks_of_interfaces.append([])
interface_num += 1
interfaces_db = orig_host_meta.get('interfaces', None)
orig_mac_list = [interface_db['mac'] for interface_db in
interfaces_db if interface_db['mac']]
self._compare_assigned_networks_between_interfaces(
interface_num, assigned_networks_of_interfaces)
# check bond slaves validity
self.check_bond_slaves_validity(
bond_slaves_lists, ether_nic_names_list)
nic_name_list = ether_nic_names_list + bond_nic_names_list
if len(set(nic_name_list)) != len(nic_name_list):
msg = (_("Nic name must be unique."))
LOG.error(msg)
raise HTTPForbidden(msg)
return orig_mac_list
@utils.mutating
def update_host(self, req, id, host_meta):
"""
@ -1186,73 +1368,12 @@ class Controller(controller.BaseController):
raise HTTPForbidden(explanation=msg,
request=req,
content_type="text/plain")
orig_mac_list = list()
self._verify_host_name(req, id, orig_host_meta, host_meta)
if 'interfaces' in host_meta:
for interface_param in eval(host_meta['interfaces']):
if not interface_param.get('pci', None) and \
interface_param.get('type', None) == 'ether':
msg = "The Interface need a non-null pci"
LOG.error(msg)
raise HTTPBadRequest(explanation=msg,
request=req,
content_type="text/plain")
if 'vswitch_type' in interface_param and interface_param[
'vswitch_type'] != '' and \
interface_param['vswitch_type'] not in ML2_TYPE:
msg = "vswitch_type %s is not supported" % interface_param[
'vswitch_type']
LOG.error(msg)
raise HTTPBadRequest(explanation=msg, request=req,
content_type="text/plain")
interfaces_db = orig_host_meta.get('interfaces', None)
orig_mac_list = [interface_db['mac'] for interface_db in
interfaces_db if interface_db['mac']]
orig_pci_list = [interface_db['pci'] for interface_db in
interfaces_db if interface_db['pci']]
if interfaces_db and len(orig_pci_list):
interfaces_param = eval(host_meta['interfaces'])
interfaces_db_ether = [
interface_db for interface_db in interfaces_db if
interface_db.get(
'type', None) != 'bond']
interfaces_param_ether = [
interface_param for interface_param in interfaces_param if
interface_param.get(
'type', None) != 'bond']
if len(interfaces_param) < len(interfaces_db_ether):
msg = "Forbidden to update part of interfaces"
LOG.error(msg)
raise HTTPForbidden(explanation=msg)
# pci in subnet interface is null,
# comment it to avoid the bug. 20160508 gaoming
if '':
pci_count = 0
for interface_db in interfaces_db:
if interface_db.get('type', None) != 'bond':
for interface_param in interfaces_param_ether:
if interface_param['pci'] == interface_db['pci']:
pci_count += 1
if interface_param[
'mac'] != interface_db['mac']:
msg = "Forbidden to modify mac of " \
"interface with pci %s" % \
interface_db['pci']
LOG.error(msg)
raise HTTPForbidden(explanation=msg)
if interface_param[
'type'] != interface_db['type']:
msg = "Forbidden to modify type of " \
"interface with pci %s" % \
interface_db['pci']
LOG.error(msg)
raise HTTPForbidden(explanation=msg)
if pci_count != len(interfaces_db_ether):
msg = "Forbidden to modify pci of interface"
LOG.error(msg)
raise HTTPForbidden(explanation=msg)
orig_mac_list = \
self._check_interface_on_update_host(req,
host_meta,
orig_host_meta)
self._verify_host_cluster(req, id, orig_host_meta, host_meta)
if ('resource_type' in host_meta and
host_meta['resource_type'] not in self.support_resource_type):
@ -1551,14 +1672,6 @@ class Controller(controller.BaseController):
request=req,
content_type="text/plain")
clusters = registry.get_clusters_detail(req.context)
orig_cluster_name = orig_host_meta.get('cluster', None)
orig_cluster_id = None
for cluster in clusters:
if cluster['name'] == orig_cluster_name:
orig_cluster_id = cluster['id']
cluster_id = host_meta.get('cluster', orig_cluster_id)
params = self._get_query_params(req)
role_list = registry.get_roles_detail(req.context, **params)
if 'role' in host_meta:
@ -1584,95 +1697,6 @@ class Controller(controller.BaseController):
LOG.error(msg)
raise HTTPNotFound(msg)
if 'interfaces' in host_meta:
host_meta_interfaces = list(eval(host_meta['interfaces']))
ether_nic_names_list = list()
bond_nic_names_list = list()
bond_slaves_lists = list()
interface_num = 0
assigned_networks_of_interfaces = []
for interface in host_meta_interfaces:
if interface.get('name', None):
if 'type' in interface and interface['type'] == 'bond':
bond_nic_names_list.append(interface['name'])
slave_list = []
if interface.get('slaves', None):
bond_slaves_lists.append(interface['slaves'])
elif interface.get('slave1', None) and \
interface.get('slave2', None):
slave_list.append(interface['slave1'])
slave_list.append(interface['slave2'])
bond_slaves_lists.append(slave_list)
else:
msg = (
_("Slaves parameter can not be "
"None when nic type was bond."))
LOG.error(msg)
raise HTTPForbidden(msg)
else: # type == ether or interface without type field
ether_nic_names_list.append(interface['name'])
else:
msg = (_("Nic name can not be None."))
LOG.error(msg)
raise HTTPForbidden(msg)
if 'is_deployment' in interface:
if interface['is_deployment'] == "True" or interface[
'is_deployment']:
interface['is_deployment'] = 1
else:
interface['is_deployment'] = 0
if ('assigned_networks' in interface and
interface['assigned_networks'] != [''] and
interface['assigned_networks']):
if cluster_id:
LOG.info(
"interface['assigned_networks']: %s" %
interface['assigned_networks'])
if interface.get('type', None) == "bond":
bond_type = interface.get("bond_type", None)
if bond_type:
assigned_networks_of_one_interface = self. \
_check_asged_net(req,
cluster_id,
interface[
'assigned_networks'],
bond_type)
else:
assigned_networks_of_one_interface = self. \
_check_asged_net(req,
cluster_id,
interface[
'assigned_networks'])
self._update_networks_phyname(
req, interface, cluster_id)
host_meta['cluster'] = cluster_id
else:
msg = "cluster must be given first " \
"when network plane is allocated"
LOG.error(msg)
raise HTTPBadRequest(explanation=msg,
request=req,
content_type="text/plain")
assigned_networks_of_interfaces.\
append(assigned_networks_of_one_interface)
else:
assigned_networks_of_interfaces.\
append([])
interface_num += 1
self._compare_assigned_networks_between_interfaces(
interface_num, assigned_networks_of_interfaces)
# check bond slaves validity
self.check_bond_slaves_validity(
bond_slaves_lists, ether_nic_names_list)
nic_name_list = ether_nic_names_list + bond_nic_names_list
if len(set(nic_name_list)) != len(nic_name_list):
msg = (_("Nic name must be unique."))
LOG.error(msg)
raise HTTPForbidden(msg)
if 'os_status' in host_meta:
if host_meta['os_status'] not in \
['init', 'installing', 'active', 'failed', 'none']:
@ -1931,7 +1955,7 @@ class Controller(controller.BaseController):
discover_host_meta)
msg = (_("Do trustme.sh %s failed!" %
discover_host_meta['ip']))
LOG.warn(_(msg))
LOG.warn(msg)
fp.write(msg)
else:
mac_info = re.search(r'"mac": ([^,\n]*)', exc_result)
@ -2044,7 +2068,7 @@ class Controller(controller.BaseController):
try:
for t in threads:
t.join()
except:
except Exception:
LOG.warn(_("Join discover host thread %s failed!" % t))
@utils.mutating

View File

@ -722,11 +722,19 @@ def _host_update(context, values, host_id):
host_interfaces_values['is_deployment'] = 0
if host_interfaces_values.has_key('id'):
del host_interfaces_values['id']
if host_interfaces_values.get('vf'):
host_interfaces_values['is_support_vf'] = True
host_interface_ref = models.HostInterface()
host_interface_ref.update(host_interfaces_values)
host_interface_ref.host_id = host_id
_update_values(host_interface_ref, host_interfaces_values)
host_interface_ref.save(session=session)
if host_interfaces_values.get('vf'):
_update_host_interface_vf_info(context,
host_id,
host_interface_ref.id,
host_interfaces_values.get('vf'),
session)
if values.has_key('cluster'):
if network.has_key('assigned_networks'):
@ -837,10 +845,19 @@ def _host_update(context, values, host_id):
host_interfaces_values['is_deployment'] = 1
else:
host_interfaces_values['is_deployment'] = 0
if host_interfaces_values.get('vf'):
host_interfaces_values['is_support_vf'] = True
host_interfaces_values['host_id'] = host_ref.id
host_interface_ref.update(host_interfaces_values)
_update_values(host_interface_ref, host_interfaces_values)
host_interface_ref.save(session=session)
if host_interfaces_values.get('vf'):
_update_host_interface_vf_info(context,
host_ref.id,
host_interface_ref.id,
host_interfaces_values.get('vf'),
session)
if values.has_key('cluster'):
if network.has_key('assigned_networks'):
@ -932,36 +949,42 @@ def get_host_interface(context, host_id, mac=None, session=None,
query = query.filter_by(deleted=False)
host_interface = query.all()
pf_host_interface = []
for interface in host_interface:
assigned_networks_list = []
openvswitch_type = ''
assignnetwork_query = \
session.query(models.AssignedNetworks).filter_by(
interface_id=interface.id).filter_by(deleted=False)
assignnetwork_list = assignnetwork_query.all()
for assignnetwork in assignnetwork_list:
query_network = \
session.query(models.Network).filter_by(
id=assignnetwork.network_id).filter_by(
deleted=False).first()
if query_network:
assigned_networks_info = {'name': query_network.name,
'ip': assignnetwork.ip,
'type': query_network.network_type}
if not interface.is_vf:
pf_host_interface.append(interface)
assigned_networks_list = []
openvswitch_type = ''
assignnetwork_query = \
session.query(models.AssignedNetworks).filter_by(
interface_id=interface.id).filter_by(deleted=False)
assignnetwork_list = assignnetwork_query.all()
for assignnetwork in assignnetwork_list:
query_network = \
session.query(models.Network).filter_by(
id=assignnetwork.network_id).filter_by(
deleted=False).first()
if query_network:
assigned_networks_info = {'name': query_network.name,
'ip': assignnetwork.ip,
'type': query_network.network_type}
assigned_networks_list.append(assigned_networks_info)
if query_network.network_type in ['DATAPLANE']:
openvswitch_type = assignnetwork.vswitch_type
interface.assigned_networks = assigned_networks_list
interface.vswitch_type = openvswitch_type
assigned_networks_list.append(assigned_networks_info)
if query_network.network_type in ['DATAPLANE']:
openvswitch_type = assignnetwork.vswitch_type
interface.assigned_networks = assigned_networks_list
interface.vswitch_type = openvswitch_type
if interface.is_support_vf:
vf_infos = [inter.to_dict() for inter in host_interface if inter.parent_id==interface.id]
interface.vf = sorted(vf_infos, key=lambda x: x["vf_index"])
except sa_orm.exc.NoResultFound:
msg = "No host found with ID %s" % host_id
LOG.debug(msg)
raise exception.NotFound(msg)
return host_interface
return pf_host_interface
def get_host_interface_mac(context, mac, session=None,
@ -969,7 +992,7 @@ def get_host_interface_mac(context, mac, session=None,
session = session or get_session()
try:
query = session.query(models.HostInterface).filter_by(
mac=mac).filter_by(deleted=False)
mac=mac).filter_by(deleted=False).filter_by(is_vf=False)
if not force_show_deleted and not context.can_see_deleted:
query = query.filter_by(deleted=False)
@ -4459,7 +4482,7 @@ def get_ip_of_ssh_discover_host(session):
ssh_host_ip_list = []
for item in query.all():
ip_query_sql = "select ip from host_interfaces where host_interfaces." \
"host_id='%s'" % item.HostInterface.host_id
"host_id='%s' and is_vf=0" % item.HostInterface.host_id
ip_query_result = session.execute(ip_query_sql).fetchall()
ip_query_list = [item[0] for item in ip_query_result if item[0]]
ssh_host_ip_list.extend(ip_query_list)
@ -5588,7 +5611,7 @@ def host_template_get_all(context, filters=None, marker=None, limit=None,
def host_interfaces_get_all(context, filters=None):
filters = filters or {}
session = get_session()
query = session.query(models.HostInterface).filter_by(deleted=0)
query = session.query(models.HostInterface).filter_by(deleted=0).filter_by(is_vf=False)
if 'host_id' in filters:
host_id = filters.pop('host_id')
@ -5604,6 +5627,8 @@ def host_interfaces_get_all(context, filters=None):
query = query.filter_by(pci=pci)
host_interfaces = []
for host_interface in query.all():
if host_interface.is_support_vf:
host_interface.vf = _get_host_interface_vf_info(context,host_interface.id,session)
host_interface = host_interface.to_dict()
host_interfaces.append(host_interface)
return host_interfaces
@ -6441,3 +6466,47 @@ def template_service_get_all(context, filters=None, marker=None, limit=None,
for template_service in template_services
if template_service["id"] in service_ids]
return template_services
def _get_host_interface_vf_info(context, pf_interface_id, session = None):
session = session or get_session()
query = session.query(models.HostInterface).filter_by(deleted = False)
if pf_interface_id:
query = query.filter_by(parent_id = pf_interface_id)
else:
msg = "Physical interface ID is NULL"
LOG.error(msg)
raise exception.NotFound(msg)
query = _paginate_query(query, models.HostInterface, None,
['vf_index'],sort_dir = 'asc')
vf_infos = []
for vf_info in query.all():
vf_dict = vf_info.to_dict()
vf_infos.append(vf_dict)
return vf_infos
def _update_host_interface_vf_info(context, host_id, pf_interface_id, vf_values, session):
if vf_values and session:
if not isinstance(vf_values, list):
vf_values = list(eval(vf_values))
for vm_info in vf_values:
if 'slaves' in vm_info:
slaves = vm_info.get('slaves', "")
slaves = slaves.split()
if len(slaves) == 1:
vm_info['slave1'] = slaves[0]
elif len(slaves) == 2:
vm_info['slave1'] = slaves[0]
vm_info['slave2'] = slaves[1]
del vm_info['slaves']
if vm_info.has_key('index'):
vm_info['vf_index'] = vm_info['index']
if vm_info.has_key('id'):
del vm_info['id']
vm_info['is_vf'] = True
vm_info['parent_id'] = pf_interface_id
vm_info['host_id'] = host_id
host_interface_ref = models.HostInterface()
host_interface_ref.update(vm_info)
_update_values(host_interface_ref, vm_info)
host_interface_ref.save(session = session)

View File

@ -0,0 +1,55 @@
# Copyright 2013 OpenStack Foundation
# All Rights Reserved.
#
# 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.
from sqlalchemy import MetaData, Table, Column, String, Integer, Boolean
parent_id = Column('parent_id', String(36))
vf_index = Column('vf_index', Integer)
is_support_vf = Column('is_support_vf', Boolean, default=0)
is_vf = Column('is_vf', Boolean, default=0)
#vxlan+sriov need svlan,default 3000:4094
svlan_start = Column('svlan_start', Integer, default=3000)
svlan_end = Column('svlan_end', Integer, default=4094)
def upgrade(migrate_engine):
print("030 upgrade")
meta = MetaData()
meta.bind = migrate_engine
host_interfaces = Table('host_interfaces', meta, autoload=True)
host_interfaces.create_column(is_support_vf)
host_interfaces.create_column(is_vf)
host_interfaces.create_column(parent_id)
host_interfaces.create_column(vf_index)
networks = Table('networks', meta, autoload=True)
networks.create_column(svlan_start)
networks.create_column(svlan_end)
def downgrade(migrate_engine):
print("030 downgrade")
meta = MetaData()
meta.bind = migrate_engine
host_interfaces = Table('host_interfaces', meta, autoload=True)
host_interfaces.drop_column(parent_id)
host_interfaces.drop_column(vf_index)
host_interfaces.drop_column(is_support_vf)
host_interfaces.drop_column(is_vf)
networks = Table('networks', meta, autoload=True)
networks.drop_column(svlan_start)
networks.drop_column(svlan_end)

View File

@ -286,6 +286,10 @@ class HostInterface(BASE, DaisyBase):
state = Column(String(64))
max_speed = Column(String(64))
current_speed = Column(String(64))
parent_id = Column(String(36))
vf_index = Column(Integer)
is_support_vf = Column(Boolean, default=False)
is_vf = Column(Boolean, default=False)
class Network(BASE, DaisyBase):
@ -316,6 +320,8 @@ class Network(BASE, DaisyBase):
mtu = Column(Integer(), nullable=False, default=1500)
alias = Column(String(255))
custom_name = Column(String(255))
svlan_start = Column(Integer, default=3000)
svlan_end = Column(Integer, default=4094)
class IpRange(BASE, DaisyBase):

View File

@ -0,0 +1,66 @@
# Copyright 2010 OpenStack Foundation
# All Rights Reserved.
#
# 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.
import routes
import webob
import webob.dec
import webob.request
from daisy.common import wsgi
from daisy import context
class FakeRouter(wsgi.Router):
def __init__(self, ext_mgr=None):
pass
@webob.dec.wsgify
def __call__(self, req):
res = webob.Response()
res.status = '200'
res.headers['X-Test-Success'] = 'True'
return res
class FakeRequestContext(context.RequestContext):
def __init__(self, *args, **kwargs):
kwargs['auth_token'] = kwargs.get('auth_token', 'fake_auth_token')
return super(FakeRequestContext, self).__init__(*args, **kwargs)
class HTTPRequest(webob.Request):
@classmethod
def blank(cls, *args, **kwargs):
kwargs['base_url'] = 'http://localhost:29292/v1'
use_admin_context = kwargs.pop('use_admin_context', False)
out = wsgi.Request.blank(*args, **kwargs)
out.context = FakeRequestContext(
'fake_user',
'fake',
is_admin=use_admin_context)
return out
class TestRouter(wsgi.Router):
def __init__(self, controller):
mapper = routes.Mapper()
mapper.resource("test",
"tests",
controller=wsgi.Resource(controller))
super(TestRouter, self).__init__(mapper)

File diff suppressed because it is too large Load Diff

View File

@ -282,3 +282,56 @@ class TestApiCommon(test.TestCase):
common.valid_ip_ranges_with_cidr,
ip_ranges,
cidr)
def test_valid_network_range(self):
range = [1, 4094]
network_meta = {}
vlan_start = 'vlan_start'
vlan_end = 'vlan_end'
value_start = 1
value_end = 4095
network_meta[vlan_start] = value_start
try:
common.valid_network_range(self.req, network_meta)
except exc.HTTPBadRequest as e:
msg = "%s and %s must be appeared "\
"at the same time" % (vlan_start, vlan_end)
self.assertEqual(e.explanation, msg)
network_meta[vlan_end] = value_end
try:
common.valid_network_range(self.req, network_meta)
except exc.HTTPBadRequest as e:
msg = "%s:%d and %s:%d must be in %d~%d and " \
"start:%d less than end:%d"\
% (vlan_start, value_start, vlan_end, value_end,
range[0], range[1], value_start, value_end)
self.assertEqual(e.explanation, msg)
network_meta[vlan_end] = value_end-1
result = common.valid_network_range(self.req, network_meta)
self.assertEqual(result, None)
svlan_start = 'svlan_start'
svlan_end = 'svlan_end'
network_meta[svlan_start] = value_start
try:
common.valid_network_range(self.req, network_meta)
except exc.HTTPBadRequest as e:
msg = "%s and %s must be appeared "\
"at the same time" % (svlan_start, svlan_end)
self.assertEqual(e.explanation, msg)
network_meta[svlan_end] = value_end
try:
common.valid_network_range(self.req, network_meta)
except exc.HTTPBadRequest as e:
msg = "%s:%d and %s:%d must be in %d~%d " \
"and start:%d less than end:%d"\
% (svlan_start, value_start, svlan_end,
value_end, range[0], range[1], value_start, value_end)
self.assertEqual(e.explanation, msg)
network_meta[svlan_end] = value_end-1
result = common.valid_network_range(self.req, network_meta)
self.assertEqual(result, None)

File diff suppressed because it is too large Load Diff

View File

@ -732,3 +732,86 @@ class TestSqlalchemyApi(test.TestCase):
update_networks = \
api._network_update(self.req.context, update_info, network_id)
self.assertEqual(update_info['cidr'], update_networks['cidr'])
def test_get_host_interface_vf_info(self):
self.assertRaises(exception.NotFound,
api._get_host_interface_vf_info,
self.req.context, None)
@mock.patch('daisy.db.sqlalchemy.models.HostInterface.save')
def test_update_host_interface_vf_info(self, mock_host_interface_save):
session = FakeSession()
host_id = "9692370d-7378-4ef8-9e21-1afe5cd1564a"
pf_interface_id = "d1e5ce54-f96d-41da-8f28-4535918660b7"
vf_values = "[{'name':'ens301','index':0}]"
mock_host_interface_save.return_value = None
api._update_host_interface_vf_info(self.req.context, host_id,
pf_interface_id, vf_values, session)
self.assertTrue(mock_host_interface_save.called)
vf_values = "[{'name':'bond0_0','slaves':'enp3s0 enp3s1','index':0}]"
mock_host_interface_save.return_value = None
api._update_host_interface_vf_info(self.req.context, host_id,
pf_interface_id, vf_values, session)
self.assertTrue(mock_host_interface_save.called)
def test_add_host_interface_vf(self):
host_id = u'9692370d-7378-4ef8-9e21-1afe5cd1566c'
host_meta = {
u'name': u'host-192-168-1-102',
u'description': u'default',
u'discover_mode': u'SSH',
u'dmi_uuid': u'574775DC-0000-1000-0000-744AA400B807',
u'id': host_id,
u'interfaces': unicode([{u'bond_type': None,
u'ip': u'10.43.203.44',
u'is_deployment': False,
u'mac': u'a0:36:9f:91:85:a9',
u'max_speed': u'1000baseT/Full',
u'name': u'ens8f1.900',
u'netmask': u'255.255.254.0',
u'vf': [
{'name': 'ens301', 'index': 0}]}]),
}
api.host_add(self.req.context, host_meta)
ret = api.host_interfaces_get_all(self.req.context)
self.assertEqual(ret[0]["host_id"], host_id)
api.host_destroy(self.req.context, host_id)
def test_update_host_interface_vf(self):
host_id = u'9692370d-7378-4ef8-9e21-1afe5cd1566c'
host_meta = {
u'name': u'host-192-168-1-102',
u'description': u'default',
u'discover_mode': u'SSH',
u'dmi_uuid': u'574775DC-0000-1000-0000-744AA400B807',
u'id': host_id,
u'interfaces': unicode([{u'bond_type': None,
u'ip': u'10.43.203.44',
u'is_deployment': False,
u'mac': u'a0:36:9f:91:85:a9',
u'max_speed': u'1000baseT/Full',
u'name': u'ens8f1.900',
u'netmask': u'255.255.254.0',
u'vf': [
{'name': 'ens301', 'index': 0}]}]),
}
update_meta = {
u'interfaces': unicode([{u'bond_type': None,
u'ip': u'10.43.203.44',
u'is_deployment': False,
u'mac': u'a0:36:9f:91:85:a9',
u'max_speed': u'1000baseT/Full',
u'name': u'ens8f1.900',
u'netmask': u'255.255.254.0',
u'vf': [
{'name': 'ens301', 'index': 1}]}]),
}
api.host_add(self.req.context, host_meta)
api.host_update(self.req.context, host_id, update_meta)
ret = api.host_interfaces_get_all(self.req.context)
self.assertEqual(ret[0]["host_id"], host_id)
api.host_destroy(self.req.context, host_id)

View File

@ -28,14 +28,14 @@ UPDATE_PARAMS = ('alias', 'mtu', 'vlan_id', 'ip', 'name', 'cluster_id',
'gateway', 'cidr', 'description', 'type', 'ml2_type',
'network_type', 'physnet_name', 'capability',
'segmentation_type', 'vni_start', 'vni_end',
'gre_id_start', 'gre_id_end')
'gre_id_start', 'gre_id_end', 'svlan_start', 'svlan_end')
CREATE_PARAMS = ('alias', 'mtu', 'vlan_id', 'ip', 'id', 'name', 'cluster_id',
'ip_ranges', 'vlan_start',
'vlan_end', 'gateway', 'cidr', 'description', 'type',
'ml2_type', 'network_type', 'physnet_name', 'capability',
'segmentation_type', 'vni_start', 'vni_end', 'gre_id_start',
'gre_id_end')
'gre_id_end', 'svlan_start', 'svlan_end')
DEFAULT_PAGE_SIZE = 20

View File

@ -1395,6 +1395,12 @@ def do_config_detail(gc, args):
help='Private plane mtu.eg.:1600.')
@utils.arg('--segmentation-type', metavar='<SEGMENTATION_TYPE>',
help='network plane segmentation type.')
@utils.arg('--svlan-start', metavar='<SVLAN_START>',
help='svlan start of network.it should be a integer in "1~4096",\
and it must be appeared with svlan end')
@utils.arg('--svlan-end', metavar='<SVLAN_END>',
help='svlan end of network.it should be a integer in "1~4096",\
and it must be appeared with svlan start')
def do_network_add(gc, args):
"""Add a network."""
ip_range_list = []
@ -1482,6 +1488,12 @@ def do_network_add(gc, args):
help='alias of network')
@utils.arg('--segmentation-type', metavar='<SEGMENTATION_TYPE>',
help='network plane segmentation type.')
@utils.arg('--svlan-start', metavar='<SVLAN_START>',
help='svlan start of network.it should be a integer in "1~4096",\
and it must be appeared with svlan end')
@utils.arg('--svlan-end', metavar='<SVLAN_END>',
help='svlan end of network.it should be a integer in "1~4096",\
and it must be appeared with svlan start')
def do_network_update(gc, args):
"""Update a specific network."""
# Filter out None values

18
contrib/ironic/ironic_discoverd/process.py Normal file → Executable file
View File

@ -13,6 +13,7 @@
"""Handling introspection data from the ramdisk."""
import copy
import logging
import time
@ -53,6 +54,13 @@ def format_node_info_for_daisy_client(node_info, ipmi_addr, os_status,
interface_list = []
interfaces = node_info.get('interfaces', {})
for value in interfaces.values():
vf_list = []
vf_dict = value.get('vf')
if vf_dict:
if not isinstance(vf_dict, dict):
vf_dict = dict(eval(vf_dict))
vf_list = vf_dict.values()
slaves = []
if value.get("slaves"):
slaves = value.get("slaves").split()
@ -67,7 +75,8 @@ def format_node_info_for_daisy_client(node_info, ipmi_addr, os_status,
'current_speed': value['current_speed'],
'netmask': value['netmask'],
'type': value['type'],
'slaves': slaves
'slaves': slaves,
'vf': vf_list
}
interface_list.append(interface)
@ -115,7 +124,12 @@ def format_node_info_for_ironic(node_info):
data_dict['path'] = '/' + property + 's' + '/' + key
else:
data_dict['path'] = '/' + property + '/' + key
data_dict['value'] = value
if property == 'interfaces' and 'vf'in value:
value_copy = copy.deepcopy(value)
value_copy.pop('vf')
data_dict['value'] = value_copy
else:
data_dict['value'] = value
patch.append(data_dict)
LOG.debug('patch:%s', patch)