Availability Zone admin API

Adds the ability for admins to create/manage availability_zones
and profiles for use with upcoming functionality. Works like flavors.

Depends-On: https://review.opendev.org/#/c/694057/
Change-Id: I468d9fdf8c9d0898f9e30f04ac233510a10a53fc
changes/65/693765/15
Adam Harwell 2019-11-12 18:15:38 -08:00
parent 4a5c24ef6f
commit 8ae6bc3697
77 changed files with 3817 additions and 58 deletions

View File

@ -7,6 +7,18 @@ path-amphora-id:
in: path
required: true
type: uuid
path-availability-zone-name:
description: |
The name of the availability zone to query.
in: path
required: true
type: string
path-availability-zone-profile-id:
description: |
The ID of the availability zone profile to query.
in: path
required: true
type: uuid
path-flavor-id:
description: |
The ID of the flavor to query.
@ -220,6 +232,66 @@ api_version_status:
in: body
required: true
type: string
availability-zone:
description: |
An availability zone object.
in: body
required: true
type: object
availability-zone-capabilities:
description: |
The provider availability zone capabilities dictonary object.
in: body
required: true
type: object
availability-zone-capability-description:
description: |
The provider availability zone capability description.
in: body
required: true
type: string
availability-zone-capability-name:
description: |
The provider availability zone capability name.
in: body
required: true
type: string
availability-zone-data:
description: |
The JSON string containing the availability zone metadata.
in: body
required: true
type: string
availability-zone-data-optional:
description: |
The JSON string containing the availability zone metadata.
in: body
required: false
type: string
availability-zone-profile:
description: |
An ``availability zone profile`` object.
in: body
required: true
type: object
availability-zone-profile-id:
description: |
The ID of the availability zone profile.
in: body
required: true
type: uuid
availability-zone-profiles:
description: |
A list of ``availability zone profile`` objects.
in: body
required: true
type: array
availability-zones:
description: |
A list of ``availability zone`` objects.
in: body
required: true
type: array
backup:
description: |
Is the member a backup? Backup members only receive traffic when all

View File

@ -0,0 +1,290 @@
.. -*- rst -*-
List Availability Zones
=======================
.. rest_method:: GET /v2.0/lbaas/availabilityzones
List all available availability zones.
Use the ``fields`` query parameter to control which fields are
returned in the response body. Additionally, you can filter results
by using query string parameters. For information, see :ref:`filtering`.
The list might be empty.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 200
.. rest_status_code:: error ../http-status.yaml
- 400
- 401
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- fields: fields
Curl Example
------------
.. literalinclude:: examples/availabilityzone-list-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- description: description
- enabled: enabled
- availability_zone_profile_id: availability-zone-profile-id
- availability_zones: availability-zones
- name: name
Response Example
----------------
.. literalinclude:: examples/availabilityzone-list-response.json
:language: javascript
Create Availability Zone
========================
.. rest_method:: POST /v2.0/lbaas/availabilityzones
Creates an availability zone.
If the API cannot fulfill the request due to insufficient data or
data that is not valid, the service returns the HTTP ``Bad Request
(400)`` response code with information about the failure in the
response body. Validation errors require that you correct the error
and submit the request again.
If you are not an administrative user the service returns the HTTP ``Forbidden
(403)`` response code.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 201
.. rest_status_code:: error ../http-status.yaml
- 400
- 401
- 403
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- description: description-optional
- enabled: enabled-optional
- availability_zone: availability-zone
- availability_zone_profile_id: availability-zone-profile-id
- name: name
Request Example
---------------
.. literalinclude:: examples/availabilityzone-create-request.json
:language: javascript
Curl Example
------------
.. literalinclude:: examples/availabilityzone-create-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- description: description
- enabled: enabled
- availability_zone_profile_id: availability-zone-profile-id
- availability_zone: availability-zone
- name: name
Response Example
----------------
.. literalinclude:: examples/availabilityzone-create-response.json
:language: javascript
Show Availability Zone Details
==============================
.. rest_method:: GET /v2.0/lbaas/availabilityzones/{availability_zone_name}
Shows the details of an availability zone.
Use the ``fields`` query parameter to control which fields are
returned in the response body. Additionally, you can filter results
by using query string parameters. For information, see :ref:`filtering`.
This operation does not require a request body.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 200
.. rest_status_code:: error ../http-status.yaml
- 401
- 404
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- fields: fields
- availability_zone_name: path-availability-zone-name
Curl Example
------------
.. literalinclude:: examples/availabilityzone-show-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- description: description
- enabled: enabled
- availability_zone_profile_id: availability-zone-profile-id
- availability_zone: availability-zone
- name: name
Response Example
----------------
.. literalinclude:: examples/availabilityzone-show-response.json
:language: javascript
Update an Availability Zone
===========================
.. rest_method:: PUT /v2.0/lbaas/availabilityzones/{availability_zone_name}
Update an availability zone.
If you are not an administrative user the service returns the HTTP ``Forbidden
(403)`` response code.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 200
.. rest_status_code:: error ../http-status.yaml
- 400
- 401
- 403
- 404
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- description: description-optional
- enabled: enabled-optional
- availability_zone: availability-zone
- availability_zone_name: path-availability-zone-name
Request Example
---------------
.. literalinclude:: examples/availabilityzone-update-request.json
:language: javascript
Curl Example
------------
.. literalinclude:: examples/availabilityzone-update-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- description: description
- enabled: enabled
- availability_zone_profile_id: availability-zone-profile-id
- availability_zone: availability-zone
- name: name
Response Example
----------------
.. literalinclude:: examples/availabilityzone-update-response.json
:language: javascript
Remove an Availability Zone
===========================
.. rest_method:: DELETE /v2.0/lbaas/availabilityzones/{availability_zone_name}
Remove an availability zone and its associated configuration.
If any load balancers are using this availability zone the service returns
the HTTP ``Conflict (409)`` response code.
If you are not an administrative user the service returns the HTTP ``Forbidden
(403)`` response code.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 204
.. rest_status_code:: error ../http-status.yaml
- 401
- 403
- 404
- 409
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- availability_zone_name: path-availability-zone-name
Curl Example
------------
.. literalinclude:: examples/availabilityzone-delete-curl
:language: bash
Response
--------
There is no body content for the response of a successful DELETE request.

View File

@ -0,0 +1,297 @@
.. -*- rst -*-
List Availability Zone Profiles
===============================
.. rest_method:: GET /v2.0/lbaas/availabilityzoneprofiles
List all available Availability Zone Profiles.
Use the ``fields`` query parameter to control which fields are
returned in the response body. Additionally, you can filter results
by using query string parameters. For information, see :ref:`filtering`.
If you are not an administrative user the service returns the HTTP ``Forbidden
(403)`` response code.
The list might be empty.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 200
.. rest_status_code:: error ../http-status.yaml
- 400
- 401
- 403
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- fields: fields
Curl Example
------------
.. literalinclude:: examples/availabilityzoneprofile-list-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- availability_zone_data: availability-zone-data
- availability_zone_profiles: availability-zone-profiles
- id: availability-zone-profile-id
- name: name
- provider_name: provider-name
Response Example
----------------
.. literalinclude:: examples/availabilityzoneprofile-list-response.json
:language: javascript
Create Availability Zone Profile
================================
.. rest_method:: POST /v2.0/lbaas/availabilityzoneprofiles
Creates a Availability Zone Profile.
If the API cannot fulfill the request due to insufficient data or
data that is not valid, the service returns the HTTP ``Bad Request
(400)`` response code with information about the failure in the
response body. Validation errors require that you correct the error
and submit the request again.
If you are not an administrative user the service returns the HTTP ``Forbidden
(403)`` response code.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 201
.. rest_status_code:: error ../http-status.yaml
- 400
- 401
- 403
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- availability_zone_data: availability-zone-data
- availability_zone_profile: availability-zone-profile
- name: name
- provider_name: provider-name
Request Example
---------------
.. literalinclude:: examples/availabilityzoneprofile-create-request.json
:language: javascript
Curl Example
------------
.. literalinclude:: examples/availabilityzoneprofile-create-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- availability_zone_data: availability-zone-data
- availability_zone_profile: availability-zone-profile
- id: availability-zone-profile-id
- name: name
- provider_name: provider-name
Response Example
----------------
.. literalinclude:: examples/availabilityzoneprofile-create-response.json
:language: javascript
Show Availability Zone Profile Details
======================================
.. rest_method:: GET /v2.0/lbaas/availabilityzoneprofiles/{availability_zone_profile_id}
Shows the details of a Availability Zone Profile.
Use the ``fields`` query parameter to control which fields are
returned in the response body. Additionally, you can filter results
by using query string parameters. For information, see :ref:`filtering`.
If you are not an administrative user the service returns the HTTP ``Forbidden
(403)`` response code.
This operation does not require a request body.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 200
.. rest_status_code:: error ../http-status.yaml
- 401
- 403
- 404
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- fields: fields
- availability_zone_profile_id: path-availability-zone-profile-id
Curl Example
------------
.. literalinclude:: examples/availabilityzoneprofile-show-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- availability_zone_data: availability-zone-data
- availability_zone_profile: availability-zone-profile
- id: availability-zone-profile-id
- name: name
- provider_name: provider-name
Response Example
----------------
.. literalinclude:: examples/availabilityzoneprofile-show-response.json
:language: javascript
Update a Availability Zone Profile
==================================
.. rest_method:: PUT /v2.0/lbaas/availabilityzoneprofiles/{availability_zone_profile_id}
Update a Availability Zone Profile.
If you are not an administrative user the service returns the HTTP ``Forbidden
(403)`` response code.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 200
.. rest_status_code:: error ../http-status.yaml
- 400
- 401
- 403
- 404
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- availability_zone_data: availability-zone-data-optional
- availability_zone_profile: availability-zone-profile
- availability_zone_profile_id: path-availability-zone-profile-id
- name: name-optional
- provider_name: provider-name-optional
Request Example
---------------
.. literalinclude:: examples/availabilityzoneprofile-update-request.json
:language: javascript
Curl Example
------------
.. literalinclude:: examples/availabilityzoneprofile-update-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- availability_zone_data: availability-zone-data
- availability_zone_profile: availability-zone-profile
- id: availability-zone-profile-id
- name: name
- provider_name: provider-name
Response Example
----------------
.. literalinclude:: examples/availabilityzoneprofile-update-response.json
:language: javascript
Remove a Availability Zone Profile
==================================
.. rest_method:: DELETE /v2.0/lbaas/availabilityzoneprofiles/{availability_zone_profile_id}
Remove a Availability Zone Profile and its associated configuration.
If any availability zone is using this Availability Zone Profile the service
returns the HTTP ``Conflict (409)`` response code.
If you are not an administrative user the service returns the HTTP ``Forbidden
(403)`` response code.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 204
.. rest_status_code:: error ../http-status.yaml
- 401
- 403
- 404
- 409
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- availability_zone_profile_id: path-availability-zone-profile-id
Curl Example
------------
.. literalinclude:: examples/availabilityzoneprofile-delete-curl
:language: bash
Response
--------
There is no body content for the response of a successful DELETE request.

View File

@ -0,0 +1 @@
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"availability_zone":{"name":"my_az","description":"My availability zone.","enabled":true,"availability_zone_profile_id":"5712097e-0092-45dc-bff0-ab68b61ad51a"}}' http://198.51.100.10:9876/v2.0/lbaas/availabilityzones

View File

@ -0,0 +1,8 @@
{
"availability_zone": {
"name": "my_az",
"description": "My availability zone.",
"enabled": true,
"availability_zone_profile_id": "5712097e-0092-45dc-bff0-ab68b61ad51a"
}
}

View File

@ -0,0 +1,8 @@
{
"availability_zone": {
"name": "my_az",
"description": "My availability zone.",
"enabled": true,
"availability_zone_profile_id": "5712097e-0092-45dc-bff0-ab68b61ad51a"
}
}

View File

@ -0,0 +1 @@
curl -X DELETE -H "X-Auth-Token: <token>" http://198.51.100.10:9876/v2.0/lbaas/availabilityzones/my_az

View File

@ -0,0 +1 @@
curl -X GET -H "X-Auth-Token: <token>" http://198.51.100.10:9876/v2.0/lbaas/availabilityzones

View File

@ -0,0 +1,10 @@
{
"availability_zones": [
{
"name": "my_az",
"description": "My availability zone.",
"enabled": true,
"availability_zone_profile_id": "5712097e-0092-45dc-bff0-ab68b61ad51a"
}
]
}

View File

@ -0,0 +1 @@
curl -X GET -H "X-Auth-Token: <token>" http://198.51.100.10:9876/v2.0/lbaas/availabilityzones/my_az

View File

@ -0,0 +1,8 @@
{
"availability_zone": {
"name": "my_az",
"description": "My availability zone.",
"enabled": true,
"availability_zone_profile_id": "5712097e-0092-45dc-bff0-ab68b61ad51a"
}
}

View File

@ -0,0 +1 @@
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"availability_zone":{"description":"My availability zone.","enabled":false}}' http://198.51.100.10:9876/v2.0/lbaas/availabilityzones/my_az

View File

@ -0,0 +1,6 @@
{
"availability_zone": {
"description": "My availability zone.",
"enabled": false
}
}

View File

@ -0,0 +1,8 @@
{
"availability_zone": {
"name": "my_az",
"description": "My availability zone.",
"enabled": false,
"availability_zone_profile_id": "5712097e-0092-45dc-bff0-ab68b61ad51a"
}
}

View File

@ -0,0 +1 @@
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"availability_zone_profile":{"name":"some_az","provider_name":"amphora","availability_zone_data":"{\"compute_zone\": \"az1\"}"}}' http://198.51.100.10:9876/v2.0/lbaas/availabilityzoneprofiles

View File

@ -0,0 +1,8 @@
{
"availability_zone_profile":
{
"name": "some_az",
"provider_name": "amphora",
"availability_zone_data": "{\"compute_zone\": \"az1\"}"
}
}

View File

@ -0,0 +1,9 @@
{
"availability_zone_profile":
{
"id": "5712097e-0092-45dc-bff0-ab68b61ad51a",
"name": "some_az",
"provider_name": "amphora",
"availability_zone_data": "{\"compute_zone\": \"az1\"}"
}
}

View File

@ -0,0 +1 @@
curl -X DELETE -H "X-Auth-Token: <token>" http://198.51.100.10:9876/v2.0/lbaas/availabilityzoneprofiles/5712097e-0092-45dc-bff0-ab68b61ad51a

View File

@ -0,0 +1 @@
curl -X GET -H "X-Auth-Token: <token>" http://198.51.100.10:9876/v2.0/lbaas/availabilityzoneprofiles

View File

@ -0,0 +1,10 @@
{
"availability_zone_profiles": [
{
"id": "5712097e-0092-45dc-bff0-ab68b61ad51a",
"name": "some_az",
"provider_name": "amphora",
"availability_zone_data": "{\"compute_zone\": \"az1\"}"
}
]
}

View File

@ -0,0 +1 @@
curl -X GET -H "X-Auth-Token: <token>" http://198.51.100.10:9876/v2.0/lbaas/availabilityzoneprofiles/5712097e-0092-45dc-bff0-ab68b61ad51a

View File

@ -0,0 +1,9 @@
{
"availability_zone_profile":
{
"id": "5712097e-0092-45dc-bff0-ab68b61ad51a",
"name": "some_az",
"provider_name": "amphora",
"availability_zone_data": "{\"compute_zone\": \"az1\"}"
}
}

View File

@ -0,0 +1 @@
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"availability_zone_profile":{"name":"other_az","provider_name":"amphora","availability_zone_data":"{\"compute_zone\": \"az2\"}"}}' http://198.51.100.10:9876/v2.0/lbaas/availabilityzoneprofiles/5712097e-0092-45dc-bff0-ab68b61ad51a

View File

@ -0,0 +1,8 @@
{
"availability_zone_profile":
{
"name": "other_az",
"provider_name": "amphora",
"availability_zone_data": "{\"compute_zone\": \"az2\"}"
}
}

View File

@ -0,0 +1,9 @@
{
"availability_zone_profile":
{
"id": "5712097e-0092-45dc-bff0-ab68b61ad51a",
"name": "other_az",
"provider_name": "amphora",
"availability_zone_data": "{\"compute_zone\": \"az2\"}"
}
}

View File

@ -0,0 +1 @@
curl -X GET -H "X-Auth-Token: <token>" http://198.51.100.10:9876/v2/lbaas/providers/amphora/availability_zone_capabilities

View File

@ -0,0 +1,8 @@
{
"availability_zone_capabilities": [
{
"name": "compute_zone",
"description": "The compute availability zone."
}
]
}

View File

@ -97,7 +97,7 @@ Request
- name: name
Request Example
----------------
---------------
.. literalinclude:: examples/flavor-create-request.json
:language: javascript

View File

@ -99,7 +99,7 @@ Request
- provider_name: provider-name
Request Example
----------------
---------------
.. literalinclude:: examples/flavorprofile-create-request.json
:language: javascript

View File

@ -66,6 +66,16 @@ Flavor Profiles
---------------
.. include:: flavorprofile.inc
------------------
Availability Zones
------------------
.. include:: availabilityzone.inc
--------------------------
Availability Zone Profiles
--------------------------
.. include:: availabilityzoneprofile.inc
--------
Amphorae
--------

View File

@ -103,3 +103,57 @@ Response Example
.. literalinclude:: examples/provider-flavor-capability-show-response.json
:language: javascript
Show Provider Availability Zone Capabilities
============================================
.. rest_method:: GET /v2/lbaas/providers/{provider}/availability_zone_capabilities
Shows the provider driver availability zone capabilities. These are the
features of the provider driver that can be configured in an Octavia
availability zone. This API returns a list of dictionaries with the name and
description of each availability zone capability of the provider.
The list might be empty and a provider driver may not implement this feature.
**New in version 2.14**
.. rest_status_code:: success ../http-status.yaml
- 200
.. rest_status_code:: error ../http-status.yaml
- 400
- 401
- 403
- 500
Request
-------
.. rest_parameters:: ../parameters.yaml
- fields: fields
- provider: path-provider
Curl Example
------------
.. literalinclude:: examples/provider-availability-zone-capability-show-curl
:language: bash
Response Parameters
-------------------
.. rest_parameters:: ../parameters.yaml
- availability_zone_capabilities: availability-zone-capabilities
- name: availability-zone-capability-name
- description: availability-zone-capability-description
Response Example
----------------
.. literalinclude:: examples/provider-availability-zone-capability-show-response.json
:language: javascript

View File

@ -0,0 +1,47 @@
# Copyright 2018 Rackspace US Inc. All rights reserved.
# Copyright 2019 Verizon Media
#
# 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 octavia.common import constants as consts
# This is a JSON schema validation dictionary
# https://json-schema.org/latest/json-schema-validation.html
#
# Note: This is used to generate the amphora driver "supported availability
# zone metadata" dictionary. Each property should include a description
# for the user to understand what this availability zone setting does.
#
# Where possible, the property name should match the configuration file name
# for the setting. The configuration file setting is the default when a
# setting is not defined in an availability zone profile.
SUPPORTED_AVAILABILITY_ZONE_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Octavia Amphora Driver Availability Zone Metadata Schema",
"description": "This schema is used to validate new availability zone "
"profiles submitted for use in an amphora driver "
"availability zone.",
"type": "object",
"additionalProperties": False,
"properties": {
consts.COMPUTE_ZONE: {
"type": "string",
"description": "The compute availability zone."
},
consts.MANAGEMENT_NETWORK: {
"type": "string",
"description": "The management network ID for the amphora."
}
}
}

View File

@ -24,6 +24,7 @@ from octavia_lib.api.drivers import data_models as driver_dm
from octavia_lib.api.drivers import exceptions
from octavia_lib.api.drivers import provider_base as driver_base
from octavia.api.drivers.amphora_driver import availability_zone_schema
from octavia.api.drivers.amphora_driver import flavor_schema
from octavia.api.drivers import utils as driver_utils
from octavia.common import constants as consts
@ -385,3 +386,70 @@ class AmphoraProviderDriver(driver_base.ProviderDriver):
# TODO(johnsom) Fix this to raise a NotFound error
# when the octavia-lib supports it.
compute_driver.validate_flavor(compute_flavor)
# Availability Zone
def get_supported_availability_zone_metadata(self):
"""Returns the valid availability zone metadata keys and descriptions.
This extracts the valid availability zone metadata keys and
descriptions from the JSON validation schema and returns it as a
dictionary.
:return: Dictionary of availability zone metadata keys and descriptions
:raises DriverError: An unexpected error occurred.
"""
try:
props = (
availability_zone_schema.SUPPORTED_AVAILABILITY_ZONE_SCHEMA[
'properties'])
return {k: v.get('description', '') for k, v in props.items()}
except Exception as e:
raise exceptions.DriverError(
user_fault_string='Failed to get the supported availability '
'zone metadata due to: {}'.format(str(e)),
operator_fault_string='Failed to get the supported '
'availability zone metadata due to: '
'{}'.format(str(e)))
def validate_availability_zone(self, availability_zone_dict):
"""Validates availability zone profile data.
This will validate an availability zone profile dataset against the
availability zone settings the amphora driver supports.
:param availability_zone_dict: The availability zone dict to validate.
:type availability_zone_dict: dict
:return: None
:raises DriverError: An unexpected error occurred.
:raises UnsupportedOptionError: If the driver does not support
one of the availability zone settings.
"""
try:
validate(
availability_zone_dict,
availability_zone_schema.SUPPORTED_AVAILABILITY_ZONE_SCHEMA)
except js_exceptions.ValidationError as e:
error_object = ''
if e.relative_path:
error_object = '{} '.format(e.relative_path[0])
raise exceptions.UnsupportedOptionError(
user_fault_string='{0}{1}'.format(error_object, e.message),
operator_fault_string=str(e))
except Exception as e:
raise exceptions.DriverError(
user_fault_string='Failed to validate the availability zone '
'metadata due to: {}'.format(str(e)),
operator_fault_string='Failed to validate the availability '
'zone metadata due to: {}'.format(str(e))
)
compute_zone = availability_zone_dict.get(consts.COMPUTE_ZONE, None)
if compute_zone:
compute_driver = stevedore_driver.DriverManager(
namespace='octavia.compute.drivers',
name=CONF.controller_worker.compute_driver,
invoke_on_load=True
).driver
# TODO(johnsom) Fix this to raise a NotFound error
# when the octavia-lib supports it.
compute_driver.validate_availability_zone(compute_zone)

View File

@ -24,6 +24,7 @@ from octavia_lib.api.drivers import data_models as driver_dm
from octavia_lib.api.drivers import exceptions
from octavia_lib.api.drivers import provider_base as driver_base
from octavia.api.drivers.amphora_driver import availability_zone_schema
from octavia.api.drivers.amphora_driver import flavor_schema
from octavia.api.drivers import utils as driver_utils
from octavia.common import constants as consts
@ -384,3 +385,70 @@ class AmphoraProviderDriver(driver_base.ProviderDriver):
# TODO(johnsom) Fix this to raise a NotFound error
# when the octavia-lib supports it.
compute_driver.validate_flavor(compute_flavor)
# Availability Zone
def get_supported_availability_zone_metadata(self):
"""Returns the valid availability zone metadata keys and descriptions.
This extracts the valid availability zone metadata keys and
descriptions from the JSON validation schema and returns it as a
dictionary.
:return: Dictionary of availability zone metadata keys and descriptions
:raises DriverError: An unexpected error occurred.
"""
try:
props = (
availability_zone_schema.SUPPORTED_AVAILABILITY_ZONE_SCHEMA[
'properties'])
return {k: v.get('description', '') for k, v in props.items()}
except Exception as e:
raise exceptions.DriverError(
user_fault_string='Failed to get the supported availability '
'zone metadata due to: {}'.format(str(e)),
operator_fault_string='Failed to get the supported '
'availability zone metadata due to: '
'{}'.format(str(e)))
def validate_availability_zone(self, availability_zone_dict):
"""Validates availability zone profile data.
This will validate an availability zone profile dataset against the
availability zone settings the amphora driver supports.
:param availability_zone_dict: The availability zone dict to validate.
:type availability_zone_dict: dict
:return: None
:raises DriverError: An unexpected error occurred.
:raises UnsupportedOptionError: If the driver does not support
one of the availability zone settings.
"""
try:
validate(
availability_zone_dict,
availability_zone_schema.SUPPORTED_AVAILABILITY_ZONE_SCHEMA)
except js_exceptions.ValidationError as e:
error_object = ''
if e.relative_path:
error_object = '{} '.format(e.relative_path[0])
raise exceptions.UnsupportedOptionError(
user_fault_string='{0}{1}'.format(error_object, e.message),
operator_fault_string=str(e))
except Exception as e:
raise exceptions.DriverError(
user_fault_string='Failed to validate the availability zone '
'metadata due to: {}'.format(str(e)),
operator_fault_string='Failed to validate the availability '
'zone metadata due to: {}'.format(str(e))
)
compute_zone = availability_zone_dict.get(consts.COMPUTE_ZONE, None)
if compute_zone:
compute_driver = stevedore_driver.DriverManager(
namespace='octavia.compute.drivers',
name=CONF.controller_worker.compute_driver,
invoke_on_load=True
).driver
# TODO(johnsom) Fix this to raise a NotFound error
# when the octavia-lib supports it.
compute_driver.validate_availability_zone(compute_zone)

View File

@ -242,6 +242,23 @@ class NoopManager(object):
flavor_hash = hash(frozenset(flavor_metadata))
self.driverconfig[flavor_hash] = (flavor_metadata, 'validate_flavor')
# Availability Zone
def get_supported_availability_zone_metadata(self):
LOG.debug(
'Provider %s no-op, get_supported_availability_zone_metadata',
self.__class__.__name__)
return {"compute_zone": "The compute availability zone to use for "
"this loadbalancer."}
def validate_availability_zone(self, availability_zone_metadata):
LOG.debug('Provider %s no-op, validate_availability_zone metadata: %s',
self.__class__.__name__, availability_zone_metadata)
availability_zone_hash = hash(frozenset(availability_zone_metadata))
self.driverconfig[availability_zone_hash] = (
availability_zone_metadata, 'validate_availability_zone')
class NoopProviderDriver(driver_base.ProviderDriver):
def __init__(self):
@ -334,3 +351,10 @@ class NoopProviderDriver(driver_base.ProviderDriver):
def validate_flavor(self, flavor_metadata):
self.driver.validate_flavor(flavor_metadata)
# Availability Zone
def get_supported_availability_zone_metadata(self):
return self.driver.get_supported_availability_zone_metadata()
def validate_availability_zone(self, availability_zone_metadata):
self.driver.validate_availability_zone(availability_zone_metadata)

View File

@ -88,6 +88,9 @@ class RootController(rest.RestController):
self._add_a_version(versions, 'v2.12', 'v2', 'SUPPORTED',
'2019-09-11T00:00:00Z', host_url)
# SOURCE_IP_PORT algorithm
self._add_a_version(versions, 'v2.13', 'v2', 'CURRENT',
self._add_a_version(versions, 'v2.13', 'v2', 'SUPPORTED',
'2019-09-13T00:00:00Z', host_url)
# Availability Zones
self._add_a_version(versions, 'v2.14', 'v2', 'CURRENT',
'2019-11-10T00:00:00Z', host_url)
return {'versions': versions}

View File

@ -16,6 +16,8 @@ from wsme import types as wtypes
from wsmeext import pecan as wsme_pecan
from octavia.api.v2.controllers import amphora
from octavia.api.v2.controllers import availability_zone_profiles
from octavia.api.v2.controllers import availability_zones
from octavia.api.v2.controllers import base
from octavia.api.v2.controllers import flavor_profiles
from octavia.api.v2.controllers import flavors
@ -47,6 +49,10 @@ class BaseV2Controller(base.BaseController):
self.providers = provider.ProviderController()
self.flavors = flavors.FlavorsController()
self.flavorprofiles = flavor_profiles.FlavorProfileController()
self.availabilityzones = (
availability_zones.AvailabilityZonesController())
self.availabilityzoneprofiles = (
availability_zone_profiles.AvailabilityZoneProfileController())
@wsme_pecan.wsexpose(wtypes.text)
def get(self):

View File

@ -0,0 +1,237 @@
# Copyright 2019 Verizon Media
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_db import exception as odb_exceptions
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import excutils
from oslo_utils import uuidutils
import pecan
from sqlalchemy.orm import exc as sa_exception
from wsme import types as wtypes
from wsmeext import pecan as wsme_pecan
from octavia.api.drivers import driver_factory
from octavia.api.drivers import utils as driver_utils
from octavia.api.v2.controllers import base
from octavia.api.v2.types import availability_zone_profile as profile_types
from octavia.common import constants
from octavia.common import exceptions
from octavia.db import api as db_api
LOG = logging.getLogger(__name__)
class AvailabilityZoneProfileController(base.BaseController):
RBAC_TYPE = constants.RBAC_AVAILABILITY_ZONE_PROFILE
def __init__(self):
super(AvailabilityZoneProfileController, self).__init__()
@wsme_pecan.wsexpose(profile_types.AvailabilityZoneProfileRootResponse,
wtypes.text, [wtypes.text], ignore_extra_args=True)
def get_one(self, id, fields=None):
"""Gets an Availability Zone Profile's detail."""
context = pecan.request.context.get('octavia_context')
self._auth_validate_action(context, context.project_id,
constants.RBAC_GET_ONE)
if id == constants.NIL_UUID:
raise exceptions.NotFound(resource='Availability Zone Profile',
id=constants.NIL_UUID)
db_availability_zone_profile = self._get_db_availability_zone_profile(
context.session, id)
result = self._convert_db_to_type(
db_availability_zone_profile,
profile_types.AvailabilityZoneProfileResponse)
if fields is not None:
result = self._filter_fields([result], fields)[0]
return profile_types.AvailabilityZoneProfileRootResponse(
availability_zone_profile=result)
@wsme_pecan.wsexpose(profile_types.AvailabilityZoneProfilesRootResponse,
[wtypes.text], ignore_extra_args=True)
def get_all(self, fields=None):
"""Lists all Availability Zone Profiles."""
pcontext = pecan.request.context
context = pcontext.get('octavia_context')
self._auth_validate_action(context, context.project_id,
constants.RBAC_GET_ALL)
db_availability_zone_profiles, links = (
self.repositories.availability_zone_profile.get_all(
context.session,
pagination_helper=pcontext.get(constants.PAGINATION_HELPER)))
result = self._convert_db_to_type(
db_availability_zone_profiles,
[profile_types.AvailabilityZoneProfileResponse])
if fields is not None:
result = self._filter_fields(result, fields)
return profile_types.AvailabilityZoneProfilesRootResponse(
availability_zone_profiles=result,
availability_zone_profile_links=links)
@wsme_pecan.wsexpose(profile_types.AvailabilityZoneProfileRootResponse,
body=profile_types.AvailabilityZoneProfileRootPOST,
status_code=201)
def post(self, availability_zone_profile_):
"""Creates an Availability Zone Profile."""
availability_zone_profile = (
availability_zone_profile_.availability_zone_profile)
context = pecan.request.context.get('octavia_context')
self._auth_validate_action(context, context.project_id,
constants.RBAC_POST)
# Do a basic JSON validation on the metadata
try:
availability_zone_data_dict = jsonutils.loads(
availability_zone_profile.availability_zone_data)
except Exception:
raise exceptions.InvalidOption(
value=availability_zone_profile.availability_zone_data,
option=constants.AVAILABILITY_ZONE_DATA)
# Validate that the provider driver supports the metadata
driver = driver_factory.get_driver(
availability_zone_profile.provider_name)
driver_utils.call_provider(
driver.name, driver.validate_availability_zone,
availability_zone_data_dict)
lock_session = db_api.get_session(autocommit=False)
try:
availability_zone_profile_dict = availability_zone_profile.to_dict(
render_unsets=True)
availability_zone_profile_dict['id'] = uuidutils.generate_uuid()
db_availability_zone_profile = (
self.repositories.availability_zone_profile.create(
lock_session, **availability_zone_profile_dict))
lock_session.commit()
except odb_exceptions.DBDuplicateEntry:
lock_session.rollback()
raise exceptions.IDAlreadyExists()
except Exception:
with excutils.save_and_reraise_exception():
lock_session.rollback()
result = self._convert_db_to_type(
db_availability_zone_profile,
profile_types.AvailabilityZoneProfileResponse)
return profile_types.AvailabilityZoneProfileRootResponse(
availability_zone_profile=result)
def _validate_update_azp(self, context, id, availability_zone_profile):
if availability_zone_profile.name is None:
raise exceptions.InvalidOption(value=None, option=constants.NAME)
if availability_zone_profile.provider_name is None:
raise exceptions.InvalidOption(
value=None, option=constants.PROVIDER_NAME)
if availability_zone_profile.availability_zone_data is None:
raise exceptions.InvalidOption(
value=None, option=constants.AVAILABILITY_ZONE_DATA)
# Don't allow changes to the availability_zone_data or provider_name if
# it is in use.
if (not isinstance(availability_zone_profile.availability_zone_data,
wtypes.UnsetType) or
not isinstance(availability_zone_profile.provider_name,
wtypes.UnsetType)):
if self.repositories.availability_zone.count(
context.session, availability_zone_profile_id=id) > 0:
raise exceptions.ObjectInUse(
object='Availability Zone Profile', id=id)
@wsme_pecan.wsexpose(profile_types.AvailabilityZoneProfileRootResponse,
wtypes.text, status_code=200,
body=profile_types.AvailabilityZoneProfileRootPUT)
def put(self, id, availability_zone_profile_):
"""Updates an Availability Zone Profile."""
availability_zone_profile = (
availability_zone_profile_.availability_zone_profile)
context = pecan.request.context.get('octavia_context')
self._auth_validate_action(context, context.project_id,
constants.RBAC_PUT)
self._validate_update_azp(context, id, availability_zone_profile)
if id == constants.NIL_UUID:
raise exceptions.NotFound(resource='Availability Zone Profile',
id=constants.NIL_UUID)
if not isinstance(availability_zone_profile.availability_zone_data,
wtypes.UnsetType):
# Do a basic JSON validation on the metadata
try:
availability_zone_data_dict = jsonutils.loads(
availability_zone_profile.availability_zone_data)
except Exception:
raise exceptions.InvalidOption(
value=availability_zone_profile.availability_zone_data,
option=constants.FLAVOR_DATA)
if isinstance(availability_zone_profile.provider_name,
wtypes.UnsetType):
db_availability_zone_profile = (
self._get_db_availability_zone_profile(
context