Initial commit for broadview-ui
Change-Id: Id9e4656d70221b6cd0c846018fc61be633db808f
This commit is contained in:
parent
12ffcc0130
commit
2f4aa82190
17
CONTRIBUTING.rst
Normal file
17
CONTRIBUTING.rst
Normal file
@ -0,0 +1,17 @@
|
||||
If you would like to contribute to the development of OpenStack, you must
|
||||
follow the steps in this page:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html
|
||||
|
||||
If you already have a good understanding of how the system works and your
|
||||
OpenStack accounts are set up, you can skip to the development workflow
|
||||
section of this documentation to learn how changes to OpenStack should be
|
||||
submitted for review via the Gerrit tool:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html#development-workflow
|
||||
|
||||
Pull requests submitted through GitHub will be ignored.
|
||||
|
||||
Bugs should be filed on Launchpad, not GitHub:
|
||||
|
||||
https://bugs.launchpad.net/broadview-ui
|
4
HACKING.rst
Normal file
4
HACKING.rst
Normal file
@ -0,0 +1,4 @@
|
||||
broadview-ui Style Commandments
|
||||
===============================================
|
||||
|
||||
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
|
176
LICENSE
Normal file
176
LICENSE
Normal file
@ -0,0 +1,176 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
6
MANIFEST.in
Normal file
6
MANIFEST.in
Normal file
@ -0,0 +1,6 @@
|
||||
include AUTHORS
|
||||
include ChangeLog
|
||||
exclude .gitignore
|
||||
exclude .gitreview
|
||||
|
||||
global-exclude *.pyc
|
106
README.md
Normal file
106
README.md
Normal file
@ -0,0 +1,106 @@
|
||||
Overview
|
||||
========
|
||||
|
||||
broadview-ui is a horizon dashboard for configuring BroadView agents.
|
||||
|
||||
broadview-ui currently supports BroadView BST. Support for other BroadView
|
||||
components may be added as functionality is added to broadview-lib
|
||||
(https://github.com/openstack/broadview-lib) and to broadview-collector
|
||||
(https://github.com/openstack/broadview-collector).
|
||||
|
||||
Devstack
|
||||
========
|
||||
|
||||
Devstack support for installing broadview-ui will be provided by the
|
||||
broadview-collector project, and is forthcoming. Devstack is the
|
||||
supported way in which this project is installed.
|
||||
|
||||
Until devstack support is added, follow the instructions outlined below.
|
||||
|
||||
Installation Prerequisites
|
||||
==========================
|
||||
|
||||
If you are installing broadview-collector
|
||||
-----------------------------------------
|
||||
|
||||
Instructions for installing broadview-collector via devstack can be found
|
||||
in the readme file located at
|
||||
https://github.com/openstack/broadview-collector/devstack/README.txt
|
||||
|
||||
Then follow the steps in Installation, below.
|
||||
|
||||
If you are not installing broadview-collector
|
||||
---------------------------------------------
|
||||
|
||||
broadview-ui itself does not have a dependency on broadview-collector,
|
||||
but it does have a dependency on a component that is itself a dependency
|
||||
of broadview-collector: broadview-lib. So you will need to install
|
||||
broadview-lib. To do so:
|
||||
|
||||
* git clone https://github.com/openstack/broadview-lib.git
|
||||
* cd broadview-lib
|
||||
* sudo python setup.py install
|
||||
|
||||
Further details are available in the README.md file at
|
||||
https://github.com/openstack/broadview-lib/README.md
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
After you have broadview-lib installed (either via broadview-collector or
|
||||
directly installing broadview-lib), follow these steps:
|
||||
|
||||
* git clone https://github.com/openstack/broadview-ui.git
|
||||
* cp _50_broadview.py /opt/stack/horizon/openstack_dashboard/enabled/
|
||||
* cp -r broadview /opt/stack/horizon/openstack_dashboard/panels
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Broadview-ui depends on a configuration file that supplies a list of
|
||||
BroadView-enabled switches in your cluster. This configuration file is
|
||||
located /etc, and is called broadviewswitches.conf.
|
||||
|
||||
An example /etc/broadviewswitches.conf is located in the broadview/config
|
||||
directory of this repository.
|
||||
|
||||
The config file must contain a [topology] section, and the [topology]
|
||||
section must contain a setting named "bst_switches".
|
||||
|
||||
The bst_switches setting is a list of dictionaries, each which contain the
|
||||
following key-value pairs:
|
||||
|
||||
* ip: the IPV4 address of the BroadView agent
|
||||
* port: the port upon which the agent is listening
|
||||
* description: a short text description of the switch
|
||||
|
||||
Known Issues
|
||||
============
|
||||
|
||||
* The layout of the panels needs some UI improvement
|
||||
* There is no way to view the current settings of thresholds in the
|
||||
thresholds panel UI. For this, you can use broadview-lib's bv-bstctl
|
||||
get-thresholds command from the commandline.
|
||||
* Loading the thresholds panel is slow, particularly if multiple switches
|
||||
are configured. This is due to a design choice in the underlying protocol
|
||||
to the switch to obtain range values for things like ports, service pools,
|
||||
and so on. We hope to address this in a future release.
|
||||
* The BST clear stats and clear threshold commands are not supported.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
(C) Copyright Broadcom Corporation 2016
|
||||
|
||||
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.
|
||||
|
9
_50_broadview.py
Normal file
9
_50_broadview.py
Normal file
@ -0,0 +1,9 @@
|
||||
DASHBOARD = 'broadview'
|
||||
|
||||
# If set to True, this dashboard will not be added to the settings.
|
||||
DISABLED = False
|
||||
|
||||
# A list of applications to be added to INSTALLED_APPS.
|
||||
ADD_INSTALLED_APPS = [
|
||||
'openstack_dashboard.dashboards.broadview',
|
||||
]
|
1
broadview/.gitignore
vendored
Normal file
1
broadview/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.tox
|
0
broadview/__init__.py
Normal file
0
broadview/__init__.py
Normal file
37
broadview/common.py
Normal file
37
broadview/common.py
Normal file
@ -0,0 +1,37 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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.
|
||||
|
||||
def getHostPort(val):
|
||||
try:
|
||||
val = val.split(":")
|
||||
host = val[0]
|
||||
port = val[1]
|
||||
except:
|
||||
host = None
|
||||
port = None
|
||||
return host, port
|
||||
|
||||
def hyphen2underscore(data):
|
||||
# django templates don't like field names with '-' (so it appears), so
|
||||
# replace them with '_' characters
|
||||
|
||||
ret = []
|
||||
for x in data:
|
||||
y = {}
|
||||
for key, val in x.iteritems():
|
||||
key = key.replace("-", '_')
|
||||
y[key] = val
|
||||
ret.append(y)
|
||||
return ret
|
||||
|
3
broadview/config/broadviewswitches.conf
Normal file
3
broadview/config/broadviewswitches.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[topology]
|
||||
bst_switches = [ { "ip": "10.14.244.128", "port": "8080", "description": "Switch 1"}]
|
||||
|
30
broadview/dashboard.py
Normal file
30
broadview/dashboard.py
Normal file
@ -0,0 +1,30 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
|
||||
class BroadViewBSTGroup(horizon.PanelGroup):
|
||||
slug = "broadviewbstgroup"
|
||||
name = _("BroadView BST")
|
||||
panels = ('featurepanel','thresholdspanel','trackingpanel')
|
||||
|
||||
class BroadViewBST(horizon.Dashboard):
|
||||
name = _("BroadView")
|
||||
slug = "broadview"
|
||||
panels = (BroadViewBSTGroup,)
|
||||
default_panel = 'featurepanel'
|
||||
|
||||
horizon.register(BroadViewBST)
|
0
broadview/featurepanel/__init__.py
Normal file
0
broadview/featurepanel/__init__.py
Normal file
159
broadview/featurepanel/forms.py
Normal file
159
broadview/featurepanel/forms.py
Normal file
@ -0,0 +1,159 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.utils.text import normalize_newlines
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.shortcuts import redirect
|
||||
from horizon import forms
|
||||
from openstack_dashboard.dashboards.broadview import switches
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
def updateBSTSwitchFeature(data):
|
||||
|
||||
args = ["bv-bstctl.py", "cfg-feature"]
|
||||
if "stat_in_percentage" in data and data["stat_in_percentage" ] == "yes":
|
||||
args.append("stat_in_percentage")
|
||||
if "send_snapshot_on_trigger" in data and data["send_snapshot_on_trigger"] == "yes":
|
||||
args.append("send_snapshot_on_trigger")
|
||||
if "enable" in data and data["enable"] == "yes":
|
||||
args.append("enable")
|
||||
if "stat_units_in_cells" in data and data["stat_units_in_cells"] == "yes":
|
||||
args.append("stat_units_in_cells")
|
||||
if "async_full_reports" in data and data["async_full_reports"] == "yes":
|
||||
args.append("async_full_reports")
|
||||
if "send_async_reports" in data and data["send_async_reports"] == "yes":
|
||||
args.append("send_async_reports")
|
||||
|
||||
if "trigger_rate_limit" in data and len(data["trigger_rate_limit"]):
|
||||
args.append("trigger_rate_limit:{}".format(data["trigger_rate_limit"]))
|
||||
if "trigger_rate_limit_interval" in data and len(data["trigger_rate_limit_interval"]):
|
||||
args.append("trigger_rate_limit_interval:{}".format(data["trigger_rate_limit_interval"]))
|
||||
if "collection_interval" in data and len(data["collection_interval"]):
|
||||
args.append("collection_interval:{}".format(data["collection_interval"]))
|
||||
switch = data["switch"].split(" ")[0].split(":")
|
||||
args.append("host:{}".format(switch[0]))
|
||||
args.append("port:{}".format(switch[1]))
|
||||
args.append("timeout:30")
|
||||
|
||||
try:
|
||||
output = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
|
||||
output = json.loads(output)
|
||||
except:
|
||||
LOG.info("updateBSTSwitchFeature: unable to execute bv-bstctl {}".format(sys.exc_info()[0]))
|
||||
|
||||
|
||||
class BSTFeatureForm(forms.SelfHandlingForm):
|
||||
yes_no_choices = [('yes', _('Yes')),
|
||||
('no', _('No'))]
|
||||
|
||||
switch_choices = switches.getBSTSwitchChoices()
|
||||
|
||||
switch = forms.ChoiceField(
|
||||
label=_('Select a switch to configure'),
|
||||
choices=switch_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'style': "width:250px",
|
||||
'class': 'switchable',
|
||||
'data-slug': 'switch'}),
|
||||
required=True)
|
||||
|
||||
enable = forms.ChoiceField(
|
||||
label=_('Enable BST Feature'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'enable'}),
|
||||
required=True)
|
||||
|
||||
send_async_reports = forms.ChoiceField(
|
||||
label=_('Send Async Reports'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'send_async_reports'}),
|
||||
required=True)
|
||||
|
||||
stat_in_percentage = forms.ChoiceField(
|
||||
label=_('Report Percentages'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'stat_in_percentage'}),
|
||||
required=True)
|
||||
|
||||
stat_units_in_cells = forms.ChoiceField(
|
||||
label=_('Report as cells'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'stat_units_in_cells'}),
|
||||
required=True)
|
||||
|
||||
send_snapshot_on_trigger = forms.ChoiceField(
|
||||
label=_('Send Snapshot on Trigger'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'send_snapshot_on_trigger'}),
|
||||
required=True)
|
||||
|
||||
async_full_reports = forms.ChoiceField(
|
||||
label=_('Async Full Reports'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'async_full_reports'}),
|
||||
required=True)
|
||||
|
||||
collection_interval = forms.CharField(
|
||||
label=_('Collection Interval'),
|
||||
widget=forms.widgets.TextInput(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'scriptsource',
|
||||
'data-scriptsource-raw': _('Script Data')}),
|
||||
required=False)
|
||||
|
||||
trigger_rate_limit = forms.CharField(
|
||||
label=_('Trigger Rate Limit'),
|
||||
widget=forms.widgets.TextInput(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'scriptsource',
|
||||
'data-scriptsource-raw': _('Script Data')}),
|
||||
required=False)
|
||||
|
||||
trigger_rate_limit_interval = forms.CharField(
|
||||
label=_('Trigger Rate Limit Interval'),
|
||||
widget=forms.widgets.TextInput(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'scriptsource',
|
||||
'data-scriptsource-raw': _('Script Data')}),
|
||||
required=False)
|
||||
|
||||
class Meta(object):
|
||||
name = _('BST Edit Feature')
|
||||
|
||||
def clean(self):
|
||||
cleaned = super(BSTFeatureForm, self).clean()
|
||||
|
||||
return cleaned
|
||||
|
||||
def handle(self, request, data):
|
||||
updateBSTSwitchFeature(data)
|
||||
return redirect(request.build_absolute_uri())
|
25
broadview/featurepanel/panel.py
Normal file
25
broadview/featurepanel/panel.py
Normal file
@ -0,0 +1,25 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
from openstack_dashboard.dashboards.broadview import dashboard
|
||||
|
||||
class Featurepanel(horizon.Panel):
|
||||
name = _("Feature")
|
||||
slug = "featurepanel"
|
||||
|
||||
|
||||
dashboard.BroadViewBST.register(Featurepanel)
|
3
broadview/featurepanel/templates/featurepanel/_form.html
Normal file
3
broadview/featurepanel/templates/featurepanel/_form.html
Normal file
@ -0,0 +1,3 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
51
broadview/featurepanel/templates/featurepanel/form.html
Normal file
51
broadview/featurepanel/templates/featurepanel/form.html
Normal file
@ -0,0 +1,51 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'broadview/featurepanel/_form.html' %}
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
$("#None").removeClass("static_page")
|
||||
$("div").removeClass("col-sm-6")
|
||||
});
|
||||
$( "#id_switch" ).change(function() {
|
||||
var sw = $( "#id_switch" ).val();
|
||||
x = sw.split(" ")
|
||||
addr = x[0].split(":")
|
||||
host = addr[0]
|
||||
port = addr[1]
|
||||
{% for x in bst_switches %}
|
||||
if ("{{x.host}}" == host && "{{x.port}}" == port) {
|
||||
{% if x.bst_enable != None %}
|
||||
$("#id_enable").val(({{x.bst_enable}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.send_async_reports != None %}
|
||||
$("#id_send_async_reports").val(({{x.send_async_reports}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.stat_in_percentage != None %}
|
||||
$("#id_stat_in_percentage").val(({{x.stat_in_percentage}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.stat_units_in_cells != None %}
|
||||
$("#id_stat_units_in_cells").val(({{x.stat_units_in_cells}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.snapshot_on_trigger != None %}
|
||||
$("#id_snapshot_on_trigger").val(({{x.snapshot_on_trigger}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.async_full_reports != None %}
|
||||
$("#id_async_full_reports").val(({{x.async_full_reports}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.collection_interval != None %}
|
||||
$("#id_collection_interval").val("{{x.collection_interval}}")
|
||||
{% endif %}
|
||||
{% if x.trigger_rate_limit != None %}
|
||||
$("#id_trigger_rate_limit").val("{{x.trigger_rate_limit}}")
|
||||
{% endif %}
|
||||
{% if x.trigger_rate_limit_interval != None %}
|
||||
$("#id_trigger_rate_limit_interval").val("{{x.trigger_rate_limit_interval}}")
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
21
broadview/featurepanel/tests.py
Normal file
21
broadview/featurepanel/tests.py
Normal file
@ -0,0 +1,21 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 horizon.test import helpers as test
|
||||
|
||||
|
||||
class FeaturepanelTests(test.TestCase):
|
||||
# Unit tests for featurepanel.
|
||||
def test_me(self):
|
||||
self.assertTrue(1 + 1 == 2)
|
22
broadview/featurepanel/urls.py
Normal file
22
broadview/featurepanel/urls.py
Normal file
@ -0,0 +1,22 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.conf.urls import url
|
||||
|
||||
from openstack_dashboard.dashboards.broadview.featurepanel import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.FeatureUpdateView.as_view(), name='index'),
|
||||
url(r'^(?P<host_port>[^/]+)/?$', views.FeatureUpdateView.as_view(), name='update'),
|
||||
]
|
161
broadview/featurepanel/views.py
Normal file
161
broadview/featurepanel/views.py
Normal file
@ -0,0 +1,161 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import views
|
||||
|
||||
from openstack_dashboard.dashboards.broadview.featurepanel import forms as bst_forms
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
|
||||
from openstack_dashboard.dashboards.broadview import switches
|
||||
from openstack_dashboard.dashboards.broadview import common
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
def getBSTSwitchFeatures(host, port):
|
||||
ret = []
|
||||
first = None
|
||||
x = switches.getBSTSwitches()
|
||||
for y in x:
|
||||
try:
|
||||
output = subprocess.Popen(\
|
||||
["bv-bstctl.py", "get-feature", "timeout:30", "host:{}".format(y["ip"]), \
|
||||
"port:{}".format(y["port"])], \
|
||||
stdout=subprocess.PIPE).communicate()[0]
|
||||
output = json.loads(output)
|
||||
output["host"] = y["ip"]
|
||||
output["port"] = y["port"]
|
||||
if output:
|
||||
if host == y["ip"] and port == y["port"]:
|
||||
first = output
|
||||
else:
|
||||
ret.append(output)
|
||||
except:
|
||||
LOG.info("getBSTSwitchFeatures: unable to execute bv-bstctl {}".format(sys.exc_info()[0]))
|
||||
|
||||
# if we found a switch matching the specified host, port, put it at the
|
||||
# head of the list
|
||||
|
||||
if first:
|
||||
ret.insert(0, first)
|
||||
return ret
|
||||
|
||||
class FeatureUpdateView(forms.ModalFormView):
|
||||
|
||||
form_class = bst_forms.BSTFeatureForm
|
||||
form_id = "edit_feature"
|
||||
page_title = _("Configure BST Feature")
|
||||
submit_url = reverse_lazy('horizon:broadview:featurepanel:index')
|
||||
cancel_url = reverse_lazy('horizon:broadview:featurepanel:index')
|
||||
success_url = reverse_lazy('horizon:broadview:featurepanel:update')
|
||||
template_name = 'broadview/featurepanel/form.html'
|
||||
|
||||
def get_initial(self):
|
||||
initial = super(FeatureUpdateView, self).get_initial()
|
||||
host_port = None
|
||||
host = None
|
||||
port = None
|
||||
|
||||
try:
|
||||
host_port = self.kwargs['host_port']
|
||||
except:
|
||||
pass
|
||||
|
||||
if host_port:
|
||||
host, port = common.getHostPort(host_port)
|
||||
self.host_port = host_port
|
||||
|
||||
switch = getBSTSwitchFeatures(host, port)
|
||||
if len(switch):
|
||||
switch = switch[0]
|
||||
try:
|
||||
initial["enable"] = "yes" if switch["bst-enable"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize enable")
|
||||
|
||||
try:
|
||||
initial["send_async_reports"] = "yes" if switch["send-async-reports"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize send_async_reports")
|
||||
|
||||
try:
|
||||
initial["stat_in_percentage"] = "yes" if switch["stat-in-percentage"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize stat_in_percentage")
|
||||
|
||||
try:
|
||||
initial["stat_units_in_cells"] = "yes" if switch["stat-units-in-cells"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize stat_units_in_cells")
|
||||
|
||||
try:
|
||||
initial["send_snapshot_on_trigger"] = "yes" if switch["send-snapshot-on-trigger"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize send_snapshot_on_trigger")
|
||||
|
||||
try:
|
||||
initial["async_full_reports"] = "yes" if switch["async-full-reports"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize async_full_reports")
|
||||
|
||||
try:
|
||||
initial["collection_interval"] = int(switch["collection-interval"])
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize collection_interval")
|
||||
|
||||
try:
|
||||
initial["trigger_rate_limit"] = int(switch["trigger-rate-limit"])
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize trigger_rate_limit")
|
||||
|
||||
try:
|
||||
initial["trigger_rate_limit_interval"] = int(switch["trigger-rate-limit-interval"])
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize trigger_rate_limit_interval")
|
||||
|
||||
return initial
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
host = None
|
||||
port = None
|
||||
host_port = None
|
||||
|
||||
try:
|
||||
host_port = self.kwargs['host_port']
|
||||
except:
|
||||
pass
|
||||
|
||||
if host_port:
|
||||
host, port = common.getHostPort(host_port)
|
||||
|
||||
context = super(FeatureUpdateView, self).get_context_data(**kwargs)
|
||||
features = getBSTSwitchFeatures(host, port)
|
||||
context["bst_switches"] = common.hyphen2underscore(features)
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
if self.host_port:
|
||||
kwargs["host_port"] = self.host_port
|
||||
|
||||
return reverse('horizon:broadview:featurepanel:update', kwargs=kwargs)
|
1
broadview/static/broadview/js/broadview.js
Normal file
1
broadview/static/broadview/js/broadview.js
Normal file
@ -0,0 +1 @@
|
||||
/* Additional JavaScript for broadview. */
|
1
broadview/static/broadview/scss/broadview.scss
Normal file
1
broadview/static/broadview/scss/broadview.scss
Normal file
@ -0,0 +1 @@
|
||||
/* Additional SCSS for {{ dash_name }}. */
|
44
broadview/switches.py
Normal file
44
broadview/switches.py
Normal file
@ -0,0 +1,44 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 broadview_lib.config.broadviewconfig import BroadViewBSTSwitches
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
def getBSTSwitches():
|
||||
ret = []
|
||||
x = BroadViewBSTSwitches()
|
||||
for y in x:
|
||||
if not "ip" in y:
|
||||
LOG.warning('getBSTSwitches: switch {} in /etc/broadviewswitches.conf has no ip'.format(y))
|
||||
continue
|
||||
if not "port" in y:
|
||||
LOG.warning('getBSTSwitches: switch {} in /etc/broadviewswitches.conf has no port'.format(y))
|
||||
continue
|
||||
ret.append(y)
|
||||
return ret
|
||||
|
||||
def getBSTSwitchChoices():
|
||||
ret = []
|
||||
x = getBSTSwitches()
|
||||
if len(x) == 0:
|
||||
LOG.warning('getBSTSwitchChoices: no configured switches in /etc/broadviewswitches.conf')
|
||||
for y in x:
|
||||
if not "description" in y:
|
||||
s = "{}:{}".format(y["ip"], y["port"])
|
||||
else:
|
||||
s = "{}:{} ({})".format(y["ip"], y["port"], y["description"])
|
||||
ret.append((s, s))
|
||||
return ret
|
11
broadview/templates/broadview/base.html
Normal file
11
broadview/templates/broadview/base.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'horizon/common/_sidebar.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include "horizon/_messages.html" %}
|
||||
{% block broadview_main %}{% endblock %}
|
||||
{% endblock %}
|
||||
|
0
broadview/thresholdspanel/__init__.py
Normal file
0
broadview/thresholdspanel/__init__.py
Normal file
336
broadview/thresholdspanel/forms.py
Normal file
336
broadview/thresholdspanel/forms.py
Normal file
@ -0,0 +1,336 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.utils.text import normalize_newlines
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.shortcuts import redirect
|
||||
from horizon import forms
|
||||
from openstack_dashboard.dashboards.broadview import switches
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
def updateBSTSwitchThresholds(data):
|
||||
undef = "<enter threshold>"
|
||||
|
||||
LOG.info("updateBSTSwitchThresholds: enter")
|
||||
args = ["bv-bstctl.py", "cfg-thresholds"]
|
||||
|
||||
if data["include_ingress_port_service_pool_um_share_threshold"] != undef:
|
||||
args.append("ingress-port-service-pool:{}:{}:{}".format(\
|
||||
data["include_ingress_port_service_pool_port"], \
|
||||
data["include_ingress_port_service_pool_service_pool"], \
|
||||
data["include_ingress_port_service_pool_um_share_threshold"]))
|
||||
|
||||
if data["include_egress_cpu_queue_cpu_threshold"] != undef:
|
||||
args.append("egress-cpu-queue:{}:{}".format(\
|
||||
data["include_egress_cpu_queue_cpu_queue"], \
|
||||
data["include_egress_cpu_queue_cpu_threshold"]))
|
||||
|
||||
if data["include_device_threshold"] != undef:
|
||||
args.append("device:{}".format(data["include_device_threshold"]))
|
||||
|
||||
if data["include_egress_port_service_pool_mc_share_threshold"] != undef and\
|
||||
data["include_egress_port_service_pool_uc_share_threshold"] != undef and\
|
||||
data["include_egress_port_service_pool_um_share_threshold"] != undef and\
|
||||
data["include_egress_port_service_pool_mc_share_queue_entries_threshold"] != undef:
|
||||
args.append("egress-port-service-pool:{}:{}:{}:{}:{}:{}".format(\
|
||||
data["include_egress_port_service_pool_port"], \
|
||||
data["include_egress_port_service_pool_service_pool"], \
|
||||
data["include_egress_port_service_pool_uc_share_threshold"], \
|
||||
data["include_egress_port_service_pool_um_share_threshold"], \
|
||||
data["include_egress_port_service_pool_mc_share_threshold"], \
|
||||
data["include_egress_port_service_pool_mc_share_queue_entries_threshold"]))
|
||||
|
||||
if data["include_ingress_service_pool_um_share_threshold"] != undef:
|
||||
args.append("ingress-service-pool:{}:{}".format(\
|
||||
data["include_ingress_service_pool_service_pool"], \
|
||||
data["include_ingress_service_pool_um_share_threshold"]))
|
||||
|
||||
if data["include_egress_uc_queue_uc_threshold"] != undef:
|
||||
args.append("egress-uc-queue:{}:{}".format(\
|
||||
data["include_egress_uc_queue_uc_queue"], \
|
||||
data["include_egress_uc_queue_uc_threshold"]))
|
||||
|
||||
if data["include_egress_service_pool_mc_share_threshold"] != undef and \
|
||||
data["include_egress_service_pool_um_share_threshold"] != undef and \
|
||||
data["include_egress_service_pool_mc_share_queue_entries_threshold"] != undef:
|
||||
args.append("egress-service-pool:{}:{}:{}:{}".format(\
|
||||
data["include_egress_service_pool_service_pool"], \
|
||||
data["include_egress_service_pool_um_share_threshold"], \
|
||||
data["include_egress_service_pool_mc_share_threshold"], \
|
||||
data["include_egress_service_pool_mc_share_queue_entries_threshold"]))
|
||||
|
||||
if data["include_egress_rqe_queue_rqe_threshold"] != undef:
|
||||
args.append("egress-rqe-queue:{}:{}".format(\
|
||||
data["include_egress_rqe_queue_rqe_queue"], \
|
||||
data["include_egress_rqe_queue_rqe_threshold"]))
|
||||
|
||||
if data["include_egress_uc_queue_group_uc_threshold"] != undef:
|
||||
args.append("egress-uc-queue-group:{}:{}".format(\
|
||||
data["include_egress_uc_queue_group_uc_queue_group"], \
|
||||
data["include_egress_uc_queue_group_uc_threshold"]))
|
||||
|
||||
if data["include_egress_mc_queue_mc_queue_entries_threshold"] != undef:
|
||||
args.append("egress-mc-queue:{}:{}".format(\
|
||||
data["include_egress_mc_queue_mc_queue"], \
|
||||
data["include_egress_mc_queue_mc_queue_entries_threshold"]))
|
||||
|
||||
if data["include_ingress_port_priority_group_um_headroom_threshold"] != undef and\
|
||||
data["include_ingress_port_priority_group_um_share_threshold"] != undef:
|
||||
args.append("ingress-port-priority-group:{}:{}:{}:{}".format(\
|
||||
data["include_ingress_port_priority_group_port"], \
|
||||
data["include_ingress_port_priority_group_priority_group"], \
|
||||
data["include_ingress_port_priority_group_um_share_threshold"], \
|
||||
data["include_ingress_port_priority_group_um_headroom_threshold"]))
|
||||
|
||||
switch = data["switch"].split(" ")[0].split(":")
|
||||
args.append("host:{}".format(switch[0]))
|
||||
args.append("port:{}".format(switch[1]))
|
||||
args.append("timeout:30")
|
||||
|
||||
try:
|
||||
output = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
|
||||
output = json.loads(output)
|
||||
except:
|
||||
LOG.info("updateBSTSwitchThresholds: unable to execute bv-bstctl {}".format(sys.exc_info()[0]))
|
||||
|
||||
class BSTThresholdsForm(forms.SelfHandlingForm):
|
||||
yes_no_choices = [('yes', _('Yes')),
|
||||
('no', _('No'))]
|
||||
|
||||
switch_choices = switches.getBSTSwitchChoices()
|
||||
|
||||
# the actual ranges are passed to the template as context
|
||||
# data. Here, we set the choices to min max so that the
|
||||
# middleware will validate (and pass along to handlers).
|
||||
|
||||
nochoices = [(x, x) for x in range(0, 4098)]
|
||||
|
||||
switch = forms.ChoiceField(
|
||||
label=_('Select a switch'),
|
||||
choices=switch_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'style': "width:250px",
|
||||
'class': 'switchable',
|
||||
'data-slug': 'switch'}),
|
||||
required=False)
|
||||
|
||||
include_ingress_port_priority_group_port = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_ingress_port_priority_group_port'}),
|
||||
required=False)
|
||||
|
||||
include_ingress_port_priority_group_priority_group = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_ingress_port_priority_group_priority_group'}),
|
||||
required=False)
|
||||
|
||||
include_ingress_port_priority_group_um_share_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_ingress_port_priority_group_um_headroom_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_ingress_port_service_pool_port = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_ingress_port_service_pool_port'}),
|
||||
required=False)
|
||||
|
||||
include_ingress_port_service_pool_service_pool = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_ingress_port_service_pool_service_pool'}),
|
||||
required=False)
|
||||
|
||||
include_ingress_port_service_pool_um_share_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_port_service_pool_port = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_egress_port_service_pool_port'}),
|
||||
required=False)
|
||||
|
||||
include_egress_port_service_pool_service_pool = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_egress_port_service_pool_service_pool'}),
|
||||
required=False)
|
||||
|
||||
include_egress_port_service_pool_uc_share_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_port_service_pool_um_share_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_port_service_pool_mc_share_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_port_service_pool_mc_share_queue_entries_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_uc_queue_group_uc_queue_group = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_egress_uc_queue_group_uc_queue_group'}),
|
||||
required=False)
|
||||
|
||||
include_egress_uc_queue_group_uc_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_uc_queue_uc_queue = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_egress_uc_queue_uc_queue'}),
|
||||
required=False)
|
||||
|
||||
include_egress_uc_queue_uc_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_mc_queue_mc_queue = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_egress_mc_queue_mc_queue'}),
|
||||
required=False)
|
||||
|
||||
include_egress_mc_queue_mc_queue_entries_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_ingress_service_pool_service_pool = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_ingress_service_pool_service_pool'}),
|
||||
required=False)
|
||||
|
||||
include_ingress_service_pool_um_share_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_service_pool_service_pool = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_egress_service_pool_service_pool'}),
|
||||
required=False)
|
||||
|
||||
include_egress_service_pool_um_share_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_service_pool_mc_share_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_service_pool_mc_share_queue_entries_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_rqe_queue_rqe_queue = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_egress_rqe_queue_rqe_queue'}),
|
||||
required=False)
|
||||
|
||||
include_egress_rqe_queue_rqe_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_egress_cpu_queue_cpu_queue = forms.ChoiceField(
|
||||
label=_(''),
|
||||
choices=nochoices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'include_egress_cpu_queue_cpu_queue'}),
|
||||
required=False)
|
||||
|
||||
include_egress_cpu_queue_cpu_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
include_device_threshold = forms.CharField(
|
||||
label=_(''),
|
||||
widget=forms.widgets.TextInput(),
|
||||
required=False)
|
||||
|
||||
class Meta(object):
|
||||
name = _('BST Edit Feature')
|
||||
|
||||
def clean(self):
|
||||
cleaned = super(BSTThresholdsForm, self).clean()
|
||||
LOG.info('leave clean {}'.format(cleaned))
|
||||
|
||||
return cleaned
|
||||
|
||||
def handle(self, request, data):
|
||||
LOG.info('enter handle {}'.format(data))
|
||||
updateBSTSwitchThresholds(data)
|
||||
LOG.info('leave handle')
|
||||
return redirect(request.build_absolute_uri())
|
24
broadview/thresholdspanel/panel.py
Normal file
24
broadview/thresholdspanel/panel.py
Normal file
@ -0,0 +1,24 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
from openstack_dashboard.dashboards.broadview import dashboard
|
||||
|
||||
class Thresholdspanel(horizon.Panel):
|
||||
name = _("Thresholds")
|
||||
slug = "thresholdspanel"
|
||||
|
||||
dashboard.BroadViewBST.register(Thresholdspanel)
|
@ -0,0 +1,3 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
243
broadview/thresholdspanel/templates/thresholdspanel/form.html
Normal file
243
broadview/thresholdspanel/templates/thresholdspanel/form.html
Normal file
@ -0,0 +1,243 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div id="None"
|
||||
data-backdrop="static"
|
||||
class="static_page">
|
||||
|
||||
<div class="">
|
||||
<div class="">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title"></h3>
|
||||
</div>
|
||||
|
||||
<form id="edit_thresholds"
|
||||
ng-controller="DummyController"
|
||||
name=""
|
||||
autocomplete=""
|
||||
class=""
|
||||
action="/dashboard/broadview/thresholdspanel/"
|
||||
method="POST"
|
||||
enctype="multipart/form-data">
|
||||
|
||||
{% csrf_token %}
|
||||
<div class="modal-body clearfix">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<fieldset>
|
||||
<div class="form-group required">
|
||||
<label class="control-label required" for="id_switch">Select a switch to configure</label>
|
||||
<span class="hz-icon-required fa fa-asterisk"></span>
|
||||
<div class=" ">
|
||||
{{ form.switch }}
|
||||
</div>
|
||||
</div>
|
||||
<input type="submit" value="Submit" />
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
// TODO - respond to these clicks by updating value text
|
||||
|
||||
$( "#ingress_port_priority_group_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#ingress_port_service_pool_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#egress_port_service_pool_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#egress_uc_queue_group_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#egress_uc_queue_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#egress_mc_queue_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#egress_service_pool_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#ingress_service_pool_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#egress_cpu_queue_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#egress_rqe_queue_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( "#device_get" ).click(function() {
|
||||
});
|
||||
|
||||
$( document ).ready(function() {
|
||||
$("#None").removeClass("static_page")
|
||||
$("div").removeClass("col-sm-6")
|
||||
$("#realmtab").insertAfter("#id_switch")
|
||||
});
|
||||
$( "#id_switch" ).change(function() {
|
||||
$("#realmtab").remove()
|
||||
$('<p></p><p></p><p></p><table id="realmtab" style="width: 100%"> <tr id="realmheader"> <th></th><th></th><th></th><th></th><th></th><th></th><th></th> </tr> </table>').insertAfter("#id_switch")
|
||||
var sw = $( "#id_switch" ).val();
|
||||
x = sw.split(" ")
|
||||
addr = x[0].split(":")
|
||||
host = addr[0]
|
||||
port = addr[1]
|
||||
{% for x in bst_switches %}
|
||||
if ("{{x.host}}" == host && "{{x.port}}" == port) {
|
||||
if ("{{x.realm}}".indexOf("ingress_port_priority_group") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>ingress</th><th>port</th><th>priority-group</th><th>um-share-threshold</th><th>um-headroom-threshold</th><th></th><th></th><th></th><th></th></tr> <tr> <td></td> <td> <select name="include_ingress_port_priority_group_port" id="id_include_ingress_port_priority_group_port"</select> </td><td> <select name="include_ingress_port_priority_group_priority_group" id="id_include_ingress_port_priority_group_priority_group" </select></td><td><input name="include_ingress_port_priority_group_um_share_threshold" type="text" id="id_include_ingress_port_priority_group_um_share_threshold" value="<enter threshold>"></td><td><input name="include_ingress_port_priority_group_um_headroom_threshold" type="text" id="id_include_ingress_port_priority_group_um_headroom_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td><button type="button" style="display: none;" id="ingress_port_priority_group_get">Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.ports %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_ingress_port_priority_group_port");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
items = new Array()
|
||||
{% for y in x.ranges.priority_groups %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
list = $("#id_include_ingress_port_priority_group_priority_group");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
} else if ("{{x.realm}}".indexOf("ingress_port_service_pool") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>ingress</th><th>port</th><th>service-pool</th><th>um_share_threshold</th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_ingress_port_service_pool_port" id="id_include_ingress_port_service_pool_port"</select></td><td><select name="include_ingress_port_service_pool_service_pool" id="id_include_ingress_port_service_pool_service_pool"</select></td><td><input type="text" id="id_include_ingress_port_service_pool_um_share_threshold" name="include_ingress_port_service_pool_um_share_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td><button id="ingress_port_service_pool_get" type="button" style="display: none;">Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.ports %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_ingress_port_service_pool_port");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
items = new Array()
|
||||
{% for y in x.ranges.service_pools %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
list = $("#id_include_ingress_port_service_pool_service_pool");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
} else if ("{{x.realm}}".indexOf("egress_port_service_pool") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>egress</th><th>port</th><th>service-pool</th><th>uc-share-threshold</th><th>um-share-threshold</th><th>mc-share-threshold</th><th>mc-share-queue-entries-threshold</th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_egress_port_service_pool_port" id="id_include_egress_port_service_pool_port"</select></td><td><select name="include_egress_port_service_pool_service_pool" id="id_include_egress_port_service_pool_service_pool"</select></td><td><input type="text" name="include_egress_port_service_pool_uc_share_threshold" id="id_include_egress_port_service_pool_uc_share_threshold" value="<enter threshold>"></td><td><input type="text" name="include_egress_port_service_pool_um_share_threshold" id="id_include_egress_port_service_pool_um_share_threshold" value="<enter threshold>"><td><input type="text" name="include_egress_port_service_pool_mc_share_threshold" id="id_include_egress_port_service_pool_mc_share_threshold" value="<enter threshold>"><td><input type="text" name="include_egress_port_service_pool_mc_share_queue_entries_threshold" id="id_include_egress_port_service_pool_mc_share_queue_entries_threshold" value="<enter threshold>"><td></td><td></td><td></td><td><button id="egress_port_service_pool_get" type="button" style="display: none;">Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.ports %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_egress_port_service_pool_port");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
items = new Array()
|
||||
{% for y in x.ranges.service_pools %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
list = $("#id_include_egress_port_service_pool_service_pool");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
} else if ("{{x.realm}}".indexOf("egress_uc_queue_group") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>egress</th><th>uc-queue-group</th><th>uc-threshold</th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_egress_uc_queue_group_uc_queue_group" id="id_include_egress_uc_queue_group_uc_queue_group"</select></td><td><input type="text" name="include_egress_uc_queue_group_uc_threshold" id="id_include_egress_uc_queue_group_uc_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td></td><td><button id="egress_uc_queue_group_get" type="button" style="display: none;">Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.queue_groups %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_egress_uc_queue_group_uc_queue_group");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
} else if ("{{x.realm}}".indexOf("egress_uc_queue") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>egress</th><th>uc-queue</th><th>uc-threshold</th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_egress_uc_queue_uc_queue" id="id_include_egress_uc_queue_uc_queue"</select></td><td><input type="text" name="include_egress_uc_queue_uc_threshold" id="id_include_egress_uc_queue_uc_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td></td><td><button id="egress_uc_queue_get" type="button" style="display: none;">Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.queues %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_egress_uc_queue_uc_queue");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
} else if ("{{x.realm}}".indexOf("egress_mc_queue") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>egress</th><th>mc-queue</th><th>mc-queue_entries-threshold</th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_egress_mc_queue_mc_queue" id="id_include_egress_mc_queue_mc_queue"</select></td><td><input type="text" name="include_egress_mc_queue_mc_queue_entries_threshold" id="id_include_egress_mc_queue_mc_queue_entries_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td></td><td><button id="egress_mc_queue_get" type="button" style="display: none;">Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.queues %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_egress_mc_queue_mc_queue");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
} else if ("{{x.realm}}".indexOf("ingress_service_pool") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>ingress</th><th>service-pool</th><th>um-share-threshold</th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_ingress_service_pool_service_pool" id="id_include_ingress_service_pool_service_pool"</select></td><td><input type="text" id="id_include_ingress_service_pool_um_share_threshold" name="include_ingress_service_pool_um_share_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td></td><td><button type="button" style="display: none;" id="ingress_service_pool_get" >Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.service_pools %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_ingress_service_pool_service_pool");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
} else if ("{{x.realm}}".indexOf("egress_service_pool") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>egress</th><th>service-pool</th><th>um-share-threshold</th><th>mc-share-threshold</th><th>mc-share-queue-entries-threshold</th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_egress_service_pool_service_pool" id="id_include_egress_service_pool_service_pool"</select></td><td><input type="text" id="id_include_egress_service_pool_um_share_threshold" name="include_egress_service_pool_um_share_threshold" value="<enter threshold>"></td><td><input type="text" id="id_include_egress_service_pool_mc_share_threshold" name="include_egress_service_pool_mc_share_threshold" value="<enter threshold>"></td><td><input type="text" id="id_include_egress_service_pool_mc_share_queue_entries_threshold" name="include_egress_service_pool_mc_share_queue_entries_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td></td><td><button type="button" style="display: none;" id="egress_service_pool_get" >Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.service_pools %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_egress_service_pool_service_pool");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
} else if ("{{x.realm}}".indexOf("egress_cpu_queue") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>egress</th><th>cpu-queue</th><th>cpu-threshold</th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_egress_cpu_queue_cpu_queue" id="id_include_egress_cpu_queue_cpu_queue"</select></td><td><input type="text" name="include_egress_cpu_queue_cpu_threshold" id="id_include_egress_cpu_queue_cpu_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td></td><td><button id="egress_cpu_queue_get" type="button" style="display: none;">Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.queues %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_egress_cpu_queue_cpu_queue");
|
||||
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
} else if ("{{x.realm}}".indexOf("egress_rqe_queue") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>egress</th><th>rqe-queue</th><th>rqe-threshold</th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><select name="include_egress_rqe_queue_rqe_queue" id="id_include_egress_rqe_queue_rqe_queue"</select></td><td><input type="text" name="include_egress_rqe_queue_rqe_threshold" id="id_include_egress_rqe_queue_rqe_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td></td><td><button id="egress_rqe_queue_get" type="button" style="display: none;">Get</button></td></tr>')
|
||||
var items = new Array()
|
||||
{% for y in x.ranges.queues %}
|
||||
items.push({{y}})
|
||||
{% endfor %}
|
||||
|
||||
var list = $("#id_include_egress_rqe_queue_rqe_queue");
|
||||
$.each(items, function(index, item) {
|
||||
list.append(new Option(item, item)); });
|
||||
|
||||
} else if ("{{x.realm}}".indexOf("device") > -1) {
|
||||
$("#realmtab tr:last").after('<tr><th>device</th><th>threshold</th><th></th><th></th><th></th><th></th><th></th><th></th></tr><tr><td></td><td><input type="text" id="id_include_device_threshold" name="include_device_threshold" value="<enter threshold>"></td><td></td><td></td><td></td><td></td><td></td><td><button type="button" style="display: none;" id="device_get" >Get</button></td></tr>')
|
||||
}
|
||||
}
|
||||
{% endfor %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
21
broadview/thresholdspanel/tests.py
Normal file
21
broadview/thresholdspanel/tests.py
Normal file
@ -0,0 +1,21 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 horizon.test import helpers as test
|
||||
|
||||
|
||||
class FeaturepanelTests(test.TestCase):
|
||||
# Unit tests for featurepanel.
|
||||
def test_me(self):
|
||||
self.assertTrue(1 + 1 == 2)
|
22
broadview/thresholdspanel/urls.py
Normal file
22
broadview/thresholdspanel/urls.py
Normal file
@ -0,0 +1,22 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.conf.urls import url
|
||||
|
||||
from openstack_dashboard.dashboards.broadview.thresholdspanel import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.ThresholdsUpdateView.as_view(), name='index'),
|
||||
url(r'^(?P<host_port>[^/]+)/?$', views.ThresholdsUpdateView.as_view(), name='update'),
|
||||
]
|
280
broadview/thresholdspanel/views.py
Normal file
280
broadview/thresholdspanel/views.py
Normal file
@ -0,0 +1,280 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import views
|
||||
|
||||
from broadview_lib.config.bst import GetBSTThresholds
|
||||
|
||||
from openstack_dashboard.dashboards.broadview.thresholdspanel import forms as bst_forms
|
||||
|
||||
import json
|
||||
import sys
|
||||
|
||||
from openstack_dashboard.dashboards.broadview import switches
|
||||
from openstack_dashboard.dashboards.broadview import common
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
def getIngressPortPriorityGroupRange(data):
|
||||
ports = set()
|
||||
priority_groups = set()
|
||||
|
||||
d = data.getIngressPortPriorityGroup()
|
||||
for x in d:
|
||||
for y in x:
|
||||
ports.add(int(y.getPort()))
|
||||
priority_groups.add(int(y.getPriorityGroup()))
|
||||
|
||||
return {"ports": sorted(list(ports)),
|
||||
"priority_groups": sorted(list(priority_groups))}
|
||||
|
||||
def getEgressPortServicePoolRange(data):
|
||||
ports = set()
|
||||
service_pools = set()
|
||||
|
||||
d = data.getEgressPortServicePool()
|
||||
for x in d:
|
||||
for y in x:
|
||||
ports.add(int(y.getPort()))
|
||||
service_pools.add(int(y.getServicePool()))
|
||||
|
||||
return {"ports": sorted(list(ports)),
|
||||
"service_pools": sorted(list(service_pools))}
|
||||
|
||||
def getIngressPortServicePoolRange(data):
|
||||
ports = set()
|
||||
service_pools = set()
|
||||
|
||||
d = data.getIngressPortServicePool()
|
||||
for x in d:
|
||||
for y in x:
|
||||
ports.add(int(y.getPort()))
|
||||
service_pools.add(int(y.getServicePool()))
|
||||
|
||||
return {"ports": sorted(list(ports)),
|
||||
"service_pools": sorted(list(service_pools))}
|
||||
|
||||
def getEgressUcQueueRange(data):
|
||||
queues = set()
|
||||
|
||||
d = data.getEgressUcQueue()
|
||||
for x in d:
|
||||
for y in x:
|
||||
queues.add(int(y.getQueue()))
|
||||
|
||||
return {"queues": sorted(list(queues))}
|
||||
|
||||
def getEgressUcQueueGroupRange(data):
|
||||
queue_groups = set()
|
||||
|
||||
d = data.getEgressUcQueueGroup()
|
||||
for x in d:
|
||||
for y in x:
|
||||
queue_groups.add(int(y.getQueueGroup()))
|
||||
|
||||
return {"queue_groups": sorted(list(queue_groups))}
|
||||
|
||||
def getEgressMcQueueRange(data):
|
||||
queues = set()
|
||||
|
||||
d = data.getEgressMcQueue()
|
||||
for x in d:
|
||||
for y in x:
|
||||
queues.add(int(y.getQueue()))
|
||||
|
||||
return {"queues": sorted(list(queues))}
|
||||
|
||||
def getIngressServicePoolRange(data):
|
||||
service_pools = set()
|
||||
|
||||
d = data.getIngressServicePool()
|
||||
for x in d:
|
||||
for y in x:
|
||||
service_pools.add(int(y.getServicePool()))
|
||||
|
||||
return {"service_pools": sorted(list(service_pools))}
|
||||
|
||||
def getEgressServicePoolRange(data):
|
||||
service_pools = set()
|
||||
|
||||
d = data.getEgressServicePool()
|
||||
for x in d:
|
||||
for y in x:
|
||||
service_pools.add(int(y.getServicePool()))
|
||||
|
||||
return {"service_pools": sorted(list(service_pools))}
|
||||
|
||||
def getEgressCPUQueueRange(data):
|
||||
queues = set()
|
||||
|
||||
d = data.getEgressCPUQueue()
|
||||
for x in d:
|
||||
for y in x:
|
||||
queues.add(int(y.getQueue()))
|
||||
|
||||
return {"queues": sorted(list(queues))}
|
||||
|
||||
def getEgressRQEQueueRange(data):
|
||||
queues = set()
|
||||
|
||||
d = data.getEgressRQEQueue()
|
||||
for x in d:
|
||||
for y in x:
|
||||
queues.add(int(y.getQueue()))
|
||||
|
||||
return {"queues": sorted(list(queues))}
|
||||
|
||||
def getDeviceRange(data):
|
||||
return {}
|
||||
|
||||
def getThresholdRanges(realm, data):
|
||||
ret = None
|
||||
|
||||
dispatch = [{"include_ingress_port_priority_group":
|
||||
getIngressPortPriorityGroupRange},
|
||||
{"include_ingress_port_service_pool":
|
||||
getIngressPortServicePoolRange},
|
||||
{"include_egress_port_service_pool":
|
||||
getEgressPortServicePoolRange},
|
||||
{"include_egress_uc_queue":
|
||||
getEgressUcQueueRange},
|
||||
{"include_egress_uc_queue_group":
|
||||
getEgressUcQueueGroupRange},
|
||||
{"include_egress_mc_queue":
|
||||
getEgressMcQueueRange},
|
||||
{"include_ingress_service_pool":
|
||||
getIngressServicePoolRange},
|
||||
{"include_egress_service_pool":
|
||||
getEgressServicePoolRange},
|
||||
{"include_egress_cpu_queue":
|
||||
getEgressCPUQueueRange},
|
||||
{"include_egress_rqe_queue":
|
||||
getEgressRQEQueueRange},
|
||||
{"include_device":
|
||||
getDeviceRange}]
|
||||
|
||||
for x in dispatch:
|
||||
if realm in x:
|
||||
ret = x[realm](data)
|
||||
break
|
||||
return ret
|
||||
|
||||
def getBSTSwitchThresholds(host, port):
|
||||
thresholds = [ "include_ingress_port_priority_group", \
|
||||
"include_ingress_port_service_pool", \
|
||||
"include_egress_port_service_pool", \
|
||||
"include_egress_uc_queue", \
|
||||
"include_egress_uc_queue_group", \
|
||||
"include_egress_mc_queue", \
|
||||
"include_ingress_service_pool", \
|
||||
"include_egress_service_pool", \
|
||||
"include_egress_cpu_queue", \
|
||||
"include_egress_rqe_queue", \
|
||||
"include_device"]
|
||||
ret = []
|
||||
first = None
|
||||
x = switches.getBSTSwitches()
|
||||
for y in x:
|
||||
try:
|
||||
# the agent doesn't seem to be able to pass back large
|
||||
# amounts of data without truncating it, so get the data
|
||||
# in multiple requests. TODO file a bug on this
|
||||
|
||||
for thresh in thresholds:
|
||||
swdata = {}
|
||||
o = GetBSTThresholds(y["ip"], int(y["port"]))
|
||||
|
||||
o.setIncludeIngressPortPriorityGroup("include_ingress_port_priority_group" in thresh)
|
||||
o.setIncludeIngressPortServicePool("include_ingress_port_service_pool" in thresh)
|
||||
o.setIncludeIngressServicePool("include_ingress_service_pool" in thresh)
|
||||
o.setIncludeEgressPortServicePool("include_egress_port_service_pool" in thresh)
|
||||
o.setIncludeEgressServicePool("include_egress_service_pool" in thresh)
|
||||
o.setIncludeEgressUcQueue("include_egress_uc_queue" in thresh)
|
||||
o.setIncludeEgressUcQueueGroup("include_egress_uc_queue_group" in thresh)
|
||||
o.setIncludeEgressMcQueue("include_egress_mc_queue" in thresh)
|
||||
o.setIncludeEgressCPUQueue("include_egress_cpu_queue" in thresh)
|
||||
o.setIncludeEgressRQEQueue("include_egress_rqe_queue" in thresh)
|
||||
o.setIncludeDevice("include_device" in thresh)
|
||||
|
||||
status, rep = o.send(30)
|
||||
|
||||
if status == 200:
|
||||
j = json.dumps(o.getJSON())
|
||||
swdata["realm"] = thresh
|
||||
swdata["data"] = j
|
||||
swdata["host"] = y["ip"]
|
||||
swdata["port"] = y["port"]
|
||||
ranges = getThresholdRanges(thresh, rep)
|
||||
swdata["ranges"] = ranges
|
||||
else:
|
||||
LOG.info("getBSTSwitchThresholds: failure {}".format(status))
|
||||
if len(swdata):
|
||||
ret.append(swdata)
|
||||
|
||||
except:
|
||||
LOG.info("getBSTSwitchThresholds: exception {}".format(sys.exc_info()[0]))
|
||||
return ret
|
||||
|
||||
class ThresholdsUpdateView(forms.ModalFormView):
|
||||
|
||||
form_class = bst_forms.BSTThresholdsForm
|
||||
form_id = "edit_thresholds"
|
||||
page_title = _("Configure BST Thresholds")
|
||||
submit_url = reverse_lazy('horizon:broadview:thresholdspanel:index')
|
||||
cancel_url = reverse_lazy('horizon:broadview:thresholdspanel:index')
|
||||
success_url = reverse_lazy('horizon:broadview:thresholdspanel:update')
|
||||
template_name = 'broadview/thresholdspanel/form.html'
|
||||
|
||||
def __init__(self):
|
||||
super(ThresholdsUpdateView, self).__init__()
|
||||
self._thresholds = None
|
||||
|
||||
def get_initial(self):
|
||||
initial = super(ThresholdsUpdateView, self).get_initial()
|
||||
return initial
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
host = None
|
||||
port = None
|
||||
host_port = None
|
||||
|
||||
try:
|
||||
host_port = self.kwargs['host_port']
|
||||
except:
|
||||
pass
|
||||
|
||||
if host_port:
|
||||
host, port = common.getHostPort(host_port)
|
||||
|
||||
context = super(ThresholdsUpdateView, self).get_context_data(**kwargs)
|
||||
|
||||
if not self._thresholds:
|
||||
self._thresholds = getBSTSwitchThresholds(host, port)
|
||||
|
||||
context["bst_switches"] = self._thresholds
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
if self.host_port:
|
||||
kwargs["host_port"] = self.host_port
|
||||
|
||||
return reverse('horizon:broadview:thresoldspanel:update', kwargs=kwargs)
|
0
broadview/trackingpanel/__init__.py
Normal file
0
broadview/trackingpanel/__init__.py
Normal file
189
broadview/trackingpanel/forms.py
Normal file
189
broadview/trackingpanel/forms.py
Normal file
@ -0,0 +1,189 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.utils.text import normalize_newlines
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.shortcuts import redirect
|
||||
from horizon import forms
|
||||
from openstack_dashboard.dashboards.broadview import switches
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
def updateBSTSwitchTracking(data):
|
||||
|
||||
args = ["bv-bstctl.py", "cfg-tracking"]
|
||||
if "track_peak_stats" in data and data["track_peak_stats" ] == "yes":
|
||||
args.append("track_peak_stats")
|
||||
if "track_ingress_port_priority_group" in data and data["track_ingress_port_priority_group"] == "yes":
|
||||
args.append("track_ingress_port_priority_group")
|
||||
if "track_ingress_port_service_pool" in data and data["track_ingress_port_service_pool"] == "yes":
|
||||
args.append("track_ingress_port_service_pool")
|
||||
if "track_ingress_service_pool" in data and data["track_ingress_service_pool"] == "yes":
|
||||
args.append("track_ingress_service_pool")
|
||||
if "track_egress_port_service_pool" in data and data["track_egress_port_service_pool"] == "yes":
|
||||
args.append("track_egress_port_service_pool")
|
||||
if "track_egress_service_pool" in data and data["track_egress_service_pool"] == "yes":
|
||||
args.append("track_egress_service_pool")
|
||||
if "track_egress_uc_queue" in data and data["track_egress_uc_queue"] == "yes":
|
||||
args.append("track_egress_uc_queue")
|
||||
if "track_egress_uc_queue_group" in data and data["track_egress_uc_queue_group"] == "yes":
|
||||
args.append("track_egress_uc_queue_group")
|
||||
if "track_egress_mc_queue" in data and data["track_egress_mc_queue"] == "yes":
|
||||
args.append("track_egress_mc_queue")
|
||||
if "track_egress_cpu_queue" in data and data["track_egress_cpu_queue"] == "yes":
|
||||
args.append("track_egress_cpu_queue")
|
||||
if "track_egress_rqe_queue" in data and data["track_egress_rqe_queue"] == "yes":
|
||||
args.append("track_egress_rqe_queue")
|
||||
if "track_device" in data and data["track_device"] == "yes":
|
||||
args.append("track_device")
|
||||
|
||||
switch = data["switch"].split(" ")[0].split(":")
|
||||
args.append("host:{}".format(switch[0]))
|
||||
args.append("port:{}".format(switch[1]))
|
||||
args.append("timeout:30")
|
||||
|
||||
try:
|
||||
output = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
|
||||
output = json.loads(output)
|
||||
except:
|
||||
LOG.info("updateBSTSwitchTracking: unable to execute bv-bstctl {}".format(sys.exc_info()[0]))
|
||||
|
||||
|
||||
class BSTTrackingForm(forms.SelfHandlingForm):
|
||||
yes_no_choices = [('yes', _('Yes')),
|
||||
('no', _('No'))]
|
||||
|
||||
switch_choices = switches.getBSTSwitchChoices()
|
||||
|
||||
switch = forms.ChoiceField(
|
||||
label=_('Select a switch to configure'),
|
||||
choices=switch_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'style': "width:250px",
|
||||
'class': 'switchable',
|
||||
'data-slug': 'switch'}),
|
||||
required=True)
|
||||
|
||||
track_peak_stats = forms.ChoiceField(
|
||||
label=_('Peak Stats'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_peak_stats'}),
|
||||
required=True)
|
||||
|
||||
track_ingress_port_priority_group = forms.ChoiceField(
|
||||
label=_('Ingress Port Priority Group'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_ingress_port_priority_group'}),
|
||||
required=True)
|
||||
|
||||
track_ingress_port_service_pool = forms.ChoiceField(
|
||||
label=_('Ingress Port Service Pool'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_ingress_port_service_pool'}),
|
||||
required=True)
|
||||
|
||||
track_ingress_service_pool = forms.ChoiceField(
|
||||
label=_('Ingress Service Pool'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_ingress_service_pool'}),
|
||||
required=True)
|
||||
|
||||
track_egress_port_service_pool = forms.ChoiceField(
|
||||
label=_('Egress Port Service Pool'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_egress_port_service_pool'}),
|
||||
required=True)
|
||||
|
||||
track_egress_service_pool = forms.ChoiceField(
|
||||
label=_('Egress Service Pool'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_egress_service_pool'}),
|
||||
required=True)
|
||||
|
||||
track_egress_uc_queue = forms.ChoiceField(
|
||||
label=_('Egress Uc Queue'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_egress_uc_queue'}),
|
||||
required=True)
|
||||
|
||||
track_egress_uc_queue_group = forms.ChoiceField(
|
||||
label=_('Egress Uc Queue Group'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_egress_uc_queue_group'}),
|
||||
required=True)
|
||||
|
||||
track_egress_mc_queue = forms.ChoiceField(
|
||||
label=_('Egress Mc Queue'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_egress_mc_queue'}),
|
||||
required=True)
|
||||
|
||||
track_egress_cpu_queue = forms.ChoiceField(
|
||||
label=_('Egress CPU Queue'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_egress_cpu_queue'}),
|
||||
required=True)
|
||||
|
||||
track_egress_rqe_queue = forms.ChoiceField(
|
||||
label=_('Egress RQE Queue'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_egress_rqe_queue'}),
|
||||
required=True)
|
||||
|
||||
track_device = forms.ChoiceField(
|
||||
label=_('Device'),
|
||||
choices=yes_no_choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'track_device'}),
|
||||
required=True)
|
||||
|
||||
class Meta(object):
|
||||
name = _('BST Configure Tracking')
|
||||
|
||||
def clean(self):
|
||||
cleaned = super(BSTTrackingForm, self).clean()
|
||||
|
||||
return cleaned
|
||||
|
||||
def handle(self, request, data):
|
||||
updateBSTSwitchTracking(data)
|
||||
return redirect(request.build_absolute_uri())
|
25
broadview/trackingpanel/panel.py
Normal file
25
broadview/trackingpanel/panel.py
Normal file
@ -0,0 +1,25 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
from openstack_dashboard.dashboards.broadview import dashboard
|
||||
|
||||
class Trackingpanel(horizon.Panel):
|
||||
name = _("Tracking")
|
||||
slug = "trackingpanel"
|
||||
|
||||
|
||||
dashboard.BroadViewBST.register(Trackingpanel)
|
@ -0,0 +1,3 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
60
broadview/trackingpanel/templates/trackingpanel/form.html
Normal file
60
broadview/trackingpanel/templates/trackingpanel/form.html
Normal file
@ -0,0 +1,60 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'broadview/featurepanel/_form.html' %}
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
$("#None").removeClass("static_page")
|
||||
$("div").removeClass("col-sm-6")
|
||||
});
|
||||
$( "#id_switch" ).change(function() {
|
||||
var sw = $( "#id_switch" ).val();
|
||||
x = sw.split(" ")
|
||||
addr = x[0].split(":")
|
||||
host = addr[0]
|
||||
port = addr[1]
|
||||
{% for x in bst_switches %}
|
||||
if ("{{x.host}}" == host && "{{x.port}}" == port) {
|
||||
{% if x.track_peak_stats != None %}
|
||||
$("#id_track_peak_stats").val(({{x.track_peak_stats}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_ingress_port_priority_group != None %}
|
||||
$("#id_track_ingress_port_priority_group").val(({{x.track_ingress_port_priority_group}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_ingress_port_service_pool != None %}
|
||||
$("#id_track_ingress_port_service_pool").val(({{x.track_ingress_port_service_pool}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_ingress_service_pool != None %}
|
||||
$("#id_track_ingress_service_pool").val(({{x.track_ingress_service_pool}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_egress_port_service_pool != None %}
|
||||
$("#id_track_egress_port_service_pool").val(({{x.track_egress_port_service_pool}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_egress_service_pool != None %}
|
||||
$("#id_track_egress_service_pool").val(({{x.track_egress_service_pool}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_egress_uc_queue != None %}
|
||||
$("#id_track_egress_uc_queue").val(({{x.track_egress_uc_queue}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_egress_uc_queue_group != None %}
|
||||
$("#id_track_egress_uc_queue_group").val(({{x.track_egress_uc_queue_group}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_egress_mc_queue != None %}
|
||||
$("#id_track_egress_mc_queue").val(({{x.track_egress_mc_queue}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_egress_cpu_queue != None %}
|
||||
$("#id_track_egress_cpu_queue").val(({{x.track_egress_cpu_queue}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_egress_rqe_queue != None %}
|
||||
$("#id_track_egress_rqe_queue").val(({{x.track_egress_rqe_queue}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
{% if x.track_device != None %}
|
||||
$("#id_track_device").val(({{x.track_device}} == 1 ? "yes" : "no")).change()
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
21
broadview/trackingpanel/tests.py
Normal file
21
broadview/trackingpanel/tests.py
Normal file
@ -0,0 +1,21 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 horizon.test import helpers as test
|
||||
|
||||
|
||||
class FeaturepanelTests(test.TestCase):
|
||||
# Unit tests for featurepanel.
|
||||
def test_me(self):
|
||||
self.assertTrue(1 + 1 == 2)
|
22
broadview/trackingpanel/urls.py
Normal file
22
broadview/trackingpanel/urls.py
Normal file
@ -0,0 +1,22 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.conf.urls import url
|
||||
|
||||
from openstack_dashboard.dashboards.broadview.trackingpanel import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.TrackingUpdateView.as_view(), name='index'),
|
||||
url(r'^(?P<host_port>[^/]+)/?$', views.TrackingUpdateView.as_view(), name='update'),
|
||||
]
|
176
broadview/trackingpanel/views.py
Normal file
176
broadview/trackingpanel/views.py
Normal file
@ -0,0 +1,176 @@
|
||||
# (C) Copyright Broadcom Corporation 2016
|
||||
#
|
||||
# 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 django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import views
|
||||
|
||||
from openstack_dashboard.dashboards.broadview.trackingpanel import forms as bst_forms
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
|
||||
from openstack_dashboard.dashboards.broadview import switches
|
||||
from openstack_dashboard.dashboards.broadview import common
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
def getBSTSwitchTracking(host, port):
|
||||
ret = []
|
||||
first = None
|
||||
x = switches.getBSTSwitches()
|
||||
for y in x:
|
||||
try:
|
||||
output = subprocess.Popen(\
|
||||
["bv-bstctl.py", "get-tracking", "timeout:30", "host:{}".format(y["ip"]), \
|
||||
"port:{}".format(y["port"])], \
|
||||
stdout=subprocess.PIPE).communicate()[0]
|
||||
output = json.loads(output)
|
||||
output["host"] = y["ip"]
|
||||
output["port"] = y["port"]
|
||||
if output:
|
||||
if host == y["ip"] and port == y["port"]:
|
||||
first = output
|
||||
else:
|
||||
ret.append(output)
|
||||
except:
|
||||
LOG.info("getBSTSwitchTracking: unable to execute bv-bstctl {}".format(sys.exc_info()[0]))
|
||||
# if we found a switch matching the specified host, port, put it at the
|
||||
# head of the list
|
||||
|
||||
if first:
|
||||
ret.insert(0, first)
|
||||
return ret
|
||||
|
||||
class TrackingUpdateView(forms.ModalFormView):
|
||||
|
||||
form_class = bst_forms.BSTTrackingForm
|
||||
form_id = "edit_feature"
|
||||
page_title = _("Configure BST Tracking")
|
||||
submit_url = reverse_lazy('horizon:broadview:trackingpanel:index')
|
||||
cancel_url = reverse_lazy('horizon:broadview:trackingpanel:index')
|
||||
success_url = reverse_lazy('horizon:broadview:trackingpanel:update')
|
||||
template_name = 'broadview/trackingpanel/form.html'
|
||||
|
||||
def get_initial(self):
|
||||
initial = super(TrackingUpdateView, self).get_initial()
|
||||
host_port = None
|
||||
host = None
|
||||
port = None
|
||||
|
||||
try:
|
||||
host_port = self.kwargs['host_port']
|
||||
except:
|
||||
pass
|
||||
|
||||
if host_port:
|
||||
host, port = common.getHostPort(host_port)
|
||||
self.host_port = host_port
|
||||
|
||||
switch = getBSTSwitchTracking(host, port)
|
||||
if len(switch):
|
||||
switch = switch[0]
|
||||
try:
|
||||
initial["track_peak_stats"] = "yes" if switch["track-peak-stats"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_peak_stats")
|
||||
|
||||
try:
|
||||
initial["track_ingress_port_priority_group"] = "yes" if switch["track-ingress-port-priority-group"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_ingress_port_priority_group")
|
||||
|
||||
try:
|
||||
initial["track_ingress_port_service_pool"] = "yes" if switch["track-ingress-port-service-pool"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_ingress_port_service_pool")
|
||||
|
||||
try:
|
||||
initial["track_ingress_service_pool"] = "yes" if switch["track-ingress-service-pool"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_ingress_service_pool")
|
||||
|
||||
try:
|
||||
initial["track_egress_port_service_pool"] = "yes" if switch["track-egress-port-service-pool"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_egress_port_service_pool")
|
||||
|
||||
try:
|
||||
initial["track_egress_service_pool"] = "yes" if switch["track-egress-service-pool"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_egress_service_pool")
|
||||
|
||||
try:
|
||||
initial["track_egress_uc_queue"] = "yes" if switch["track-egress-uc-queue"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_egress_uc_queue")
|
||||
|
||||
try:
|
||||
initial["track_egress_uc_queue_group"] = "yes" if switch["track-egress-uc-queue-group"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_egress_uc_queue_group")
|
||||
|
||||
try:
|
||||
initial["track_egress_mc_queue"] = "yes" if switch["track-egress-mc-queue"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_egress_mc_queue")
|
||||
|
||||
try:
|
||||
initial["track_egress_cpu_queue"] = "yes" if switch["track-egress-cpu-queue"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_egress_cpu_queue")
|
||||
|
||||
try:
|
||||
initial["track_egress_rqe_queue"] = "yes" if switch["track-egress-rqe-queue"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_egress_rqe_queue")
|
||||
|
||||
try:
|
||||
initial["track_device"] = "yes" if switch["track-device"] else "no"
|
||||
except:
|
||||
LOG.info("get_initial: unable to initialize track_device")
|
||||
|
||||
|
||||
return initial
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
host = None
|
||||
port = None
|
||||
host_port = None
|
||||
|
||||
try:
|
||||
host_port = self.kwargs['host_port']
|
||||
except:
|
||||
pass
|
||||
|
||||
if host_port:
|
||||
host, port = common.getHostPort(host_port)
|
||||
|
||||
context = super(TrackingUpdateView, self).get_context_data(**kwargs)
|
||||
features = getBSTSwitchTracking(host, port)
|
||||
context["bst_switches"] = common.hyphen2underscore(features)
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
if self.host_port:
|
||||
kwargs["host_port"] = self.host_port
|
||||
|
||||
return reverse('horizon:broadview:trackingpanel:update', kwargs=kwargs)
|
75
doc/source/conf.py
Executable file
75
doc/source/conf.py
Executable file
@ -0,0 +1,75 @@
|
||||
# -*- 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.
|
||||
# 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 os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
#'sphinx.ext.intersphinx',
|
||||
'oslosphinx'
|
||||
]
|
||||
|
||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||
# text edit cycles.
|
||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'broadview-ui'
|
||||
copyright = u'2013, OpenStack Foundation'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
# html_theme_path = ["."]
|
||||
# html_theme = '_theme'
|
||||
# html_static_path = ['static']
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index',
|
||||
'%s.tex' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'OpenStack Foundation', 'manual'),
|
||||
]
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
4
doc/source/contributing.rst
Normal file
4
doc/source/contributing.rst
Normal file
@ -0,0 +1,4 @@
|
||||
============
|
||||
Contributing
|
||||
============
|
||||
.. include:: ../../CONTRIBUTING.rst
|
25
doc/source/index.rst
Normal file
25
doc/source/index.rst
Normal file
@ -0,0 +1,25 @@
|
||||
.. broadview-ui 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 broadview-ui's documentation!
|
||||
========================================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
readme
|
||||
installation
|
||||
usage
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
12
doc/source/installation.rst
Normal file
12
doc/source/installation.rst
Normal file
@ -0,0 +1,12 @@
|
||||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
At the command line::
|
||||
|
||||
$ pip install broadview-ui
|
||||
|
||||
Or, if you have virtualenvwrapper installed::
|
||||
|
||||
$ mkvirtualenv broadview-ui
|
||||
$ pip install broadview-ui
|
1
doc/source/readme.rst
Normal file
1
doc/source/readme.rst
Normal file
@ -0,0 +1 @@
|
||||
.. include:: ../../README.rst
|
7
doc/source/usage.rst
Normal file
7
doc/source/usage.rst
Normal file
@ -0,0 +1,7 @@
|
||||
========
|
||||
Usage
|
||||
========
|
||||
|
||||
To use broadview-ui in a project::
|
||||
|
||||
import broadview_ui
|
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr>=1.6
|
46
setup.cfg
Normal file
46
setup.cfg
Normal file
@ -0,0 +1,46 @@
|
||||
[metadata]
|
||||
name = broadview-ui
|
||||
summary = broadview-ui is a horizon panel that is used to configure OpenStack broadview-collector
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://www.openstack.org/
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Information Technology
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.3
|
||||
Programming Language :: Python :: 3.4
|
||||
|
||||
[files]
|
||||
packages =
|
||||
broadview_ui
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
all_files = 1
|
||||
|
||||
[upload_sphinx]
|
||||
upload-dir = doc/build/html
|
||||
|
||||
[compile_catalog]
|
||||
directory = broadview_ui/locale
|
||||
domain = broadview_ui
|
||||
|
||||
[update_catalog]
|
||||
domain = broadview_ui
|
||||
output_dir = broadview_ui/locale
|
||||
input_file = broadview_ui/locale/broadview_ui.pot
|
||||
|
||||
[extract_messages]
|
||||
keywords = _ gettext ngettext l_ lazy_gettext
|
||||
mapping_file = babel.cfg
|
||||
output_file = broadview_ui/locale/broadview_ui.pot
|
29
setup.py
Normal file
29
setup.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, 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.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
||||
# setuptools if some other modules registered functions in `atexit`.
|
||||
# solution from: http://bugs.python.org/issue15881#msg170215
|
||||
try:
|
||||
import multiprocessing # noqa
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True)
|
14
test-requirements.txt
Normal file
14
test-requirements.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
hacking<0.11,>=0.10.0
|
||||
|
||||
coverage>=3.6
|
||||
python-subunit>=0.0.18
|
||||
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
||||
oslosphinx>=2.5.0 # Apache-2.0
|
||||
oslotest>=1.10.0 # Apache-2.0
|
||||
testrepository>=0.0.18
|
||||
testscenarios>=0.4
|
||||
testtools>=1.4.0
|
60
tox.ini
Normal file
60
tox.ini
Normal file
@ -0,0 +1,60 @@
|
||||
[tox]
|
||||
minversion = 2.0
|
||||
envlist = py34-constraints,py27-constraints,pypy-constraints,pep8-constraints
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
install_command =
|
||||
constraints: {[testenv:common-constraints]install_command}
|
||||
pip install -U {opts} {packages}
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
commands = python setup.py test --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:common-constraints]
|
||||
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
|
||||
|
||||
[testenv:pep8]
|
||||
commands = flake8 {posargs}
|
||||
|
||||
[testenv:pep8-constraints]
|
||||
install_command = {[testenv:common-constraints]install_command}
|
||||
commands = flake8 {posargs}
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:venv-constraints]
|
||||
install_command = {[testenv:common-constraints]install_command}
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:cover]
|
||||
commands = python setup.py test --coverage --testr-args='{posargs}'
|
||||
|
||||
[testenv:cover-constraints]
|
||||
install_command = {[testenv:common-constraints]install_command}
|
||||
commands = python setup.py test --coverage --testr-args='{posargs}'
|
||||
|
||||
[testenv:docs]
|
||||
commands = python setup.py build_sphinx
|
||||
|
||||
[testenv:docs-constraints]
|
||||
install_command = {[testenv:common-constraints]install_command}
|
||||
commands = python setup.py build_sphinx
|
||||
|
||||
[testenv:debug]
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[testenv:debug-constraints]
|
||||
install_command = {[testenv:common-constraints]install_command}
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[flake8]
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
|
||||
show-source = True
|
||||
ignore = E123,E125
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build
|
Loading…
Reference in New Issue
Block a user