Browse Source

Initial submit of the networking_hpe files

Change-Id: I55e992f5c1511b954248a81d2841b69d703cf222
tags/1.0.0
stephen-ma 2 years ago
parent
commit
1dc6a3dfed
78 changed files with 6305 additions and 39 deletions
  1. +25
    -0
      devstack/README.rst
  2. +68
    -0
      devstack/plugin.sh
  3. +20
    -0
      devstack/settings
  4. +2
    -0
      doc/source/conf.py
  5. BIN
      doc/source/images/bnp_deployment.png
  6. +5
    -0
      doc/source/index.rst
  7. +79
    -3
      doc/source/usage.rst
  8. +17
    -0
      etc/hp_network_provisioning_conf.ini
  9. +14
    -0
      etc/ml2_conf_hpe.ini
  10. +16
    -0
      networking_hpe/__init__.py
  11. +44
    -0
      networking_hpe/_i18n.py
  12. +0
    -0
      networking_hpe/bnpclient/__init__.py
  13. +0
    -0
      networking_hpe/bnpclient/bnp_client_ext/__init__.py
  14. +0
    -0
      networking_hpe/bnpclient/bnp_client_ext/bnpcredential/__init__.py
  15. +180
    -0
      networking_hpe/bnpclient/bnp_client_ext/bnpcredential/_bnp_credential.py
  16. +0
    -0
      networking_hpe/bnpclient/bnp_client_ext/bnpswitch/__init__.py
  17. +140
    -0
      networking_hpe/bnpclient/bnp_client_ext/bnpswitch/_bnp_switch.py
  18. +40
    -0
      networking_hpe/bnpclient/bnp_client_ext/bnpswitch/_bnp_switchport.py
  19. +81
    -0
      networking_hpe/bnpclient/bnp_client_ext/shell.py
  20. +0
    -0
      networking_hpe/bnpclient/bnp_client_ext/v2_0/__init__.py
  21. +75
    -0
      networking_hpe/bnpclient/bnp_client_ext/v2_0/client.py
  22. +0
    -0
      networking_hpe/common/__init__.py
  23. +67
    -0
      networking_hpe/common/constants.py
  24. +47
    -0
      networking_hpe/common/exceptions.py
  25. +222
    -0
      networking_hpe/common/snmp_client.py
  26. +276
    -0
      networking_hpe/common/validators.py
  27. +0
    -0
      networking_hpe/db/__init__.py
  28. +507
    -0
      networking_hpe/db/bm_nw_provision_db.py
  29. +86
    -0
      networking_hpe/db/bm_nw_provision_models.py
  30. +0
    -0
      networking_hpe/db/migration/__init__.py
  31. +1
    -0
      networking_hpe/db/migration/alembic_migrations/README
  32. +0
    -0
      networking_hpe/db/migration/alembic_migrations/__init__.py
  33. +92
    -0
      networking_hpe/db/migration/alembic_migrations/env.py
  34. +36
    -0
      networking_hpe/db/migration/alembic_migrations/script.py.mako
  35. +1
    -0
      networking_hpe/db/migration/alembic_migrations/versions/CONTRACT_HEAD
  36. +1
    -0
      networking_hpe/db/migration/alembic_migrations/versions/EXPAND_HEAD
  37. +0
    -0
      networking_hpe/db/migration/alembic_migrations/versions/__init__.py
  38. +28
    -0
      networking_hpe/db/migration/alembic_migrations/versions/pike/contract/9f1c0061fd83_initial.py
  39. +95
    -0
      networking_hpe/db/migration/alembic_migrations/versions/pike/expand/06867195bc82_initial.py
  40. +32
    -0
      networking_hpe/db/migration/alembic_migrations/versions/start_networking_hpe.py
  41. +0
    -0
      networking_hpe/db/migration/models/__init__.py
  42. +8
    -13
      networking_hpe/db/migration/models/head.py
  43. +0
    -0
      networking_hpe/drivers/__init__.py
  44. +70
    -0
      networking_hpe/drivers/port_provisioning_driver.py
  45. +181
    -0
      networking_hpe/drivers/snmp_provisioning_driver.py
  46. +61
    -0
      networking_hpe/managers.py
  47. +0
    -0
      networking_hpe/ml2/__init__.py
  48. +0
    -0
      networking_hpe/ml2/extensions/__init__.py
  49. +353
    -0
      networking_hpe/ml2/extensions/bnp_credential.py
  50. +372
    -0
      networking_hpe/ml2/extensions/bnp_switch.py
  51. +155
    -0
      networking_hpe/ml2/extensions/bnp_switchport.py
  52. +40
    -0
      networking_hpe/ml2/hpe_ironic_credential_ext_driver.py
  53. +40
    -0
      networking_hpe/ml2/hpe_ironic_switch_ports_ext_driver.py
  54. +40
    -0
      networking_hpe/ml2/hpeironicextensiondriver.py
  55. +448
    -0
      networking_hpe/ml2/mechanism_hpe.py
  56. +2
    -2
      networking_hpe/tests/base.py
  57. +0
    -0
      networking_hpe/tests/unit/bnpclient/__init__.py
  58. +106
    -0
      networking_hpe/tests/unit/bnpclient/test_cli20.py
  59. +389
    -0
      networking_hpe/tests/unit/bnpclient/test_cli20_bnp_credential_ext.py
  60. +180
    -0
      networking_hpe/tests/unit/bnpclient/test_cli20_bnp_switch_ext.py
  61. +0
    -0
      networking_hpe/tests/unit/common/__init__.py
  62. +134
    -0
      networking_hpe/tests/unit/common/test_snmp_client.py
  63. +0
    -0
      networking_hpe/tests/unit/db/__init__.py
  64. +210
    -0
      networking_hpe/tests/unit/db/test_bm_nw_provision_db.py
  65. +0
    -0
      networking_hpe/tests/unit/drivers/__init__.py
  66. +154
    -0
      networking_hpe/tests/unit/drivers/test_snmp_driver.py
  67. +0
    -0
      networking_hpe/tests/unit/ml2/__init__.py
  68. +0
    -0
      networking_hpe/tests/unit/ml2/extensions/__init__.py
  69. +525
    -0
      networking_hpe/tests/unit/ml2/extensions/test_bnp_credential.py
  70. +192
    -0
      networking_hpe/tests/unit/ml2/extensions/test_bnp_switch.py
  71. +57
    -0
      networking_hpe/tests/unit/ml2/extensions/test_bnp_switchport.py
  72. +222
    -0
      networking_hpe/tests/unit/ml2/test_mechanism_hpe.py
  73. +3
    -2
      requirements.txt
  74. +28
    -5
      setup.cfg
  75. +1
    -1
      setup.py
  76. +11
    -5
      test-requirements.txt
  77. +7
    -4
      tools/tox_install.sh
  78. +19
    -4
      tox.ini

+ 25
- 0
devstack/README.rst View File

@@ -0,0 +1,25 @@
==================================================================
Enabling Networking-hpe Baremetal Network Provisioning in Devstack
==================================================================

1. Download DevStack

2. Add this repo as an external repository for Baremetal network provisoning (BNP)::

> cat local.conf
[[local|localrc]]
enable_plugin networking-hpe https://git.openstack.org/openstack/networking-hpe
enable_service networking-hpe-plugin

3. Add the following required flag in local.conf to enable BNP ML2 MechanismDriver::

Q_ML2_PLUGIN_MECHANISM_DRIVERS=openvswitch,l2population,hpe_bnp

4. Add the following required flag in local.conf to enable BNP Extension driver::

#append the below lines
Q_ML2_PLUGIN_EXT_DRIVERS=port_security,bnp_ext_driver,bnp_cred_ext_driver,bnp_switch_ports_ext_driver

5. Read the settings file for more details.

6. run ``stack.sh``

+ 68
- 0
devstack/plugin.sh View File

@@ -0,0 +1,68 @@
#!/bin/bash
# devstack/plugin.sh
# Functions to control the configuration and operation of the networking-hpe baremetal network provisioning (bnp)
# Dependencies:
#
# ``functions`` file
# ``DEST`` must be defined
# ``STACK_USER`` must be defined
# ``stack.sh`` calls the entry points in this order:
# Save trace setting

XTRACE=$(set +o | grep xtrace)
set +o xtrace
source $TOP_DIR/lib/neutron-legacy

function install_bnp {
setup_develop $BNP_DIR
}

function run_bnp_alembic_migration {
$NEUTRON_BIN_DIR/neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head
}

function configure_bnp_plugin {
if [ ! -d $NEUTRON_CONF_DIR ]; then
sudo mkdir -p $NEUTRON_CONF_DIR
sudo chown -R $STACK_USER:root /etc/neutron
fi
cp $BNP_DIR/etc/ml2_conf_hpe.ini $BNP_ML2_CONF_HPE_FILE
neutron_server_config_add $BNP_ML2_CONF_HPE_FILE
iniset $BNP_ML2_CONF_HPE_FILE default snmp_timeout $SNMP_TIMEOUT
iniset $BNP_ML2_CONF_HPE_FILE default snmp_retries $SNMP_RETRIES
iniadd $BNP_ML2_CONF_HPE_FILE ml2_hpe provisioning_driver $HPE_SNMP
iniset $BNP_ENTRY_POINT_FILE neutron.ml2.mechanism_drivers hpe_bnp $HPE_MECHANISM_DRIVER
iniset $BNP_ENTRY_POINT_FILE neutron.ml2.extension_drivers bnp_ext_driver $BNP_EXTENSION_DRIVER
iniset $BNP_ENTRY_POINT_FILE neutron.ml2.extension_drivers bnp_cred_ext_driver $BNP_CRED_EXT_DRIVER
iniset $BNP_ENTRY_POINT_FILE neutron.ml2.extension_drivers bnp_switch_ports_ext_driver $BNP_SWITCH_PORTS_EXT_DRIVER
}


# main loop
if is_service_enabled networking-hpe-plugin; then
if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then
# no-op
:
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
install_bnp
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
configure_bnp_plugin
run_bnp_alembic_migration
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
# no-op
:
fi

if [[ "$1" == "unstack" ]]; then
# no-op
:
fi

if [[ "$1" == "clean" ]]; then
# no-op
:
fi
fi

# Restore xtrace
$XTRACE

+ 20
- 0
devstack/settings View File

@@ -0,0 +1,20 @@
# Devstack settings
BNP_DIR=$DEST/networking-hpe
BNP_ML2_CONF_HPE_FILE=/etc/neutron/plugins/ml2/ml2_conf_hpe.ini
BNP_ENTRY_POINT_FILE=/opt/stack/neutron/neutron.egg-info/entry_points.txt
NEUTRON_CONF_DIR=/etc/neutron/plugins/ml2
HPE_MECHANISM_DRIVER=networking_hpe.ml2.mechanism_hpe:HPEMechanismDriver
BNP_EXTENSION_DRIVER=networking_hpe.ml2.hpeironicextensiondriver:HPEIronicExtensionDriver
BNP_CRED_EXT_DRIVER=networking_hpe.ml2.hpe_ironic_credential_ext_driver:HPEIronicCredentialExtDriver
BNP_SWITCH_PORTS_EXT_DRIVER=networking_hpe.ml2.hpe_ironic_switch_ports_ext_driver:HPEIronicSwitchPortsExtDriver
HPE_SNMP=hpe_snmp
#
# Each service you enable has the following meaning:
# networking-hpe-plugin - Add this config flag to enable bnp service plugin
#
# An example of enabling networking-hpe-plugin is below.
# enable_service networking-hpe-plugin
#
# This can be overridden in the localrc file
SNMP_TIMEOUT=${SNMP_TIMEOUT:-3}
SNMP_RETRIES=${SNMP_RETRIES:-5}

+ 2
- 0
doc/source/conf.py View File

@@ -1,3 +1,5 @@
# Copyright (c) 2015 OpenStack Foundation
#
# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

BIN
doc/source/images/bnp_deployment.png View File

Before After
Width: 902  |  Height: 429  |  Size: 112KB

+ 5
- 0
doc/source/index.rst View File

@@ -1,3 +1,8 @@
.. networking-hpe documentation master file, created by
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.

Welcome to networking-hpe's documentation!
========================================================


+ 79
- 3
doc/source/usage.rst View File

@@ -1,7 +1,83 @@

========
Usage
Overview
========
.. _whatisbnp:

1. What is Networking HPE (NHPE)
================================

Openstack Ironic project deals with provisioning BM servers. However, plumbing of BM servers into tenant networks has been a manual procedure by the Cloud Admin .Within the timeframe of Liberty/Mitaka release of Openstack, we are attempting to spruce-up ironic to automate plumbing BM servers into tenant networks. Since Openstack Neutron project deals with plumbing ports on tenant-network in the cloud, Ironic has requested the Neutron team to provide enhancement to enable plumb the BM server ports into Cloud infrastructure (part of solution).Initially, Openstack Neutron will be extended to allow plumbing of BM server ports into only VLAN-based networks. These networks could either be a boot up network (ie., PXE booting network for BM servers) , or tenant network (for cloud to BM server communication) or cleaning-network (for recovering BM server used IP namespaces).

To support this neutron has added new vnic_type as 'baremetal' and ironic supplied the link_local_information in the binding:profile dict of port .

.. _model:
2. NHPE models
==============
NHPE introduces various models to describe the relationship between neutron ports and the physical ports.

.. _cli:
3. NHPE CLI's
=============

Create Switch:

neutron-bnp switch-create $switch_ip $vendor_name $protocol --access_parameters write_community=$community_string

Show Switch:

neutron-bnp switch-show <switch_id>

List Switch:

neutron-bnp switch-list

Delete switch:
This happens in 2 steps:
a. Disable the switch: neutron-bnp switch-update <switch_id> --enable=False
b. Delete the switch: neutron-bnp switch-delete <switch_id>

Update Switch:

neutron-bnp switch-update $switch_id --enable False --rediscover True
neutron-bnp switch-update $switch_id --rediscover True

.. _deployment:
4. Deployment Components
========================
.. image:: images/bnp_deployment.png
:height: 225px
:width: 450px
:align: center

.. _enablement:
5. Enable NHPE code in devstack
===============================
Refer the below link
https://github.com/hp-networking/baremetal-network-provisioning/blob/master/devstack/README.rst

.. _mechanism_driver:
6. Mechanism Driver Actions
===========================

Mechanism driver is listening for PortContext events from the ML2 Plugin .
Implemented create_port_precommit(), update_port_precommit(), delete_port_precommit() & bind_port()
only bind_port() calls make the SNMP request to the switch.

when ironic invokes the neutron port-create calls to the neutron then mechanism driver takes the action accordingly.
The mechanism driver acts based on VNIC_TYPE =='baremetal' and process the neutron ports.

The physical information like switch_id and port_id is fetched from the 'local_link_information' list from portbindings.PROFILE

.. _supported_switches:
7. Supported Switches
===========================
The following switches are supported in this project
5900, 5920, 5930, 5700, 7900

To use networking-hpe in a project::
.. _references:
8. References
=============
https://specs.openstack.org/openstack/ironic-specs/specs/not-implemented/network-provider.html
https://specs.openstack.org/openstack/ironic-specs/specs/not-implemented/ironic-ml2-integration.html

import networking_hpe

+ 17
- 0
etc/hp_network_provisioning_conf.ini View File

@@ -0,0 +1,17 @@
# Configuration for the HPE MechanismDriver

[default]
# HPE SDN controller base REST URL(string value)
# If this is not set then no HTTP requests will be made.
# base_url = https://127.0.0.1:8443/sdn/ui/nvf/app/rs/nvf

# auth token for HTTP basic authentication to SDN controller(string value)
# auth_token =

# Timeout in seconds to wait for SDN Controller request completion.(integer value)
# This is an optional parameter, default value is 30 seconds.
# timeout = 30

# Option full path to the file containing the SDN Controller's(string value)
# public key certificate (defaults to None).
# ca_cert = /opt/stack/data/certificates

+ 14
- 0
etc/ml2_conf_hpe.ini View File

@@ -0,0 +1,14 @@
[ml2_hpe]
# (StrOpt) Back end driver
#
# net_provisioning_driver =
# Example : net_provisioning_driver = baremetal_network_provisioning.drivers.hp.hp_snmp_provisioning_driver.HPSNMPProvisioningDriver

[default]
# snmp_timeout =
# Example snmp_timeout = 3
#(IntOpt)Timeout in seconds to wait for SNMP request completion

# snmp_retries
# Example snmp_retries = 5
# (IntOpt) Number of retries to be done for the SNMP request after the timeout

+ 16
- 0
networking_hpe/__init__.py View File

@@ -12,8 +12,24 @@
# License for the specific language governing permissions and limitations
# under the License.

import gettext

from debtcollector import removals
import pbr.version
import six


__version__ = pbr.version.VersionInfo(
'networking_hpe').version_string()


if six.PY2:
gettext.install('networking_hpe', unicode=1)
else:
gettext.install('networking_hpe')


# flake8: noqa
six.moves.builtins.__dict__['_'] = removals.remove(
message='Builtin _ translation function is deprecated in OpenStack; '
'use the function from _i18n module for your project.')(_)

+ 44
- 0
networking_hpe/_i18n.py View File

@@ -0,0 +1,44 @@
# Copyright (c) 2017 Hewlett-Packard Enterprise Development, L.P.
#
# 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 oslo_i18n


DOMAIN = "networking-hpe"

_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN)

# The primary translation function using the well-known name "_"
_ = _translators.primary

# The contextual translation function using the name "_C"
_C = _translators.contextual_form

# The plural translation function using the name "_P"
_P = _translators.plural_form

# Translators for log levels.
#
# The abbreviated names are meant to reflect the usual use of a short
# name like "-'. The "L" is for "log" and the other letter comes from
# the level.
_LI = _translators.log_info
_LW = _translators.log_warning
_LE = _translators.log_error
_LC = _translators.log_critical


def get_available_languages():
return oslo_i18n.get_available_languages(DOMAIN)

+ 0
- 0
networking_hpe/bnpclient/__init__.py View File


+ 0
- 0
networking_hpe/bnpclient/bnp_client_ext/__init__.py View File


+ 0
- 0
networking_hpe/bnpclient/bnp_client_ext/bnpcredential/__init__.py View File


+ 180
- 0
networking_hpe/bnpclient/bnp_client_ext/bnpcredential/_bnp_credential.py View File

@@ -0,0 +1,180 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development, L.P.
# 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 neutronclient.common import exceptions
from neutronclient.common import extension
from neutronclient.common import utils

from networking_hpe.common import constants as const

meta_snmpv1_v2 = 'write_community=WRITE_COMMUNITY'
meta_snmpv3 = ('security_name=SECURITY_NAME,'
'auth_protocol=AUTH_PROTOCOL,'
'priv_protocol=PRIV_PROTOCOL,'
'auth_key=AUTH_KEY,'
'priv_key=PRIV_KEY')
meta_netconf_ssh = ('user_name=USER_NAME,'
'password=PASSWORD,'
'key_path=KEY_PATH')
meta_netconf_soap = ('user_name=USER_NAME,'
'password=PASSWORD')


def check_multiple_args(args, attribute):
if len(args) > 1:
raise exceptions.CommandError(_('Attribute \'%s\' given'
' multiple times') % attribute)


class BnpCredential(extension.NeutronClientExtension):
resource = const.BNP_CREDENTIAL_RESOURCE_NAME
resource_plural = '%ss' % resource
path = 'bnp-credentials'
object_path = '/%s' % path
resource_path = '/%s/%%s' % path
versions = ['2.0']


class UpdateCredentialSnmpNetconfMixin(object):

def add_arguments_snmp_netconf(self, parser):
group_snmp_netconf = parser.add_mutually_exclusive_group()
group_snmp_netconf.add_argument('--snmpv1',
metavar=meta_snmpv1_v2,
action='append',
type=utils.str2dict_type(
optional_keys=['write_community']),
dest='snmpv1', help=_('SNMPV1 access '
'credentials for'
' physical'
' switch.')
)
group_snmp_netconf.add_argument('--snmpv2c',
metavar=meta_snmpv1_v2,
action='append', dest='snmpv2c',
type=utils.str2dict_type(
optional_keys=['write_community']),
help=_('SNMPV2c access credentials'
' for physical switch.'))
group_snmp_netconf.add_argument('--snmpv3', metavar=meta_snmpv3,
action='append', dest='snmpv3',
type=utils.str2dict_type(
optional_keys=[
'security_name',
'auth_protocol',
'priv_protocol', 'auth_key',
'priv_key']),
help=_('SNMPV3 access credentials for'
' physical switch.'))
group_snmp_netconf.add_argument('--netconf-ssh',
metavar=meta_netconf_ssh,
action='append', dest='netconf_ssh',
type=utils.str2dict_type(
optional_keys=['user_name',
'password',
'key_path']),
help=_('NETCONF-SSH access credentials'
' for physical switch.'
' Absolute path has to be pro'
'vided for key_path.'))

group_snmp_netconf.add_argument('--netconf-soap',
metavar=meta_netconf_soap,
action='append', dest='netconf_soap',
type=utils.str2dict_type(
optional_keys=['user_name',
'password']),
help=_('NETCONF-SOAP access'
' credentials for physical'
' switch.'))

def args2body_snmp_netconf(self, parsed_args, body):
if parsed_args.snmpv1:
check_multiple_args(parsed_args.snmpv1, '--snmpv1')
body[const.BNP_CREDENTIAL_RESOURCE_NAME]['snmpv1'] = (
parsed_args.snmpv1[0])
elif parsed_args.snmpv2c:
check_multiple_args(parsed_args.snmpv2c, '--snmpv2c')
body[const.BNP_CREDENTIAL_RESOURCE_NAME]['snmpv2c'] = (
parsed_args.snmpv2c[0])
elif parsed_args.snmpv3:
check_multiple_args(parsed_args.snmpv3, '--snmpv3')
body[const.BNP_CREDENTIAL_RESOURCE_NAME]['snmpv3'] = (
parsed_args.snmpv3[0])
elif parsed_args.netconf_ssh:
check_multiple_args(parsed_args.netconf_ssh, '--netconf-ssh')
body[const.BNP_CREDENTIAL_RESOURCE_NAME]['netconf_ssh'] = (
parsed_args.netconf_ssh[0])
elif parsed_args.netconf_soap:
check_multiple_args(parsed_args.netconf_soap, '--netconf-soap')
body[const.BNP_CREDENTIAL_RESOURCE_NAME]['netconf_soap'] = (
parsed_args.netconf_soap[0])


class BnpCredentialCreate(extension.ClientExtensionCreate, BnpCredential,
UpdateCredentialSnmpNetconfMixin):

"""Create credential for a physical switch."""

shell_command = 'credential-create'

def add_known_arguments(self, parser):
parser.add_argument('name', metavar='CRED_NAME',
help=_('credential name'))
self.add_arguments_snmp_netconf(parser)

def args2body(self, parsed_args):

body = {const.BNP_CREDENTIAL_RESOURCE_NAME: {
'name': parsed_args.name}}
self.args2body_snmp_netconf(parsed_args, body)
return body


class BnpCredentialUpdate(extension.ClientExtensionUpdate, BnpCredential,
UpdateCredentialSnmpNetconfMixin):

"""Update credential's information of a physical switch."""
shell_command = 'credential-update'

def add_known_arguments(self, parser):
self.add_arguments_snmp_netconf(parser)

def args2body(self, parsed_args):
body = {const.BNP_CREDENTIAL_RESOURCE_NAME: {}}
self.args2body_snmp_netconf(parsed_args, body)
return body


class BnpCredentialList(extension.ClientExtensionList, BnpCredential):

"""List credential's of a physical switch."""
shell_command = 'credential-list'
listcolumns = ['id', 'name', 'type']
pagination_support = True
sorting_support = True


class BnpCredentialShow(extension.ClientExtensionShow, BnpCredential):

"""Show credential information of a physical switch."""
shell_command = 'credential-show'


class BnpCredentialDelete(extension.ClientExtensionDelete, BnpCredential):

"""Delete credential information of a physical switch."""
shell_command = 'credential-delete'

+ 0
- 0
networking_hpe/bnpclient/bnp_client_ext/bnpswitch/__init__.py View File


+ 140
- 0
networking_hpe/bnpclient/bnp_client_ext/bnpswitch/_bnp_switch.py View File

@@ -0,0 +1,140 @@
# Copyright (c) 2015 Hewlett-Packard Enterprise Development, L.P.
# 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 neutronclient.common import extension
from neutronclient.neutron import v2_0 as neutronV20

from networking_hpe.common import constants as const


class BnpSwitch(extension.NeutronClientExtension):
resource = const.BNP_SWITCH_RESOURCE_NAME
resource_plural = '%ses' % resource
path = 'bnp-switches'
object_path = '/%s' % path
resource_path = '/%s/%%s' % path
versions = ['2.0']


class BnpSwitchCreate(extension.ClientExtensionCreate, BnpSwitch):
"""Create Physical Switch information."""
shell_command = 'switch-create'

def add_known_arguments(self, parser):

parser.add_argument('name', metavar='NAME',
help=_('Name of the physical switch.'))
parser.add_argument('ip_address', metavar='IP_ADDRESS',
help=_('IP address of the physical switch.'))
parser.add_argument('mac_address', metavar='MAC_ADDRESS',
help=_('MAC address of the physical switch.'))
parser.add_argument('vendor', metavar='VENDOR',
help=_('Vendor of the physical switch.'))
parser.add_argument('--family',
metavar='FAMILY',
help=_('Family of the physical switch.'))
parser.add_argument('--management-protocol',
metavar='MANAGEMENT_PROTOCOL',
help=_('Management protocol of the physical'
' switch.'))
parser.add_argument('--credentials',
metavar='CREDS',
help=_('Credential of the physical'
' switch.'))

def args2body(self, parsed_args):

body = {
const.BNP_SWITCH_RESOURCE_NAME: {
'name': parsed_args.name,
'ip_address': parsed_args.ip_address,
'vendor': parsed_args.vendor,
'mac_address': parsed_args.mac_address}}

neutronV20.update_dict(parsed_args, body[
const.BNP_SWITCH_RESOURCE_NAME], [
'family', 'management_protocol',
'credentials'])
return body


class BnpSwitchList(extension.ClientExtensionList, BnpSwitch):
"""List all physical switch information."""

shell_command = 'switch-list'
allow_names = True
list_columns = ['id', 'name', 'ip_address',
'mac_address', 'vendor', 'family', 'port_provisioning',
'management_protocol', 'credentials', 'validation_result']
pagination_support = True
sorting_support = True


class BnpSwitchShow(extension.ClientExtensionShow, BnpSwitch):
"""Show the physical switch information."""

shell_command = 'switch-show'
allow_names = True


class BnpSwitchDelete(extension.ClientExtensionDelete, BnpSwitch):
"""Delete the physical switch."""

shell_command = 'switch-delete'
allow_names = True


class BnpSwitchUpdate(extension.ClientExtensionUpdate, BnpSwitch):
"""Update the physical switch information."""

shell_command = 'switch-update'
allow_names = True

def add_known_arguments(self, parser):

parser.add_argument('--vendor', metavar='VENDOR',
help=_('Vendor of the physical switch.'))
parser.add_argument('--mac-address', metavar='MAC_ADDRESS',
help=_('MAC address of the physical switch.'))
parser.add_argument('--family',
metavar='FAMILY',
help=_('Family of the physical switch.'))
parser.add_argument('--port-provisioning',
metavar='{ENABLED, DISABLED}',
help=_('Port Provisioning status of '
' the physical switch.'))
parser.add_argument('--management-protocol',
metavar='MANAGEMENT_PROTOCOL',
help=_('Management protocol of the physical'
' switch.'))
parser.add_argument('--credentials',
metavar='CREDS',
help=_('Credential of the physical'
' switch.'))
parser.add_argument('--validate', action='store_true',
help=_('validate the given credentials based on'
' protocol.'))

def args2body(self, parsed_args):

body = {const.BNP_SWITCH_RESOURCE_NAME: {}}
neutronV20.update_dict(parsed_args, body[
const.BNP_SWITCH_RESOURCE_NAME], [
'name', 'vendor', 'mac_address',
'family', 'port_provisioning',
'management_protocol',
'credentials', 'validate'])
return body

+ 40
- 0
networking_hpe/bnpclient/bnp_client_ext/bnpswitch/_bnp_switchport.py View File

@@ -0,0 +1,40 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development, L.P.
#
# 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 neutronclient.common import extension


class BnpSwitchPort(extension.NeutronClientExtension):
resource = 'bnp_switch_port'
resource_plural = '%ss' % resource
path = 'bnp-switch-ports'
object_path = '/%s' % path
resource_path = '/%s/%%s' % path
versions = ['2.0']


class BnpSwitchPortList(extension.ClientExtensionList, BnpSwitchPort):
"""List all switch ports information."""

shell_command = 'switch-port-list'
allow_names = False
list_columns = ['switch_name',
'neutron_port_id',
'switch_port_name',
'segmentation_id',
'lag_id', 'bind_status',
'access_type']
pagination_support = True
sorting_support = True

+ 81
- 0
networking_hpe/bnpclient/bnp_client_ext/shell.py View File

@@ -0,0 +1,81 @@
# Copyright (c) 2015 Hewlett-Packard Enterprise Development, L.P.
# 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.
#

"""
Command-line interface to the BNP Switch APIs
"""
from __future__ import print_function

import itertools
import sys

from cliff import commandmanager
from neutronclient.common import clientmanager
from neutronclient.common import exceptions as exc
from neutronclient import shell as neutronshell
from oslo_utils import encodeutils
from stevedore import extension as ext


VERSION = '2.0'
NEUTRON_API_VERSION = '2.0'
clientmanager.neutron_client.API_VERSIONS = {
'2.0': 'networking_hpe.bnpclient.'
'bnp_client_ext.v2_0.client.Client',
}


COMMANDS = {'2.0': {}}


class BnpShell(neutronshell.NeutronShell):

def _register_extensions(self, version):
for name, module in itertools.chain(
discover_via_entry_points()):
self._extend_shell_commands(name, module, version)

def __init__(self, apiversion):
super(neutronshell.NeutronShell, self).__init__(
description=__doc__.strip(),
version=VERSION,
command_manager=commandmanager.CommandManager('bnp.cli'), )
self.commands = COMMANDS
for k, v in self.commands[apiversion].items():
self.command_manager.add_command(k, v)
self._register_extensions(VERSION)
self.auth_client = None
self.api_version = apiversion


def discover_via_entry_points():
emgr = ext.ExtensionManager('bnpclient.extension',
invoke_on_load=False)
return ((ext.name, ext.plugin) for ext in emgr)


def main(argv=sys.argv[1:]):
try:
return BnpShell(NEUTRON_API_VERSION).run(list(map(
encodeutils.safe_decode, argv)))
except exc.NeutronClientException:
return 1
except Exception:
return 1


if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))

+ 0
- 0
networking_hpe/bnpclient/bnp_client_ext/v2_0/__init__.py View File


+ 75
- 0
networking_hpe/bnpclient/bnp_client_ext/v2_0/client.py View File

@@ -0,0 +1,75 @@
# Copyright (c) 2015 Hewlett-Packard Enterprise Development, L.P.
# 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 itertools

from neutronclient import client
from neutronclient.v2_0 import client as V2_Client

from networking_hpe.bnpclient.bnp_client_ext import shell


class Client(V2_Client.Client):
"""Client for the BaremetalNetworkProvisioning v2.0 API.

:param string username: Username for authentication. (optional)
:param string user_id: User ID for authentication. (optional)
:param string password: Password for authentication. (optional)
:param string token: Token for authentication. (optional)
:param string tenant_name: Tenant name. (optional)
:param string tenant_id: Tenant id. (optional)
:param string auth_url: Keystone service endpoint for authorization.
:param string service_type: Network service type to pull from the
keystone catalog (e.g. 'network') (optional)
:param string endpoint_type: Network service endpoint type to pull from the
keystone catalog (e.g. 'publicURL',
'internalURL', or 'adminURL') (optional)
:param string region_name: Name of a region to select when choosing an
endpoint from the service catalog.
:param string endpoint_url: A user-supplied endpoint URL for the neutron
service. Lazy-authentication is possible for API
service calls if endpoint is set at
instantiation.(optional)
:param integer timeout: Allows customization of the timeout for client
http requests. (optional)
:param bool insecure: SSL certificate validation. (optional)
:param string ca_cert: SSL CA bundle file to use. (optional)
:param integer retries: How many times idempotent (GET, PUT, DELETE)
requests to Neutron server should be retried if
they fail (default: 0).
:param bool raise_errors: If True then exceptions caused by connection
failure are propagated to the caller.
(default: True)
:param session: Keystone client auth session to use. (optional)
:param auth: Keystone auth plugin to use. (optional)
"""
def _register_extensions(self, version):
for name, module in itertools.chain(
shell.discover_via_entry_points()):
self._extend_client_with_module(module, version)

def __init__(self, **kwargs):
"""Initialize new client for BaremetalNetworkProvisioning v2.0 API."""

super(Client, self).__init__()
self.retries = kwargs.pop('retries', 0)
self.raise_errors = kwargs.pop('raise_errors', True)
self.httpclient = client.construct_http_client(**kwargs)
self.version = '2.0'
self.format = 'json'
self.action_prefix = "/v%s" % (self.version)
self.retry_interval = 1
self._register_extensions(self.version)

+ 0
- 0
networking_hpe/common/__init__.py View File


+ 67
- 0
networking_hpe/common/constants.py View File

@@ -0,0 +1,67 @@
# Copyright (c) 2015 OpenStack Foundation.
# Copyright (c) 2016 Hewlett-Packard Enterprise Development L.P.
#
# 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.
# service type constants:

BNP_SWITCH_RESOURCE_NAME = 'bnp_switch'
BNP_CREDENTIAL_RESOURCE_NAME = 'bnp_credential'

NAME = 'name'
TRUNK = 'trunk'
ACCESS = 'access'
BIND_IGNORE = 'bind_ignore'
BIND_SUCCESS = 'bind_success'
BIND_FAILURE = 'bind_failure'
HP_VIF_TYPE = 'hp-ironic'

SUPPORTED_PROTOCOLS = ['snmpv1', 'snmpv2c',
'snmpv3', 'netconf_ssh', 'netconf_soap']
SUPPORTED_AUTH_PROTOCOLS = [None, 'md5', 'sha', 'sha1']
SUPPORTED_PRIV_PROTOCOLS = [None, 'des', '3des', 'aes',
'des56', 'aes128', 'aes192', 'aes256']

SNMP_V1 = 'snmpv1'
SNMP_V2C = 'snmpv2c'
SNMP_V3 = 'snmpv3'
SNMP_PORT = 161
PHY_PORT_TYPE = '6'
SNMP_NO_SUCH_INSTANCE = 'No Such'

NETCONF_SSH = 'netconf_ssh'
NETCONF_SOAP = 'netconf_soap'

OID_MAC_ADDRESS = '1.0.8802.1.1.2.1.3.2.0'
OID_IF_INDEX = '1.3.6.1.2.1.2.2.1.1'
OID_PORTS = '1.3.6.1.2.1.2.2.1.2'
OID_IF_TYPE = '1.3.6.1.2.1.2.2.1.3'
OID_PORT_STATUS = '1.3.6.1.2.1.2.2.1.8'
OID_VLAN_CREATE = '1.3.6.1.2.1.17.7.1.4.3.1.5'
OID_VLAN_EGRESS_PORT = '1.3.6.1.2.1.17.7.1.4.3.1.2'
OID_SYS_NAME = '1.3.6.1.2.1.1.5.0'
PROTOCOL_SNMP = 'snmp'
PORT_STATUS = {'1': 'UP',
'2': 'DOWN',
'3': 'TESTING',
'4': 'UNKNOWN',
'5': 'DORMANT',
'6': 'NOTPRESENT',
'7': 'LOWERLAYERDOWN'}

PORT_PROVISIONING_STATUS = {'enable': 'ENABLED',
'disable': 'DISABLED'}
SUCCESS = 'Success'
REQUEST_TIMED_OUT = 'Request Timed Out'
NO_DRVR_FOUND = 'No Provisioning driver found for given Vendor/Family/Protocol'
FAMILY = 'family'
DEVICE_NOT_REACHABLE = 'Either device is not reacheable or invalid credentials'

+ 47
- 0
networking_hpe/common/exceptions.py View File

@@ -0,0 +1,47 @@
# Copyright (c) 2015 Hewlett-Packard Enterprise LP
#
# 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.


"""Exceptions used by the networking-hpe ML2 Mechanism Driver."""

from neutron_lib import exceptions
from webob import exc


class HPNetProvisioningConfigError(exceptions.NeutronException):
message = _('%(msg)s')


class HPNetProvisioningDriverError(exceptions.NeutronException):
message = _('%(msg)s')


class SslCertificateValidationError(exceptions.NeutronException):
message = _("SSL certificate validation has failed: %(msg)s")


class ConnectionFailed(exceptions.NeutronException):
message = _(" Connection has failed: %(msg)s")


class SNMPFailure(exc.HTTPBadRequest):

def __init__(self, **kwargs):
self.explanation = self.explanation % (kwargs)
super(SNMPFailure, self).__init__()

explanation = ("SNMP operation '%(operation)s'"
"failed: Either device is not reacheable"
" or invalid credentials")

+ 222
- 0
networking_hpe/common/snmp_client.py View File

@@ -0,0 +1,222 @@
# Copyright (c) 2015 Hewlett-Packard Enterprise Development, L.P.
#
# 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 networking_hpe.common import constants
from networking_hpe.common import exceptions

import struct

from oslo_config import cfg
from oslo_log import log as logging
from pysnmp.entity.rfc3413.oneliner import cmdgen
from pysnmp import error as snmp_error
from pysnmp.proto import rfc1902

LOG = logging.getLogger(__name__)

Auth_protocol = {None: cmdgen.usmNoAuthProtocol,
'md5': cmdgen.usmHMACMD5AuthProtocol,
'sha': cmdgen.usmHMACSHAAuthProtocol}

Priv_protocol = {None: cmdgen.usmNoPrivProtocol,
'des': cmdgen.usmDESPrivProtocol,
'des56': cmdgen.usmDESPrivProtocol,
'3des': cmdgen.usm3DESEDEPrivProtocol,
'aes': cmdgen.usmAesCfb128Protocol,
'aes128': cmdgen.usmAesCfb128Protocol,
'aes192': cmdgen.usmAesCfb192Protocol,
'aes256': cmdgen.usmAesCfb256Protocol}


class SNMPClient(object):

"""SNMP client object.

"""
def __init__(self, ip_address, access_protocol,
write_community=None, security_name=None,
auth_protocol=None, auth_key=None,
priv_protocol=None, priv_key=None):
self.conf = cfg.CONF
self.ip_address = ip_address
self.access_protocol = access_protocol
self.timeout = cfg.CONF.default.snmp_timeout
self.retries = cfg.CONF.default.snmp_retries
if self.access_protocol == constants.SNMP_V3:
self.security_name = security_name
self.auth_protocol = Auth_protocol[auth_protocol]
self.auth_key = auth_key
self.priv_protocol = Priv_protocol[priv_protocol]
self.priv_key = priv_key
else:
self.write_community = write_community
self.cmd_gen = cmdgen.CommandGenerator()

def _get_auth(self):
"""Return the authorization data for an SNMP request.

"""
if self.access_protocol == constants.SNMP_V3:
return cmdgen.UsmUserData(self.security_name,
authKey=self.auth_key,
privKey=self.priv_key,
authProtocol=self.auth_protocol,
privProtocol=self.priv_protocol)
else:
mp_model = 1 if self.access_protocol == constants.SNMP_V2C else 0
return cmdgen.CommunityData(self.write_community,
mpModel=mp_model)

def _get_transport(self):
"""Return the transport target for an SNMP request.

"""
return cmdgen.UdpTransportTarget(
(self.ip_address, constants.SNMP_PORT),
timeout=self.timeout,
retries=self.retries)

def get(self, oid):
"""Use PySNMP to perform an SNMP GET operation on a single object.

"""
try:
results = self.cmd_gen.getCmd(self._get_auth(),
self._get_transport(),
oid)
except snmp_error.PySnmpError as e:
raise exceptions.SNMPFailure(operation="GET", error=e)

error_indication, error_status, error_index, var_binds = results

if error_indication:
raise exceptions.SNMPFailure(operation="GET",
error=error_indication)

if error_status:
raise exceptions.SNMPFailure(operation="GET",
error=error_status.prettyPrint())

return var_binds

def get_bulk(self, *oids):
try:
results = self.cmd_gen.bulkCmd(self._get_auth(),
self._get_transport(),
0, 52,
*oids
)
except snmp_error.PySnmpError as e:
raise exceptions.SNMPFailure(operation="GET_BULK", error=e)

error_indication, error_status, error_index, var_binds = results

if error_indication:
raise exceptions.SNMPFailure(operation="GET_BULK",
error=error_indication)

if error_status:
raise exceptions.SNMPFailure(operation="GET_BULK",
error=error_status.prettyPrint())

return var_binds

def set(self, oid, value):
"""Use PySNMP to perform an SNMP SET operation on a single object.

:param oid: The OID of the object to set.
:param value: The value of the object to set.
:raises: SNMPFailure if an SNMP request fails.
"""
try:
# oid = tuple(map(string.atoi, string.split(oid, '.')[1:]))
results = self.cmd_gen.setCmd(self._get_auth(),
self._get_transport(),
(oid, value))
except Exception as e:
raise exceptions.SNMPFailure(operation="SET", error=e)
except snmp_error.PySnmpError as e:
raise exceptions.SNMPFailure(operation="SET", error=e)

error_indication, error_status, error_index, var_binds = results
if error_indication:
# SNMP engine-level error.
raise exceptions.SNMPFailure(operation="SET",
error=error_indication)

if error_status:
# SNMP PDU error.
raise exceptions.SNMPFailure(operation="SET",
error=error_status.prettyPrint())

def get_rfc1902_integer(self, value):
return rfc1902.Integer32(value)

def get_rfc1902_octet_string(self, value):
return rfc1902.OctetString(value)

def get_bit_map_for_add(self, val, egress_byte):
ifindex = val
byte_index = int(ifindex - 1) / 8
bit_index = int(ifindex) % 8
if bit_index == 0:
bit_index = 8
target_byte = egress_byte[byte_index]
mask = 0x80
if bit_index >= 1:
mask = ((mask & 0xFF) >> (bit_index - 1))
target_byte = int('%x' % ord(target_byte), base=16)
target_byte = ((target_byte) | mask)
egress_byte = list(egress_byte)
hex_repr = []
while target_byte:
hex_repr.append(struct.pack('B', target_byte & 255))
target_byte >>= 8
egress_byte[byte_index] = hex_repr[0]
return egress_byte

def get_bit_map_for_del(self, val, egress_byte):
ifindex = val
byte_index = int(ifindex - 1) / 8
bitindex = int(ifindex) % 8
if bitindex == 0:
bitindex = 8
target_byte = egress_byte[byte_index]
mask = 0x80
if bitindex > 1:
mask = ((mask & 0xFF) >> (bitindex - 1))
mask = ~ mask
target_byte = int('%x' % ord(target_byte), base=16)
target_byte = ((target_byte) & mask)
egress_byte = list(egress_byte)
hex_repr = []
hex_repr.append(struct.pack('B', target_byte & 255))
egress_byte[byte_index] = hex_repr[0]
return egress_byte


def get_client(snmp_info):
"""Create and return an SNMP client object.

"""
return SNMPClient(snmp_info['ip_address'],
snmp_info['management_protocol'],
snmp_info['write_community'],
snmp_info['security_name'],
snmp_info['auth_protocol'],
snmp_info['auth_key'],
snmp_info['priv_protocol'],
snmp_info['priv_key']
)

+ 276
- 0
networking_hpe/common/validators.py View File

@@ -0,0 +1,276 @@
# Copyright (c) 2015 OpenStack Foundation.
# Copyright (c) 2016 Hewlett-Packard Enterprise Development L.P.
#
# 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.
# service type constants:

from simplejson import scanner as json_scanner
import webob.exc

from copy import deepcopy
import os.path

from networking_hpe.common import constants as const

from oslo_utils import uuidutils


access_parameter_keys = ['write_community', 'security_name',
'auth_protocol', 'priv_protocol', 'auth_key',
'priv_key', 'security_level']


def access_parameter_validator(data, valid_values=None):
"""Validate the access parameters."""
if not data:
# Access parameters must be provided.
msg = _("Cannot create a switch from the given input.")
return msg
if type(data) is not dict:
msg = _("Given details is not in the form of a dictionary.")
return msg


def validate_request(request):
"""Validate if the request is in proper format."""
try:
body = request.json_body
except json_scanner.JSONDecodeError:
raise webob.exc.HTTPBadRequest(
_("Invalid JSON body"))
try:
keys = list(body.keys())
if keys[0] in [const.BNP_SWITCH_RESOURCE_NAME,
const.BNP_CREDENTIAL_RESOURCE_NAME]:
body = body.pop(keys[0])
except KeyError:
raise webob.exc.HTTPBadRequest(
_("resource name not found in request body"))
return body


def validate_attributes(keys, attr_keys):
"""Validate the keys in request body."""
extra_keys = set(keys) - set(attr_keys)
if extra_keys:
msg = _("Unrecognized attribute(s) '%s'") % ', '.join(extra_keys)
raise webob.exc.HTTPBadRequest(msg)


def validate_access_parameters(body):
"""Validate if the request body is in proper format."""
protocol_dict = deepcopy(body)
if const.NAME not in protocol_dict.keys():
raise webob.exc.HTTPBadRequest(
_("Name not found in request body"))
if uuidutils.is_uuid_like(protocol_dict['name']):
raise webob.exc.HTTPBadRequest(
_("Name=%s should not be in uuid format") %
protocol_dict['name'])
protocol_dict.pop('name')
keys = list(protocol_dict.keys())
if not len(keys):
raise webob.exc.HTTPBadRequest(
_("Request body should have at least one protocol specified"))
elif len(keys) > 1:
raise webob.exc.HTTPBadRequest(
_("multiple protocols in a single request is not supported"))
key = keys[0]
if key.lower() not in const.SUPPORTED_PROTOCOLS:
raise webob.exc.HTTPBadRequest(
_("'protocol %s' is not supported") % keys)
if key.lower() == const.SNMP_V3:
return validate_snmpv3_parameters(protocol_dict, key)
elif key.lower() in [const.NETCONF_SSH, const.NETCONF_SOAP]:
return validate_netconf_parameters(protocol_dict, key)
else:
return validate_snmp_parameters(protocol_dict, key)


def validate_snmp_parameters(protocol_dict, key):
"""Validate SNMP v1 and v2c parameters."""
access_parameters = protocol_dict.pop(key)
keys = access_parameters.keys()
validate_attributes(keys, ['write_community'])
if not access_parameters.get('write_community'):
raise webob.exc.HTTPBadRequest(
_("'write_community' not found in request body"))
if key.lower() == const.SNMP_V1:
return const.SNMP_V1
else:
return const.SNMP_V2C


def validate_snmpv3_parameters(protocol_dict, key):
"""Validate SNMP v3 parameters."""
access_parameters = protocol_dict.pop(key)
keys = access_parameters.keys()
attr_keys = ['security_name', 'auth_protocol',
'auth_key', 'priv_protocol', 'priv_key']
validate_attributes(keys, attr_keys)
if not access_parameters.get('security_name'):
raise webob.exc.HTTPBadRequest(
_("security_name not found in request body"))
if access_parameters.get('auth_protocol'):
if access_parameters.get('auth_protocol').lower(
) not in const.SUPPORTED_AUTH_PROTOCOLS:
raise webob.exc.HTTPBadRequest(
_("auth_protocol %s is not supported") %
access_parameters['auth_protocol'])
elif not access_parameters.get('auth_key'):
raise webob.exc.HTTPBadRequest(
_("auth_key is required for auth_protocol %s") %
access_parameters['auth_protocol'])
elif len(access_parameters.get('auth_key')) < 8:
raise webob.exc.HTTPBadRequest(
_("auth_key %s should be equal or more than"
"8 characters") % access_parameters['auth_key'])
if access_parameters.get('priv_protocol'):
if access_parameters.get('priv_protocol').lower(
) not in const.SUPPORTED_PRIV_PROTOCOLS:
raise webob.exc.HTTPBadRequest(
_("priv_protocol %s is not supported") %
access_parameters['priv_protocol'])
elif not access_parameters.get('priv_key'):
raise webob.exc.HTTPBadRequest(
_("priv_key is required for priv_protocol %s") %
access_parameters['priv_protocol'])
elif len(access_parameters.get('priv_key')) < 8:
raise webob.exc.HTTPBadRequest(
_("'priv_key %s' should be equal or more than"
"8 characters") % access_parameters['priv_key'])
return const.SNMP_V3


def _validate_user_name_password(access_parameters):
"""Validate if the request contains user_name and password."""
if not access_parameters.get('user_name'):
raise webob.exc.HTTPBadRequest(
_("user_name not found in request body"))
elif not access_parameters.get('password'):
raise webob.exc.HTTPBadRequest(
_("password not found in request body"))


def validate_netconf_parameters(protocol_dict, key):
"""Validate NETCONF SSH/SOAP parameters."""
access_parameters = protocol_dict.pop(key)
if key.lower() == const.NETCONF_SSH:
if access_parameters.get('key_path'):
if not os.path.isfile(access_parameters.get('key_path')):
raise webob.exc.HTTPBadRequest(
_("Invalid key path"))
return const.NETCONF_SSH
_validate_user_name_password(access_parameters)
return const.NETCONF_SSH
else:
if access_parameters.get('key_path'):
raise webob.exc.HTTPBadRequest(
_("Invalid attribute key_path"))
_validate_user_name_password(access_parameters)
return const.NETCONF_SOAP


def validate_access_parameters_for_update(body):
"""Validate if the request body is in proper format."""

protocol_dict = deepcopy(body)
if (const.NAME not in protocol_dict.keys() and
not len(protocol_dict.keys())):
raise webob.exc.HTTPBadRequest(
_("Request must have name or one protocol type"))
if const.NAME in protocol_dict.keys():
if uuidutils.is_uuid_like(protocol_dict['name']):
raise webob.exc.HTTPBadRequest(
_("Name=%s should not be in uuid format") %
protocol_dict['name'])
protocol_dict.pop('name')
if protocol_dict:
keys = list(protocol_dict.keys())
if len(keys) > 1:
raise webob.exc.HTTPBadRequest(
_("Multiple protocols in a single request is not supported"))
key = keys[0]
if key.lower() not in const.SUPPORTED_PROTOCOLS:
raise webob.exc.HTTPBadRequest(
_("Protocol %s is not supported") % keys)
if key.lower() == const.SNMP_V3:
return validate_snmpv3_parameters_for_update(protocol_dict, key)
elif key.lower() in [const.NETCONF_SSH, const.NETCONF_SOAP]:
return validate_netconf_parameters_for_update(protocol_dict, key)
else:
return validate_snmp_parameters_for_update(protocol_dict, key)
else:
return None


def validate_snmpv3_parameters_for_update(protocol_dict, key):
"""Validate SNMP v3 parameters."""
access_parameters = protocol_dict.pop(key)
keys = list(access_parameters.keys())
attr_keys = ['security_name', 'auth_protocol',
'auth_key', 'priv_protocol', 'priv_key']
validate_attributes(keys, attr_keys)
if access_parameters.get('auth_protocol'):
if access_parameters.get('auth_protocol').lower(
) not in const.SUPPORTED_AUTH_PROTOCOLS:
raise webob.exc.HTTPBadRequest(
_("auth_protocol %s is not supported") %
access_parameters['auth_protocol'])
if access_parameters.get('auth_key'):
if len(access_parameters.get('auth_key')) < 8:
raise webob.exc.HTTPBadRequest(
_("auth_key %s should be equal or more than"
" 8 characters") % access_parameters['auth_key'])
if access_parameters.get('priv_protocol'):
if access_parameters.get('priv_protocol').lower(
) not in const.SUPPORTED_PRIV_PROTOCOLS:
raise webob.exc.HTTPBadRequest(
_("priv_protocol %s is not supported") %
access_parameters['priv_protocol'])
if access_parameters.get('priv_key'):
if len(access_parameters.get('priv_key')) < 8:
raise webob.exc.HTTPBadRequest(
_("priv_key %s should be equal or more than"
" 8 characters") % access_parameters['priv_key'])
return const.SNMP_V3


def validate_netconf_parameters_for_update(protocol_dict, key):
"""Validate NETCONF SSH/SOAP parameters."""
access_parameters = protocol_dict.pop(key)
if key.lower() == const.NETCONF_SSH:
keys = access_parameters.keys()
attr_keys = ['user_name', 'password', 'key_path']
validate_attributes(keys, attr_keys)
if access_parameters.get('key_path'):
if not os.path.isfile(access_parameters.get('key_path')):
raise webob.exc.HTTPBadRequest(
_("Invalid key path"))
return const.NETCONF_SSH
else:
keys = access_parameters.keys()
attr_keys = ['user_name', 'password']
validate_attributes(keys, attr_keys)
return const.NETCONF_SOAP


def validate_snmp_parameters_for_update(protocol_dict, key):
"""Validate SNMP v1 and v2c parameters."""
access_parameters = protocol_dict.pop(key)
keys = access_parameters.keys()
validate_attributes(keys, ['write_community'])
if key.lower() == const.SNMP_V1:
return const.SNMP_V1
else:
return const.SNMP_V2C

+ 0
- 0
networking_hpe/db/__init__.py View File


+ 507
- 0
networking_hpe/db/bm_nw_provision_db.py View File

@@ -0,0 +1,507 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development, L.P.
#
# 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 oslo_log import log as logging
from oslo_utils import uuidutils
from sqlalchemy.orm import exc

from neutron.db import models_v2

from networking_hpe._i18n import _LE
from networking_hpe._i18n import _LI
from networking_hpe.db import bm_nw_provision_models as models


LOG = logging.getLogger(__name__)


def get_subnets_by_network(context, network_id):
subnet_qry = context.session.query(models_v2.Subnet)
return subnet_qry.filter_by(network_id=network_id).all()


def add_bnp_phys_switch(context, switch):
"""Add physical switch."""
session = context.session
with session.begin(subtransactions=True):
uuid = uuidutils.generate_uuid()
phy_switch = models.BNPPhysicalSwitch(
id=uuid,
name=switch['name'],
ip_address=switch['ip_address'],
mac_address=switch['mac_address'],
port_provisioning=switch['port_provisioning'],
management_protocol=switch['management_protocol'],
credentials=switch['credentials'],
validation_result=switch['validation_result'],
vendor=switch['vendor'],
family=switch['family'])
session.add(phy_switch)
return phy_switch


def add_bnp_neutron_port(context, port):
"""Add neutron port."""
session = context.session
with session.begin(subtransactions=True):
neutron_port = models.BNPNeutronPort(
neutron_port_id=port['neutron_port_id'],
lag_id=port['lag_id'],
access_type=port['access_type'],
segmentation_id=port['segmentation_id'],
bind_status=port['bind_status'])
session.add(neutron_port)


def add_bnp_switch_port_map(context, mapping):
"""Add switch port to neutron port mapping."""
session = context.session
with session.begin(subtransactions=True):
port_map = models.BNPSwitchPortMapping(
neutron_port_id=mapping['neutron_port_id'],
switch_port_name=mapping['switch_port_name'],
ifindex=mapping['ifindex'],
switch_id=mapping['switch_id'])
session.add(port_map)


def get_bnp_phys_switch(context, switch_id):
"""Get physical switch that matches id."""
try:
query = context.session.query(models.BNPPhysicalSwitch)
switch = query.filter_by(id=switch_id).one()
except exc.NoResultFound:
LOG.error(_LE("no physical switch found with id: %s"), switch_id)
return
return switch


def get_bnp_phys_switch_name(context, name):
"""Get physical switch that matches name."""
try:
query = context.session.query(models.BNPPhysicalSwitch)
switch = query.filter_by(name=name).all()
except exc.NoResultFound:
LOG.error(_LE("no physical switch found with name: %s"), name)
return
return switch


def get_bnp_phys_switch_by_ip(context, ip_addr):
"""Get physical switch that matches ip address."""
try:
query = context.session.query(models.BNPPhysicalSwitch)
switch = query.filter_by(ip_address=ip_addr).one()
except exc.NoResultFound:
LOG.info(_LI("no physical switch found with ip address: %s"), ip_addr)
return
return switch


def get_if_bnp_phy_switch_exists(context, **args):
"""check if physical switch exists for a given filter."""
try:
query = context.session.query(
models.BNPPhysicalSwitch).filter_by(**args)
switch_exists = context.session.query(query.exists()).scalar()
except exc.NoResultFound:
LOG.error(_LE("no physical switch found"))
return
return switch_exists


def get_bnp_neutron_port(context, neutron_port_id):
"""Get bnp neutron port that matches neutron_port_id."""
try:
query = context.session.query(models.BNPNeutronPort)
port_map = query.filter_by(neutron_port_id=neutron_port_id).one()
except exc.NoResultFound:
LOG.error(_LE('no port map found with id: %s'), port_map)
return
return port_map


def get_bnp_neutron_port_by_seg_id(context, segmentation_id):
"""Get bnp neutron port that matches seg_id."""
try:
query = context.session.query(models.BNPNeutronPort)
port_map = query.filter_by(segmentation_id=segmentation_id).all()
except exc.NoResultFound:
LOG.error(_LE('no port map found with id: %s'), segmentation_id)
return
return port_map


def get_bnp_switch_port_map_by_switchid(context, switch_id):
"""Get switch port map by switch_id."""
try:
query = context.session.query(models.BNPSwitchPortMapping)
port_map = query.filter_by(switch_id=switch_id).all()
except exc.NoResultFound:
LOG.error(_LE("no switch port mapping found for switch: %s"),
switch_id)
return
return port_map


def get_bnp_switch_port_mappings(context, neutron_port_id):
"""Get switch port map by neutron_port_id."""
try:
query = context.session.query(models.BNPSwitchPortMapping)
port_map = query.filter_by(neutron_port_id=neutron_port_id).all()
except exc.NoResultFound:
LOG.error(_LE("no switch port mapping found for switch: %s"),
neutron_port_id)
return
return port_map


def get_all_bnp_switch_port_maps(context, filter_dict):
"""Get all switch port maps."""
try:
switchportmap = models.BNPSwitchPortMapping
neutronport = models.BNPNeutronPort
physwitch = models.BNPPhysicalSwitch
query = context.session.query(switchportmap.neutron_port_id,
switchportmap.switch_port_name,
neutronport.lag_id,
neutronport.segmentation_id,
neutronport.access_type,
neutronport.bind_status, physwitch.name)
query = query.join(neutronport,
neutronport.neutron_port_id ==
switchportmap.neutron_port_id)
query = query.join(physwitch, switchportmap.switch_id == physwitch.id)
for key, value in filter_dict.items():
query = query.filter(key == value)
port_maps = query.all()
except exc.NoResultFound:
LOG.error(_LE("no switch port mappings found"))
return
return port_maps


def get_bnp_phys_switch_by_mac(context, mac):
"""Get physical switch that matches mac address."""
try:
query = context.session.query(models.BNPPhysicalSwitch)
switch = query.filter_by(mac_address=mac).one()
except exc.NoResultFound:
LOG.error(_LE('no physical switch found with mac address: %s'), mac)
return
return switch


def delete_bnp_switch_port_mappings(context, neutron_port_id):
"""Delete mappings that matches neutron_port_id."""
session = context.session
with session.begin(subtransactions=True):
if neutron_port_id:
session.query(models.BNPSwitchPortMapping).filter_by(
neutron_port_id=neutron_port_id).delete()


def delete_bnp_phys_switch(context, switch_id):
"""Delete physical switch that matches switch_id."""
try:
session = context.session
with session.begin(subtransactions=True):
if switch_id:
session.query(models.BNPPhysicalSwitch).filter_by(
id=switch_id).delete()
except exc.NoResultFound:
LOG.error(_LE("no switch found for switch id: %s"), switch_id)


def delete_bnp_neutron_port(context, nport_id):
"""Delete neutron port that matches_id."""
session = context.session
with session.begin(subtransactions=True):
if nport_id:
session.query(models.BNPNeutronPort).filter_by(
neutron_port_id=nport_id).delete()


def get_all_bnp_phys_switches(context, **args):
"""Get all physical switches."""
try:
query = context.session.query(
models.BNPPhysicalSwitch).filter_by(**args)
switches = query.all()
except exc.NoResultFound:
LOG.error(_LE("no physical switch found"))
return
return switches


def update_bnp_phy_switch(context, sw_id, switch):
"""Update physical switch name."""
try:
with context.session.begin(subtransactions=True):
(context.session.query(models.BNPPhysicalSwitch).filter_by(
id=sw_id).update(
{'name': switch['name'],
'ip_address': switch['ip_address'],
'mac_address': switch['mac_address'],
'port_provisioning': switch['port_provisioning'],
'management_protocol': switch['management_protocol'],
'credentials': switch['credentials'],
'validation_result': switch['validation_result'],
'vendor': switch['vendor'],
'family': switch['family']},
synchronize_session=False))
except exc.NoResultFound:
LOG.error(_LE("no physical switch found for id: %s"), sw_id)


def update_bnp_phys_switch_result_status(context, sw_id, sw_status):
"""Update physical switch validation result status."""
try:
with context.session.begin(subtransactions=True):
(context.session.query(models.BNPPhysicalSwitch).filter_by(
id=sw_id).update(
{'validation_result': sw_status},
synchronize_session=False))
except exc.NoResultFound:
LOG.error(_LE("no physical switch found for id: %s"), sw_id)


def update_bnp_phys_switch_access_params(context, switch_id, params):
"""Update physical switch with access params."""
try:
with context.session.begin(subtransactions=True):
(context.session.query(models.BNPPhysicalSwitch).filter_by(
id=switch_id).update(
{'access_protocol': params['access_protocol'],
'write_community': params['write_community'],
'security_name': params['security_name'],
'auth_protocol': params['auth_protocol'],
'auth_key': params['auth_key'],
'priv_protocol': params['priv_protocol'],
'priv_key': params['priv_key'],
'security_level': params['security_level']},
synchronize_session=False))
except exc.NoResultFound:
LOG.error(_LE("no physical switch found for id: %s"), switch_id)


def update_bnp_snmp_cred_by_id(context, cred_id, creds):
"""Update snmp switch credentials."""
try:
with context.session.begin(subtransactions=True):
(context.session.query(models.BNPSNMPCredential).filter_by(
id=cred_id).update(
{'name': creds['name'],
'protocol_type': creds['protocol_type'],
'write_community': creds['write_community'],
'security_name': creds['security_name'],
'auth_protocol': creds['auth_protocol'],
'auth_key': creds['auth_key'],
'priv_protocol': creds['priv_protocol'],
'priv_key': creds['priv_key'],
'security_level': creds['security_level']},
synchronize_session=False))
except exc.NoResultFound:
LOG.error(_LE("no snmp switch credentials found for id: %s"), cred_id)


def get_snmp_cred_by_name_and_protocol(context, name, proto_type):
"""Get SNMP Credential that matches name and protocol."""
try:
query = context.session.query(models.BNPSNMPCredential)
snmp_creds = query.filter_by(name=name, protocol_type=proto_type).all()
except exc.NoResultFound:
LOG.info(
_LI("no snmp credential found with name:"
" %(name)s and protocol: %(proto_type)s"), {'name': name,
'proto_type':
proto_type})
return
return snmp_creds


def get_netconf_cred_by_name_and_protocol(context, name, proto_type):
"""Get NETCONF Credentials that matches name and protocol."""
try:
query = context.session.query(models.BNPNETCONFCredential)
netconf_creds = query.filter_by(name=name,
protocol_type=proto_type).all()
except exc.NoResultFound:
LOG.info(_LI("no netconf credential found with name:"
" %(name)s and protocol: %(proto_type)s"), {'name': name,
'proto_type':
proto_type})
return
return netconf_creds


def update_bnp_netconf_cred_by_id(context, cred_id, creds):
"""Update netconf switch credentials."""
try:
with context.session.begin(subtransactions=True):
(context.session.query(models.BNPNETCONFCredential).filter_by(
id=cred_id).update(
{'name': creds['name'],
'protocol_type': creds['protocol_type'],
'user_name': creds['user_name'],
'password': creds['password'],
'key_path': creds['key_path']},
synchronize_session=False))
except exc.NoResultFound:
LOG.error(
_LE("no netconf switch credentials found for id: %s"), cred_id)


def add_bnp_snmp_cred(context, snmp_cred):
"""Add SNMP Credential."""
session = context.session
with session.begin(subtransactions=True):
uuid = uuidutils.generate_uuid()
snmp_cred = models.BNPSNMPCredential(
id=uuid,
name=snmp_cred['name'],
protocol_type=snmp_cred['protocol_type'],
write_community=snmp_cred['write_community'],
security_name=snmp_cred['security_name'],
auth_protocol=snmp_cred['auth_protocol'],
auth_key=snmp_cred['auth_key'],
priv_protocol=snmp_cred['priv_protocol'],
priv_key=snmp_cred['priv_key'],
security_level=snmp_cred['security_level'])
session.add(snmp_cred)
return snmp_cred


def add_bnp_netconf_cred(context, netconf_cred):
"""Add NETCONF Credential."""
session = context.session
with session.begin(subtransactions=True):
uuid = uuidutils.generate_uuid()
netconf_cred = models.BNPNETCONFCredential(
id=uuid,
name=netconf_cred['name'],
protocol_type=netconf_cred['protocol_type'],
user_name=netconf_cred['user_name'],
password=netconf_cred['password'],
key_path=netconf_cred['key_path'])
session.add(netconf_cred)
return netconf_cred


def get_all_snmp_creds(context, **args):
"""Get all SNMP Credentials."""
try:
query = context.session.query(
models.BNPSNMPCredential).filter_by(**args)
snmp_creds = query.all()
except exc.NoResultFound:
LOG.error(_LE("no snmp credential found"))
return
return snmp_creds


def get_all_netconf_creds(context, **args):
"""Get all NETCONF Credentials."""
try:
query = context.session.query(
models.BNPNETCONFCredential).filter_by(**args)
netconf_creds = query.all()
except exc.NoResultFound:
LOG.error(_LE("no netconf credential found"))
return
return netconf_creds


def get_snmp_cred_by_name(context, name):
"""Get SNMP Credential that matches name."""
try:
query = context.session.query(models.BNPSNMPCredential)
snmp_creds = query.filter_by(name=name).all()
except exc.NoResultFound:
LOG.info(_LI("no snmp credential found with name: %s"), name)
return
return snmp_creds


def get_snmp_cred_by_id(context, id):
"""Get SNMP Credential that matches id."""
try:
query = context.session.query(models.BNPSNMPCredential)
snmp_cred = query.filter_by(id=id).one()
except exc.NoResultFound:
LOG.info(_LI("no snmp credential found with id: %s"), id)
return
return snmp_cred


def get_netconf_cred_by_name(context, name):
"""Get NETCONF Credential that matches name."""
try:
query = context.session.query(models.BNPNETCONFCredential)
netconf_creds = query.filter_by(name=name).all()
except exc.NoResultFound:
LOG.info(_LI("no netconf credential found with name: %s"), name)
return
return netconf_creds


def get_netconf_cred_by_id(context, id):
"""Get NETCONF Credential that matches id."""
try:
query = context.session.query(models.BNPNETCONFCredential)
netconf_cred = query.filter_by(id=id).one()
except exc.NoResultFound:
LOG.info(_LI("no netconf credential found with id: %s"), id)
return
return netconf_cred


def delete_snmp_cred_by_id(context, id):
"""Delete SNMP credential by id."""
session = context.session
with session.begin(subtransactions=True):
session.query(models.BNPSNMPCredential).filter_by(
id=id).delete()


def delete_netconf_cred_by_id(context, id):
"""Delete NETCONF credential by id."""
session = context.session
with session.begin(subtransactions=True):
session.query(models.BNPNETCONFCredential).filter_by(
id=id).delete()


def get_bnp_phys_switch_by_name(context, name):
"""Get physical switch that matches name."""
try:
query = context.session.query(models.BNPPhysicalSwitch)
switch = query.filter_by(name=name).all()
except exc.NoResultFound:
LOG.error(_LE("no physical switch found with name: %s"), name)
return
return switch


def delete_bnp_phys_switch_by_name(context, name):
"""Delete physical switch that matches name."""
try:
session = context.session
with session.begin(subtransactions=True):
if name:
session.query(models.BNPPhysicalSwitch).filter_by(
name=name).delete()
except exc.NoResultFound:
LOG.error(_LE("no switch found for switch name: %s"), name)

+ 86
- 0
networking_hpe/db/bm_nw_provision_models.py View File

@@ -0,0 +1,86 @@
# Copyright (c) 2015 OpenStack Foundation.
# Copyright (c) 2015 Hewlett-Packard Enterprise Development, L.P.
#
# 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 neutron_lib.db import model_base
import sqlalchemy as sa


class BNPPhysicalSwitch(model_base.BASEV2, model_base.HasId):
"""Define physical switch properties."""
__tablename__ = "bnp_physical_switches"
name = sa.Column(sa.String(36), nullable=False)
vendor = sa.Column(sa.String(16), nullable=False)
family = sa.Column(sa.String(16), nullable=True)
ip_address = sa.Column(sa.String(64), nullable=False)
mac_address = sa.Column(sa.String(32), nullable=True)
port_provisioning = sa.Column(sa.String(16), nullable=False)
management_protocol = sa.Column(sa.String(16), nullable=False)
credentials = sa.Column(sa.String(36), nullable=False)
validation_result = sa.Column(sa.String(255), nullable=True)
__table_args__ = (sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('ip_address', 'mac_address'))


class BNPSwitchPortMapping(model_base.BASEV2):
"""Define neutron port and switch port mapping."""
__tablename__ = "bnp_switch_port_mappings"
neutron_port_id = sa.Column(sa.String(36), nullable=False)