Skip to content

Commit

Permalink
Add vpc.v1.subnet resource (#256)
Browse files Browse the repository at this point in the history
Add `vpc.v1.subnet` resource

Add subnet methods to vpc.v1.proxy
Add acceptance tests for vpc.v1.subnet
Add vpc.v1.vpc and vpc.v1.subnet documentation

Reviewed-by: Rodion Gyrbu <[email protected]>
Reviewed-by: Anton Sidelnikov <None>
Reviewed-by: Anton Kachurin <[email protected]>
Reviewed-by: None <None>
  • Loading branch information
outcatcher authored Dec 24, 2021
1 parent 1382ee7 commit 747044f
Show file tree
Hide file tree
Showing 11 changed files with 526 additions and 17 deletions.
16 changes: 16 additions & 0 deletions doc/source/sdk/proxies/vpc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,19 @@ VPC Route Operations
.. autoclass:: otcextensions.sdk.vpc.v1._proxy.Proxy
:noindex:
:members: routes, get_route, add_route, delete_route

VPC Operations
^^^^^^^^^^^^^^

.. autoclass:: otcextensions.sdk.vpc.v1._proxy.Proxy
:noindex:
:members: vpcs, create_vpc, delete_vpc, get_vpc,
find_vpc, update_vpc

VPC Subnet Operations
^^^^^^^^^^^^^^^^^^^^^

.. autoclass:: otcextensions.sdk.vpc.v1._proxy.Proxy
:noindex:
:members: subnets, create_subnet, delete_subnet, get_subnet,
find_subnet, update_subnet
2 changes: 2 additions & 0 deletions doc/source/sdk/resources/vpc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ VPC Resources
.. toctree::
:maxdepth: 1

v1/vpc
v1/subnet
v2/peering
v2/route
13 changes: 13 additions & 0 deletions doc/source/sdk/resources/vpc/v1/subnet.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
otcextensions.sdk.vpc.v1.subnet
================================

.. automodule:: otcextensions.sdk.vpc.v1.subnet

The VPC Subnet Class
--------------------

The ``Subnet`` class inherits from
:class:`~otcextensions.sdk.sdk_resource.Resource`.

.. autoclass:: otcextensions.sdk.vpc.v1.subnet.Subnet
:members:
13 changes: 13 additions & 0 deletions doc/source/sdk/resources/vpc/v1/vpc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
otcextensions.sdk.vpc.v1.vpc
================================

.. automodule:: otcextensions.sdk.vpc.v1.vpc

The VPC Class
-------------------

The ``Vpc`` class inherits from
:class:`~otcextensions.sdk.sdk_resource.Resource`.

.. autoclass:: otcextensions.sdk.vpc.v1.vpc.Vpc
:members:
138 changes: 131 additions & 7 deletions otcextensions/sdk/vpc/v1/_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
# 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 openstack import exceptions
from openstack import proxy

from otcextensions.sdk.vpc.v1 import peering as _peering
from otcextensions.sdk.vpc.v1 import route as _route
from otcextensions.sdk.vpc.v1 import subnet as _subnet
from otcextensions.sdk.vpc.v1 import vpc as _vpc


Expand Down Expand Up @@ -187,15 +189,17 @@ def vpcs(self, **query):
return self._list(_vpc.Vpc, **query)

def create_vpc(self, **attrs):
""" Create a new vpc from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~otcextensions.sdk.vpc.v1.vpc.Vpc`
"""Create a new vpc from attributes
:param dict attrs: Keyword arguments which will be used to create a
:class:`~otcextensions.sdk.vpc.v1.vpc.Vpc`
"""
return self._create(_vpc.Vpc, **attrs,
project_id=self.get_project_id())

def delete_vpc(self, vpc, ignore_missing=True):
""" Delete a vpc
"""Delete a vpc
:param vpc: vpc id or an instance of
:class:`~otcextensions.sdk.vpc.v1.vpc.Vpc`
Expand All @@ -212,9 +216,10 @@ def delete_vpc(self, vpc, ignore_missing=True):
ignore_missing=ignore_missing)

def get_vpc(self, vpc):
""" Get a vpc by id
"""Get a vpc by id
:param vpc: vpc id or an instance of
:class:`~otcextensions.sdk.vpc.v1.vpc.Vpc`
:class:`~otcextensions.sdk.vpc.v1.vpc.Vpc`
:returns: One :class:`~otcextensions.sdk.vpc.v1.vpc.Vpc`
"""
Expand All @@ -224,6 +229,7 @@ def find_vpc(self, name_or_id, ignore_missing=False):
"""Find a single vpc
:param name_or_id: The name or ID of a vpc
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised
when the vpc does not exist.
Expand All @@ -238,7 +244,7 @@ def find_vpc(self, name_or_id, ignore_missing=False):
project_id=self.get_project_id())

def update_vpc(self, vpc, **attrs):
""" Update vpc
"""Update vpc
:param vpc: vpc id or an instance of
:class:`~otcextensions.sdk.vpc.v1.vpc.Vpc`
Expand All @@ -249,6 +255,124 @@ def update_vpc(self, vpc, **attrs):
attrs['project_id'] = self.get_project_id()
return self._update(_vpc.Vpc, vpc, **attrs)

# ========== Subnet ==========
def subnets(self, **query):
"""Return a generator of subnets
:param dict query: Optional query parameters to be sent to limit
the resources being returned.
:returns: A generator of subnet objects
:rtype: :class:`~otcextensions.sdk.vpc.v1.subnet.Subnet`
"""
query['project_id'] = self.get_project_id()
return self._list(_subnet.Subnet, **query)

def create_subnet(self, **attrs):
"""Create a new subnet from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~otcextensions.sdk.vpc.v1.subnet.Subnet`
"""
attrs['project_id'] = self.get_project_id()
return self._create(_subnet.Subnet, **attrs)

def get_subnet(self, subnet):
"""Get a subnet by id
:param subnet: subnet id or an instance of
:class:`~otcextensions.sdk.vpc.v1.subnet.Subnet`
:returns: One :class:`~otcextensions.sdk.vpc.v1.subnet.Subnet`
"""
return self._get(_subnet.Subnet, subnet,
project_id=self.get_project_id())

def find_subnet(self, name_or_id, ignore_missing=False):
"""Find a single subnet
:param name_or_id: The name or ID of a subnet
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised
when the subnet does not exist.
When set to ``True``, no exception will be set when attempting
to delete a nonexistent peering.
:returns: One :class:`~otcextensions.sdk.vpc.v1.subnet.Subnet`
"""
return self._find(
_subnet.Subnet, name_or_id,
ignore_missing=ignore_missing,
project_id=self.get_project_id())

def update_subnet(self, subnet, **attrs):
"""Update subnet
:param subnet: subnet id or an instance of
:class:`~otcextensions.sdk.vpc.v1.subnet.Subnet`
:param dict attrs: The attributes to update on the subnet
represented by ``subnet``.
"""
attrs['project_id'] = self.get_project_id()

rs = self._get_resource(_subnet.Subnet, subnet)
if rs.vpc_id is None and 'vpc_id' not in attrs:
raise AttributeError('Updating subnet requires VPC ID')
vpc_id = attrs.pop('vpc_id', rs.vpc_id) # vpc_id can't be changed

attrs.pop('base_path', None)
base_path = _subnet.vpc_subnet_base_path(vpc_id)

return self._update(_subnet.Subnet,
subnet,
base_path=base_path,
**attrs)

def _delete(self, resource_type, value, ignore_missing=True, **attrs):
"""Override of ``_delete`` with support of ``base_path``"""
base_path = attrs.pop('base_path', None)

res = self._get_resource(resource_type, value, **attrs)

try:
rv = res.delete(self, base_path=base_path)
except exceptions.ResourceNotFound:
if ignore_missing:
return None
raise

return rv

def delete_subnet(self, subnet, vpc_id=None, ignore_missing=True):
"""Delete a subnet
:param subnet: subnet id or an instance of
:class:`~otcextensions.sdk.vpc.v1.subnet.Subnet`
:param vpc_id: VPC id. By default, taken from ``subnet``, if provided.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the subnet route does not exist.
When set to ``True``, no exception will be set when attempting to
delete a nonexistent route.
:returns: none
"""
sn_res = self._get_resource(_subnet.Subnet, subnet)
sn_res.vpc_id = vpc_id or sn_res.vpc_id
if sn_res.vpc_id is None:
raise AttributeError('Deleting subnet requires VPC ID')

base_path = _subnet.vpc_subnet_base_path(sn_res.vpc_id)

return self._delete(_subnet.Subnet, subnet,
ignore_missing=ignore_missing,
base_path=base_path)

# ========== Project cleanup ==========
def _get_cleanup_dependencies(self):
return {
Expand Down
66 changes: 66 additions & 0 deletions otcextensions/sdk/vpc/v1/subnet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# 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 openstack import resource


class ExtraDHCPOpt(resource.Resource):
#: Specifies the NTP server address configured for the subnet.
opt_value = resource.Body('opt_value')
#: Specifies the NTP server address name configured for the subnet.
#: Currently, the value can only be set to ntp.
opt_name = resource.Body('opt_name', default='ntp')


class Subnet(resource.Resource):
resource_key = 'subnet'
resources_key = 'subnets'
base_path = '/v1/%(project_id)s/subnets'

# capabilities
allow_create = True
allow_fetch = True
allow_commit = True
allow_delete = True
allow_list = True

# Properties
project_id = resource.URI('project_id')
description = resource.Body('description')
#: Specifies the subnet CIDR block.
cidr = resource.Body('cidr')
#: Specifies the gateway of the subnet.
gateway_ip = resource.Body('gateway_ip')
#: Specifies whether DHCP is enabled for the subnet.
dhcp_enable = resource.Body('dhcp_enable')
#: Specifies the IP address of DNS server 1 on the subnet.
primary_dns = resource.Body('primary_dns')
#: Specifies the IP address of DNS server 2 on the subnet.
secondary_dns = resource.Body('secondary_dns')
#: Specifies the DNS server address list of a subnet.
#: This field is required if use more than two DNS servers.
dns_list = resource.Body('dnsList', type=list, list_type=str)
#: Specifies the AZ to which the subnet belongs
availability_zone = resource.Body('availability_zone')
#: Specifies the ID of the VPC to which the subnet belongs.
vpc_id = resource.Body('vpc_id')
#: Specifies the NTP server address configured for the subnet.
extra_dhcp_opts = resource.Body('extra_dhcp_opts', type=list,
list_type=ExtraDHCPOpt)

status = resource.Body('status')
neutron_network_id = resource.Body('neutron_network_id')
neutron_subnet_id = resource.Body('neutron_subnet_id')


def vpc_subnet_base_path(vpc_id):
"""Special case of subnet resource path"""
return f'/v1/%(project_id)s/vpcs/{vpc_id}/subnets'
Empty file.
Loading

0 comments on commit 747044f

Please sign in to comment.