Merge "Add rbac support for octavia service apis"

This commit is contained in:
Zuul 2018-04-06 18:30:41 +00:00 committed by Gerrit Code Review
commit dac1952bf6
43 changed files with 222 additions and 79 deletions

3
.gitignore vendored
View File

@ -61,3 +61,6 @@ ChangeLog
.*.swp .*.swp
.*sw? .*sw?
.ropeproject/ .ropeproject/
# Conf
octavia_dashboard/conf

View File

@ -38,12 +38,28 @@ Howto
2. Copy ``_1482_project_load_balancer_panel.py`` in 2. Copy ``_1482_project_load_balancer_panel.py`` in
``octavia_dashboard/enabled`` directory ``octavia_dashboard/enabled`` directory
to ``openstack_dashboard/local/enabled``. to ``openstack_dashboard/local/enabled``::
3. (Optional) Copy the policy file into horizon's policy files folder, and $ cp -a \
add this config ``POLICY_FILES``:: ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/enabled/_1482_*.py \
${HORIZON_DIR}/openstack_dashboard/local/enabled/
'octavia': 'octavia_policy.json', 3. (Optional) Generate the policy file and copy into horizon's policy files
folder, and copy ``_1499_load_balancer_settings.py`` in
``octavia_dashboard/local_settings.d`` directory
to ``openstack_dashboard/local/local_settings.d``::
$ oslopolicy-policy-generator \
--config-file \
${OCTAVIA_DIR}/etc/policy/octavia-policy-generator.conf \
--output-file \
${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml
$ cp -a \
${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml \
${HORIZON_DIR}/openstack_dashboard/conf/
$ cp -a \
${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/local_settings.d/_1499_*.py \
${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/
4. Django has a compressor feature that performs many enhancements for the 4. Django has a compressor feature that performs many enhancements for the
delivery of static files. If the compressor feature is enabled in your delivery of static files. If the compressor feature is enabled in your

View File

@ -1,10 +1,15 @@
function octavia_dashboard_install { function octavia_dashboard_install {
setup_develop $OCTAVIA_DASHBOARD_DIR setup_develop ${OCTAVIA_DASHBOARD_DIR}
} }
function octavia_dashboard_configure { function octavia_dashboard_configure {
cp $OCTAVIA_DASHBOARD_ENABLE_FILE_PATH \ cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/enabled/_1482_project_load_balancer_panel.py ${HORIZON_DIR}/openstack_dashboard/local/enabled/
$HORIZON_DIR/openstack_dashboard/local/enabled/ cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/
oslopolicy-policy-generator --config-file ${OCTAVIA_DIR}/etc/policy/octavia-policy-generator.conf --output-file ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml
cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml ${HORIZON_DIR}/openstack_dashboard/conf/
if [[ -d ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/locale ]]; then
(cd ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard; DJANGO_SETTINGS_MODULE=openstack_dashboard.settings python ../manage.py compilemessages)
fi
} }
if is_service_enabled horizon && is_service_enabled o-api; then if is_service_enabled horizon && is_service_enabled o-api; then
@ -16,20 +21,18 @@ if is_service_enabled horizon && is_service_enabled o-api; then
echo_summary "Configuring octavia-dashboard" echo_summary "Configuring octavia-dashboard"
octavia_dashboard_configure octavia_dashboard_configure
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
# Initialize and start the Octavia dashboard service :
echo_summary "Initializing octavia-dashboard" fi
if [[ "$1" == "unstack" ]]; then
:
fi
if [[ "$1" == "clean" ]]; then
# Remove state and transient data
# Remember clean.sh first calls unstack.sh
rm -f ${HORIZON_DIR}/openstack_dashboard/local/enabled/_1482_project_load_balancer_panel.py*
rm -f ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/_1499_load_balancer_settings.py*
rm -f ${HORIZON_DIR}/openstack_dashboard/conf/octavia_policy.yaml
fi fi
fi fi
if [[ "$1" == "unstack" ]]; then
# Shut down Octavia dashboard services
:
fi
if [[ "$1" == "clean" ]]; then
# Remove state and transient data
# Remember clean.sh first calls unstack.sh
# Remove octavia-dashboard enabled file and pyc
rm -f "$HORIZON_DIR"/openstack_dashboard/local/enabled/"$OCTAVIA_DASHBOARD_ENABLE_FILE_NAME"*
fi

View File

@ -1,5 +1 @@
OCTAVIA_DASHBOARD_DIR=$DEST/octavia-dashboard OCTAVIA_DASHBOARD_DIR=$DEST/octavia-dashboard
OCTAVIA_DASHBOARD_ENABLE_FILE_NAME=_1482_project_load_balancer_panel.py
OCTAVIA_DASHBOARD_ENABLE_FILE_PATH=$OCTAVIA_DASHBOARD_DIR/octavia_dashboard/enabled/$OCTAVIA_DASHBOARD_ENABLE_FILE_NAME

View File

@ -109,7 +109,6 @@ bug_project = '909'
bug_tag = 'docs' bug_tag = 'docs'
# TODO(mordred) We should extract this into a sphinx plugin # TODO(mordred) We should extract this into a sphinx plugin
def run_apidoc(_): def run_apidoc(_):
cur_dir = os.path.abspath(os.path.dirname(__file__)) cur_dir = os.path.abspath(os.path.dirname(__file__))
@ -128,6 +127,8 @@ def run_apidoc(_):
'octavia_dashboard/enabled', 'octavia_dashboard/enabled',
'octavia_dashboard/locale', 'octavia_dashboard/locale',
'octavia_dashboard/static', 'octavia_dashboard/static',
'octavia_dashboard/conf',
'octavia_dashboard/local_settings.d',
'octavia_dashboard/post_install.sh', 'octavia_dashboard/post_install.sh',
'octavia_dashboard/karma.conf.js' 'octavia_dashboard/karma.conf.js'
]) ])

View File

@ -0,0 +1,22 @@
# Copyright 2018 Walmart.
# 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 to be included for configuring application which relates
# to load-balancer(Octavia) functions.
from django.conf import settings
settings.POLICY_FILES.update({
'load-balancer': 'octavia_policy.yaml',
})

View File

@ -54,7 +54,9 @@
}); });
function allowed() { function allowed() {
return policy.ifAllowed({ rules: [['neutron', 'create_health_monitor']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:post']]
});
} }
function handle(response) { function handle(response) {

View File

@ -31,7 +31,11 @@
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed) expect(policy.ifAllowed)
.toHaveBeenCalledWith({rules: [['neutron', 'create_health_monitor']]}); .toHaveBeenCalledWith({
rules: [[
'load-balancer', 'os_load-balancer_api:healthmonitor:post'
]]
});
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -67,9 +67,9 @@
////////////// //////////////
function allowed(/*item*/) { function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there return policy.ifAllowed({
// will be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:delete']]
return policy.ifAllowed({ rules: [['neutron', 'delete_health_monitor']] }); });
} }
function perform(items, scope) { function perform(items, scope) {

View File

@ -55,7 +55,9 @@
}); });
function allowed(/*healthmonitor*/) { function allowed(/*healthmonitor*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_health_monitor']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:put']]
});
} }
function handle(response) { function handle(response) {

View File

@ -31,7 +31,11 @@
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed) expect(policy.ifAllowed)
.toHaveBeenCalledWith({rules: [['neutron', 'update_health_monitor']]}); .toHaveBeenCalledWith({
rules: [[
'load-balancer', 'os_load-balancer_api:healthmonitor:put'
]]
});
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -61,7 +61,7 @@
function allowed() { function allowed() {
return $q.all([ return $q.all([
policy.ifAllowed({ rules: [['neutron', 'create_l7policy']] }) policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7policy:post']] })
]); ]);
} }

View File

@ -67,9 +67,9 @@
////////////// //////////////
function allowed(/*item*/) { function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there return policy.ifAllowed({
// will be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:l7policy:delete']]
return policy.ifAllowed({ rules: [['neutron', 'delete_l7policy']] }); });
} }
function perform(items, scope) { function perform(items, scope) {

View File

@ -56,7 +56,9 @@
}); });
function allowed(/*item*/) { function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_l7policy']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:l7policy:put']]
});
} }
function handle(response) { function handle(response) {

View File

@ -43,7 +43,7 @@
it('should check policy to allow editing a l7policy', function() { it('should check policy to allow editing a l7policy', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_l7policy']]}); expect(policy.ifAllowed).toHaveBeenCalled();
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -61,7 +61,7 @@
function allowed() { function allowed() {
return $q.all([ return $q.all([
policy.ifAllowed({ rules: [['neutron', 'create_l7rule']] }) policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7rule:post']] })
]); ]);
} }

View File

@ -67,9 +67,9 @@
////////////// //////////////
function allowed(/*item*/) { function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there return policy.ifAllowed({
// will be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:l7rule:delete']]
return policy.ifAllowed({ rules: [['neutron', 'delete_l7rule']] }); });
} }
function perform(items, scope) { function perform(items, scope) {

View File

@ -56,7 +56,9 @@
}); });
function allowed(/*item*/) { function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_l7rule']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:l7rule:put']]
});
} }
function handle(response) { function handle(response) {

View File

@ -43,7 +43,7 @@
it('should check policy to allow editing a l7rule', function() { it('should check policy to allow editing a l7rule', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_l7rule']]}); expect(policy.ifAllowed).toHaveBeenCalled();
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -56,7 +56,9 @@
}); });
function allowed() { function allowed() {
return policy.ifAllowed({ rules: [['neutron', 'create_listener']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:listener:post']]
});
} }
function handle(response) { function handle(response) {

View File

@ -43,7 +43,13 @@
it('should check policy to allow creating a listener', function() { it('should check policy to allow creating a listener', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'create_listener']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:listener:post'
]]
}
);
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -156,7 +156,9 @@
} }
function allowed() { function allowed() {
return policy.ifAllowed({ rules: [['neutron', 'delete_listener']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:listener:delete']]
});
} }
function deleteItem(id) { function deleteItem(id) {

View File

@ -24,7 +24,13 @@
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
var allowed = service.allowed(item); var allowed = service.allowed(item);
$scope.$apply(); $scope.$apply();
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'delete_listener']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:listener:delete'
]]
}
);
return allowed; return allowed;
} }

View File

@ -56,7 +56,9 @@
}); });
function allowed(/*item*/) { function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_listener']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:listener:put']]
});
} }
function handle(response) { function handle(response) {

View File

@ -43,7 +43,13 @@
it('should check policy to allow editing a listener', function() { it('should check policy to allow editing a listener', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_listener']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:listener:put'
]]
}
);
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -57,9 +57,9 @@
}); });
function allowed() { function allowed() {
// This rule is made up and should therefore always pass. I assume at some point there return policy.ifAllowed({
// will be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:post']]
return policy.ifAllowed({ rules: [['neutron', 'create_loadbalancer']] }); });
} }
function handle(response) { function handle(response) {

View File

@ -44,7 +44,13 @@
it('should check policy to allow creating a load balancer', function() { it('should check policy to allow creating a load balancer', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'create_loadbalancer']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:loadbalancer:post'
]]
}
);
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -124,9 +124,9 @@
} }
function allowed() { function allowed() {
// This rule is made up and should therefore always pass. I assume at some point there return policy.ifAllowed({
// will be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:delete']]
return policy.ifAllowed({ rules: [['neutron', 'delete_loadbalancer']] }); });
} }
function canBeDeleted(item) { function canBeDeleted(item) {

View File

@ -24,7 +24,13 @@
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
var allowed = service.allowed(item); var allowed = service.allowed(item);
$scope.$apply(); $scope.$apply();
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'delete_loadbalancer']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:loadbalancer:delete'
]]
}
);
return allowed; return allowed;
} }

View File

@ -62,9 +62,9 @@
/////////////// ///////////////
function allowed() { function allowed() {
// This rule is made up and should therefore always pass. At some point there will return policy.ifAllowed({
// likely be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:put']]
return policy.ifAllowed({ rules: [['neutron', 'update_loadbalancer']] }); });
} }
function handle(response) { function handle(response) {

View File

@ -24,7 +24,13 @@
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
var allowed = service.allowed(item); var allowed = service.allowed(item);
scope.$apply(); scope.$apply();
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_loadbalancer']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:loadbalancer:put'
]]
}
);
return allowed; return allowed;
} }

View File

@ -65,9 +65,9 @@
////////////// //////////////
function allowed(/*item*/) { function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there return policy.ifAllowed({
// will be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:member:delete']]
return policy.ifAllowed({ rules: [['neutron', 'pool_member_delete']] }); });
} }
function perform(items, scope) { function perform(items, scope) {

View File

@ -71,9 +71,9 @@
//////////// ////////////
function allowed(/*item*/) { function allowed(/*item*/) {
// This rule is made up and should therefore always pass. At some point there will return policy.ifAllowed({
// likely be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:member:put']]
return policy.ifAllowed({ rules: [['neutron', 'pool_member_update']] }); });
} }
/** /**

View File

@ -32,7 +32,13 @@
function allowed(item) { function allowed(item) {
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
var allowed = service.allowed(item); var allowed = service.allowed(item);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'pool_member_update']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:member:put'
]]
}
);
return allowed; return allowed;
} }

View File

@ -57,7 +57,9 @@
}); });
function allowed(/*item*/) { function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_member_list']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:pool:put']]
});
} }
function handle(response) { function handle(response) {

View File

@ -46,7 +46,13 @@
it('should check policy to allow updating member list', function() { it('should check policy to allow updating member list', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_member_list']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:pool:put'
]]
}
);
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -62,7 +62,9 @@
function allowed() { function allowed() {
return $q.all([ return $q.all([
policy.ifAllowed({ rules: [['neutron', 'create_pool']] }) policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:pool:post']]
})
]); ]);
} }

View File

@ -68,9 +68,9 @@
////////////// //////////////
function allowed(/*item*/) { function allowed(/*item*/) {
// This rule is made up and should therefore always pass. I assume at some point there return policy.ifAllowed({
// will be a valid rule similar to this that we will want to use. rules: [['load-balancer', 'os_load-balancer_api:pool:delete']]
return policy.ifAllowed({ rules: [['neutron', 'delete_pool']] }); });
} }
function perform(items, scope) { function perform(items, scope) {

View File

@ -57,7 +57,9 @@
}); });
function allowed(/*item*/) { function allowed(/*item*/) {
return policy.ifAllowed({ rules: [['neutron', 'update_pool']] }); return policy.ifAllowed({
rules: [['load-balancer', 'os_load-balancer_api:pool:put']]
});
} }
function handle(response) { function handle(response) {

View File

@ -44,7 +44,13 @@
it('should check policy to allow editing a pool', function() { it('should check policy to allow editing a pool', function() {
spyOn(policy, 'ifAllowed').and.returnValue(true); spyOn(policy, 'ifAllowed').and.returnValue(true);
expect(service.allowed()).toBe(true); expect(service.allowed()).toBe(true);
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_pool']]}); expect(policy.ifAllowed).toHaveBeenCalledWith(
{
rules: [[
'load-balancer', 'os_load-balancer_api:pool:put'
]]
}
);
}); });
it('should handle the action result properly', function() { it('should handle the action result properly', function() {

View File

@ -0,0 +1,18 @@
---
features:
- |
Adds RBAC support to the dashboard panels.
upgrade:
- |
To enable RBAC support in the Octavia dashboard you need to install the
generated octavia_dashboard/conf/octavia_policy.yaml file into your
horizon openstack_dashboard/conf/ directory and also
copy octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py
file into your horizon openstack_dashboard/local/local_settings.d/
directory.
security:
- |
RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC
in the dashboard or not, the API RBAC will still be in effect. Enabling
RBAC in the dashboard will enforce the policies in the dashboard before
the API call is made.

View File

@ -38,6 +38,8 @@ autodoc_tree_excludes =
octavia_dashboard/enabled octavia_dashboard/enabled
octavia_dashboard/locale octavia_dashboard/locale
octavia_dashboard/static octavia_dashboard/static
octavia_dashboard/conf
octavia_dashboard/local_settings.d
octavia_dashboard/post_install.sh octavia_dashboard/post_install.sh
octavia_dashboard/karma.conf.js octavia_dashboard/karma.conf.js
autodoc_index_modules = False autodoc_index_modules = False