Add DNS support

Add support for the DNS service. There are still some unimplemented 
resources (tld, pools, limits, tsigkey, blacklist, quota, 
service_status). They would be added in the follow-up, since this change 
is already very big for a review.

Change-Id: I4acab7c4cace63b4ea7d719854e159bd41d49039
This commit is contained in:
Artem Goncharov 2019-03-02 09:09:56 +01:00
parent 9cd0ef2ac5
commit 8d14cbaa88
36 changed files with 1907 additions and 0 deletions

View File

@ -0,0 +1,18 @@
Using OpenStack DNS
===================
Before working with the DNS service, you'll need to create a connection
to your OpenStack cloud by following the :doc:`connect` user guide. This will
provide you with the ``conn`` variable used in the examples below.
.. TODO(gtema): Implement this guide
List Zones
----------
.. literalinclude:: ../examples/dns/list.py
:pyobject: list_zones
Full example: `dns resource list`_
.. _dns resource list: http://git.openstack.org/cgit/openstack/openstacksdk/tree/examples/dns/list.py

View File

@ -39,6 +39,7 @@ approach, this is where you'll want to begin.
Clustering <guides/clustering>
Compute <guides/compute>
Database <guides/database>
DNS <guides/dns>
Identity <guides/identity>
Image <guides/image>
Key Manager <guides/key_manager>
@ -98,6 +99,7 @@ control which services can be used.
Clustering <proxies/clustering>
Compute <proxies/compute>
Database <proxies/database>
DNS <proxies/dns>
Identity v2 <proxies/identity_v2>
Identity v3 <proxies/identity_v3>
Image v1 <proxies/image_v1>
@ -130,6 +132,7 @@ The following services have exposed *Resource* classes.
Clustering <resources/clustering/index>
Compute <resources/compute/index>
Database <resources/database/index>
DNS <resources/dns/index>
Identity <resources/identity/index>
Image <resources/image/index>
Key Management <resources/key_manager/index>

View File

@ -0,0 +1,81 @@
DNS API
=======
For details on how to use dns, see :doc:`/user/guides/dns`
.. automodule:: openstack.dns.v2._proxy
The DNS Class
-------------
The dns high-level interface is available through the ``dns``
member of a :class:`~openstack.connection.Connection` object. The
``dns`` member will only be added if the service is detected.
DNS Zone Operations
^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.dns.v2._proxy.Proxy
.. automethod:: openstack.dns.v2._proxy.Proxy.create_zone
.. automethod:: openstack.dns.v2._proxy.Proxy.delete_zone
.. automethod:: openstack.dns.v2._proxy.Proxy.get_zone
.. automethod:: openstack.dns.v2._proxy.Proxy.find_zone
.. automethod:: openstack.dns.v2._proxy.Proxy.zones
.. automethod:: openstack.dns.v2._proxy.Proxy.abandon_zone
.. automethod:: openstack.dns.v2._proxy.Proxy.xfr_zone
Recordset Operations
^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.dns.v2._proxy.Proxy
.. automethod:: openstack.dns.v2._proxy.Proxy.create_recordset
.. automethod:: openstack.dns.v2._proxy.Proxy.update_recordset
.. automethod:: openstack.dns.v2._proxy.Proxy.get_recordset
.. automethod:: openstack.dns.v2._proxy.Proxy.delete_recordset
.. automethod:: openstack.dns.v2._proxy.Proxy.recordsets
Zone Import Operations
^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.dns.v2._proxy.Proxy
.. automethod:: openstack.dns.v2._proxy.Proxy.zone_imports
.. automethod:: openstack.dns.v2._proxy.Proxy.create_zone_import
.. automethod:: openstack.dns.v2._proxy.Proxy.get_zone_import
.. automethod:: openstack.dns.v2._proxy.Proxy.delete_zone_import
Zone Export Operations
^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.dns.v2._proxy.Proxy
.. automethod:: openstack.dns.v2._proxy.Proxy.zone_exports
.. automethod:: openstack.dns.v2._proxy.Proxy.create_zone_export
.. automethod:: openstack.dns.v2._proxy.Proxy.get_zone_export
.. automethod:: openstack.dns.v2._proxy.Proxy.get_zone_export_text
.. automethod:: openstack.dns.v2._proxy.Proxy.delete_zone_export
FloatingIP Operations
^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.dns.v2._proxy.Proxy
.. automethod:: openstack.dns.v2._proxy.Proxy.floating_ips
.. automethod:: openstack.dns.v2._proxy.Proxy.get_floating_ip
.. automethod:: openstack.dns.v2._proxy.Proxy.update_floating_ip
Zone Transfer Operations
^^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.dns.v2._proxy.Proxy
.. automethod:: openstack.dns.v2._proxy.Proxy.zone_transfer_requests
.. automethod:: openstack.dns.v2._proxy.Proxy.get_zone_transfer_request
.. automethod:: openstack.dns.v2._proxy.Proxy.create_zone_transfer_request
.. automethod:: openstack.dns.v2._proxy.Proxy.update_zone_transfer_request
.. automethod:: openstack.dns.v2._proxy.Proxy.delete_zone_transfer_request
.. automethod:: openstack.dns.v2._proxy.Proxy.zone_transfer_accepts
.. automethod:: openstack.dns.v2._proxy.Proxy.get_zone_transfer_accept
.. automethod:: openstack.dns.v2._proxy.Proxy.create_zone_transfer_accept

View File

@ -0,0 +1,12 @@
DNS Resources
=============
.. toctree::
:maxdepth: 1
v2/zone
v2/zone_transfer
v2/zone_export
v2/zone_import
v2/floating_ip
v2/recordset

View File

@ -0,0 +1,12 @@
openstack.dns.v2.floating_ip
============================
.. automodule:: openstack.dns.v2.floating_ip
The FloatingIP Class
--------------------
The ``DNS`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.dns.v2.floating_ip.FloatingIP
:members:

View File

@ -0,0 +1,12 @@
openstack.dns.v2.recordset
==========================
.. automodule:: openstack.dns.v2.recordset
The Recordset Class
-------------------
The ``DNS`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.dns.v2.recordset.Recordset
:members:

View File

@ -0,0 +1,12 @@
openstack.dns.v2.zone
==============================
.. automodule:: openstack.dns.v2.zone
The Zone Class
--------------
The ``DNS`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.dns.v2.zone.Zone
:members:

View File

@ -0,0 +1,12 @@
openstack.dns.v2.zone_export
============================
.. automodule:: openstack.dns.v2.zone_export
The ZoneExport Class
--------------------
The ``DNS`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.dns.v2.zone_export.ZoneExport
:members:

View File

@ -0,0 +1,12 @@
openstack.dns.v2.zone_import
============================
.. automodule:: openstack.dns.v2.zone_import
The ZoneImport Class
--------------------
The ``DNS`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.dns.v2.zone_import.ZoneImport
:members:

View File

@ -0,0 +1,20 @@
openstack.dns.v2.zone_transfer
==============================
.. automodule:: openstack.dns.v2.zone_transfer
The ZoneTransferRequest Class
-----------------------------
The ``DNS`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.dns.v2.zone_transfer.ZoneTransferRequest
:members:
The ZoneTransferAccept Class
----------------------------
The ``DNS`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.dns.v2.zone_transfer.ZoneTransferAccept
:members:

0
examples/dns/__init__.py Normal file
View File

24
examples/dns/list.py Normal file
View File

@ -0,0 +1,24 @@
# 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.
"""
List resources from the DNS service.
For a full guide see TODO(gtema):link to docs on developer.openstack.org
"""
def list_zones(conn):
print("List Zones:")
for zone in conn.dns.zones():
print(zone)

View File

View File

@ -0,0 +1,22 @@
# 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.dns.v2 import _proxy
from openstack import service_description
class DnsService(service_description.ServiceDescription):
"""The DNS service."""
supported_versions = {
'2': _proxy.Proxy,
}

View File

494
openstack/dns/v2/_proxy.py Normal file
View File

@ -0,0 +1,494 @@
# 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 proxy
from openstack.dns.v2 import recordset as _rs
from openstack.dns.v2 import zone as _zone
from openstack.dns.v2 import zone_import as _zone_import
from openstack.dns.v2 import zone_export as _zone_export
from openstack.dns.v2 import zone_transfer as _zone_transfer
from openstack.dns.v2 import floating_ip as _fip
class Proxy(proxy.Proxy):
# ======== Zones ========
def zones(self, **query):
"""Retrieve a generator of zones
:param dict query: Optional query parameters to be sent to limit the
resources being returned.
* `name`: Zone Name field.
* `type`: Zone Type field.
* `email`: Zone email field.
* `status`: Status of the zone.
* `ttl`: TTL field filter.abs
* `description`: Zone description field filter.
:returns: A generator of zone
:class:`~openstack.dns.v2.zone.Zone` instances.
"""
return self._list(_zone.Zone, **query)
def create_zone(self, **attrs):
"""Create a new zone from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.zone.Zone`,
comprised of the properties on the Zone class.
:returns: The results of zone creation.
:rtype: :class:`~openstack.dns.v2.zone.Zone`
"""
return self._create(_zone.Zone, prepend_key=False, **attrs)
def get_zone(self, zone):
"""Get a zone
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:returns: Zone instance.
:rtype: :class:`~openstack.dns.v2.zone.Zone`
"""
return self._get(_zone.Zone, zone)
def delete_zone(self, zone, ignore_missing=True):
"""Delete a zone
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist.
When set to ``True``, no exception will be set when attempting to
delete a nonexistent zone.
:returns: Zone been deleted
:rtype: :class:`~openstack.dns.v2.zone.Zone`
"""
return self._delete(_zone.Zone, zone, ignore_missing=ignore_missing)
def update_zone(self, zone, **attrs):
"""Update zone attributes
:param zone: The id or an instance of
:class:`~openstack.dns.v2.zone.Zone`.
:param dict attrs: attributes for update on
:class:`~openstack.dns.v2.zone.Zone`.
:rtype: :class:`~openstack.dns.v2.zone.Zone`
"""
return self._update(_zone.Zone, zone, **attrs)
def find_zone(self, name_or_id, ignore_missing=True):
"""Find a single zone
:param name_or_id: The name or ID of a zone
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised
when the zone does not exist.
When set to ``True``, no exception will be set when attempting
to delete a nonexistent zone.
:returns: :class:`~openstack.dns.v2.zone.Zone`
"""
return self._find(_zone.Zone, name_or_id,
ignore_missing=ignore_missing)
def abandon_zone(self, zone, **attrs):
"""Abandon Zone
:param zone: The value can be the ID of a zone to be abandoned
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:returns: None
"""
zone = self._get_resource(_zone.Zone, zone)
return zone.abandon(self)
def xfr_zone(self, zone, **attrs):
"""Trigger update of secondary Zone
:param zone: The value can be the ID of a zone to be abandoned
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:returns: None
"""
zone = self._get_resource(_zone.Zone, zone)
return zone.xfr(self)
# ======== Recordsets ========
def recordsets(self, zone=None, **query):
"""Retrieve a generator of recordsets
:param zone: The optional value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance. If it is not
given all recordsets for all zones of the tenant would be
retrieved
:param dict query: Optional query parameters to be sent to limit the
resources being returned.
* `name`: Recordset Name field.
* `type`: Type field.
* `status`: Status of the recordset.
* `ttl`: TTL field filter.
* `description`: Recordset description field filter.
:returns: A generator of zone
(:class:`~openstack.dns.v2.recordset.Recordset`) instances
"""
base_path = None
if not zone:
base_path = '/recordsets'
else:
zone = self._get_resource(_zone.Zone, zone)
query.update({'zone_id': zone.id})
return self._list(_rs.Recordset, base_path=base_path, **query)
def create_recordset(self, zone, **attrs):
"""Create a new recordset in the zone
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.recordset.Recordset`,
comprised of the properties on the Recordset class.
:returns: The results of zone creation
:rtype: :class:`~openstack.dns.v2.recordset.Recordset`
"""
zone = self._get_resource(_zone.Zone, zone)
attrs.update({'zone_id': zone.id})
return self._create(_rs.Recordset, prepend_key=False, **attrs)
def update_recordset(self, recordset, **attrs):
"""Update Recordset attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.recordset.Recordset`,
comprised of the properties on the Recordset class.
:returns: The results of zone creation
:rtype: :class:`~openstack.dns.v2.recordset.Recordset`
"""
return self._update(_rs.Recordset, recordset, **attrs)
def get_recordset(self, recordset, zone):
"""Get a recordset
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:param recordset: The value can be the ID of a recordset
or a :class:`~openstack.dns.v2.recordset.Recordset` instance.
:returns: Recordset instance
:rtype: :class:`~openstack.dns.v2.recordset.Recordset`
"""
zone = self._get_resource(_zone.Zone, zone)
return self._get(_rs.Recordset, recordset, zone_id=zone.id)
def delete_recordset(self, recordset, zone=None, ignore_missing=True):
"""Delete a zone
:param recordset: The value can be the ID of a recordset
or a :class:`~openstack.dns.v2.recordset.Recordset`
instance.
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist. When set to ``True``, no exception will
be set when attempting to delete a nonexistent zone.
:returns: Recordset instance been deleted
:rtype: :class:`~openstack.dns.v2.recordset.Recordset`
"""
if zone:
zone = self._get_resource(_zone.Zone, zone)
recordset = self._get(
_rs.Recordset, recordset, zone_id=zone.id)
return self._delete(_rs.Recordset, recordset,
ignore_missing=ignore_missing)
# ======== Zone Imports ========
def zone_imports(self, **query):
"""Retrieve a generator of zone imports
:param dict query: Optional query parameters to be sent to limit the
resources being returned.
* `zone_id`: Zone I field.
* `message`: Message field.
* `status`: Status of the zone import record.
:returns: A generator of zone
:class:`~openstack.dns.v2.zone_import.ZoneImport` instances.
"""
return self._list(_zone_import.ZoneImport, **query)
def create_zone_import(self, **attrs):
"""Create a new zone import from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.zone_import.ZoneImport`,
comprised of the properties on the ZoneImport class.
:returns: The results of zone creation.
:rtype: :class:`~openstack.dns.v2.zone_import.ZoneImport`
"""
return self._create(_zone_import.ZoneImport, prepend_key=False,
**attrs)
def get_zone_import(self, zone_import):
"""Get a zone import record
:param zone: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_import.ZoneImport` instance.
:returns: ZoneImport instance.
:rtype: :class:`~openstack.dns.v2.zone_import.ZoneImport`
"""
return self._get(_zone_import.ZoneImport, zone_import)
def delete_zone_import(self, zone_import, ignore_missing=True):
"""Delete a zone import
:param zone_import: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_import.ZoneImport` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist.
When set to ``True``, no exception will be set when attempting to
delete a nonexistent zone.
:returns: None
"""
return self._delete(_zone_import.ZoneImport, zone_import,
ignore_missing=ignore_missing)
# ======== Zone Exports ========
def zone_exports(self, **query):
"""Retrieve a generator of zone exports
:param dict query: Optional query parameters to be sent to limit the
resources being returned.
* `zone_id`: Zone I field.
* `message`: Message field.
* `status`: Status of the zone import record.
:returns: A generator of zone
:class:`~openstack.dns.v2.zone_export.ZoneExport` instances.
"""
return self._list(_zone_export.ZoneExport, **query)
def create_zone_export(self, zone, **attrs):
"""Create a new zone export from attributes
:param zone: The value can be the ID of a zone to be exported
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.zone_export.ZoneExport`,
comprised of the properties on the ZoneExport class.
:returns: The results of zone creation.
:rtype: :class:`~openstack.dns.v2.zone_export.ZoneExport`
"""
zone = self._get_resource(_zone.Zone, zone)
return self._create(_zone_export.ZoneExport,
base_path='/zones/%(zone_id)s/tasks/export',
prepend_key=False,
zone_id=zone.id,
**attrs)
def get_zone_export(self, zone_export):
"""Get a zone export record
:param zone: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:returns: ZoneExport instance.
:rtype: :class:`~openstack.dns.v2.zone_export.ZoneExport`
"""
return self._get(_zone_export.ZoneExport, zone_export)
def get_zone_export_text(self, zone_export):
"""Get a zone export record as text
:param zone: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:returns: ZoneExport instance.
:rtype: :class:`~openstack.dns.v2.zone_export.ZoneExport`
"""
return self._get(_zone_export.ZoneExport, zone_export,
base_path='/zones/tasks/export/%(id)s/export')
def delete_zone_export(self, zone_export, ignore_missing=True):
"""Delete a zone export
:param zone_export: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist.
When set to ``True``, no exception will be set when attempting to
delete a nonexistent zone.
:returns: None
"""
return self._delete(_zone_export.ZoneExport, zone_export,
ignore_missing=ignore_missing)
# ======== FloatingIPs ========
def floating_ips(self, **query):
"""Retrieve a generator of recordsets
:param dict query: Optional query parameters to be sent to limit the
resources being returned.
* `name`: Recordset Name field.
* `type`: Type field.
* `status`: Status of the recordset.
* `ttl`: TTL field filter.
* `description`: Recordset description field filter.
:returns: A generator of floatingips
(:class:`~openstack.dns.v2.floating_ip.FloatingIP`) instances
"""
return self._list(_fip.FloatingIP, **query)
def get_floating_ip(self, floating_ip):
"""Get a Floating IP
:param floating_ip: The value can be the ID of a floating ip
or a :class:`~openstack.dns.v2.floating_ip.FloatingIP` instance.
The ID is in format "region_name:floatingip_id"
:returns: FloatingIP instance.
:rtype: :class:`~openstack.dns.v2.floating_ip.FloatingIP`
"""
return self._get(_fip.FloatingIP, floating_ip)
def update_floating_ip(self, floating_ip, **attrs):
"""Update floating ip attributes
:param floating_ip: The id or an instance of
:class:`~openstack.dns.v2.fip.FloatingIP`.
:param dict attrs: attributes for update on
:class:`~openstack.dns.v2.fip.FloatingIP`.
:rtype: :class:`~openstack.dns.v2.fip.FloatingIP`
"""
return self._update(_fip.FloatingIP, floating_ip, **attrs)
# ======== Zone Transfer ========
def zone_transfer_requests(self, **query):
"""Retrieve a generator of zone transfer requests
:param dict query: Optional query parameters to be sent to limit the
resources being returned.
* `status`: Status of the recordset.
:returns: A generator of transfer requests
(:class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`)
instances
"""
return self._list(_zone_transfer.ZoneTransferRequest, **query)
def get_zone_transfer_request(self, request):
"""Get a ZoneTransfer Request info
:param request: The value can be the ID of a transfer request
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
instance.
:returns: Zone transfer request instance.
:rtype: :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
"""
return self._get(_zone_transfer.ZoneTransferRequest, request)
def create_zone_transfer_request(self, zone, **attrs):
"""Create a new ZoneTransfer Request from attributes
:param zone: The value can be the ID of a zone to be transferred
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`,
comprised of the properties on the ZoneTransferRequest class.
:returns: The results of zone transfer request creation.
:rtype: :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
"""
zone = self._get_resource(_zone.Zone, zone)
return self._create(
_zone_transfer.ZoneTransferRequest,
base_path='/zones/%(zone_id)s/tasks/transfer_requests',
prepend_key=False,
zone_id=zone.id,
**attrs)
def update_zone_transfer_request(self, request, **attrs):
"""Update ZoneTransfer Request attributes
:param floating_ip: The id or an instance of
:class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`.
:param dict attrs: attributes for update on
:class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`.
:rtype: :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
"""
return self._update(_zone_transfer.ZoneTransferRequest,
request, **attrs)
def delete_zone_transfer_request(self, request, ignore_missing=True):
"""Delete a ZoneTransfer Request
:param request: The value can be the ID of a zone transfer request
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist.
When set to ``True``, no exception will be set when attempting to
delete a nonexistent zone.
:returns: None
"""
return self._delete(_zone_transfer.ZoneTransferRequest, request,
ignore_missing=ignore_missing)
def zone_transfer_accepts(self, **query):
"""Retrieve a generator of zone transfer accepts
:param dict query: Optional query parameters to be sent to limit the
resources being returned.
* `status`: Status of the recordset.
:returns: A generator of transfer accepts
(:class:`~openstack.dns.v2.zone_transfer.ZoneTransferAccept`)
instances
"""
return self._list(_zone_transfer.ZoneTransferAccept, **query)
def get_zone_transfer_accept(self, accept):
"""Get a ZoneTransfer Accept info
:param request: The value can be the ID of a transfer accept
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferAccept`
instance.
:returns: Zone transfer request instance.
:rtype: :class:`~openstack.dns.v2.zone_transfer.ZoneTransferAccept`
"""
return self._get(_zone_transfer.ZoneTransferAccept, accept)
def create_zone_transfer_accept(self, **attrs):
"""Create a new ZoneTransfer Accept from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferAccept`,
comprised of the properties on the ZoneTransferAccept class.
:returns: The results of zone transfer request creation.
:rtype: :class:`~openstack.dns.v2.zone_transfer.ZoneTransferAccept`
"""
return self._create(_zone_transfer.ZoneTransferAccept, **attrs)

View File

@ -0,0 +1,40 @@
# 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 exceptions
from openstack import resource
class FloatingIP(resource.Resource):
"""DNS Floating IP Resource"""
resource_key = ''
resources_key = 'floatingips'
base_path = '/reverse/floatingips'
# capabilities
allow_fetch = True
allow_commit = True
allow_list = True
commit_method = "PATCH"
#: Properties
#: current action in progress on the resource
action = resource.Body('action')
#: The floatingip address for this PTR record
address = resource.Body('address')
#: Description for this PTR record
description = resource.Body('description')
#: Domain name for this PTR record
ptrdname = resource.Body('ptrdname')
#: status of the resource
status = resource.Body('status')
#: Time to live for this PTR record
ttl = resource.Body('ttl', type=int)

View File

@ -0,0 +1,64 @@
# 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 exceptions
from openstack import resource
class Recordset(resource.Resource):
"""DNS Recordset Resource"""
resource_key = 'recordset'
resources_key = 'recordsets'
base_path = '/zones/%(zone_id)s/recordsets'
# capabilities
allow_create = True
allow_fetch = True
allow_commit = True
allow_delete = True
allow_list = True
_query_mapping = resource.QueryParameters(
'name', 'type', 'ttl', 'data', 'status', 'description',
'limit', 'marker')
#: Properties
#: current action in progress on the resource
action = resource.Body('action')
#: Timestamp when the zone was created
created_at = resource.Body('create_at')
#: Recordset description
description = resource.Body('description')
#: Links contains a `self` pertaining to this zone or a `next` pertaining
#: to next page
links = resource.Body('links', type=dict)
#: DNS Name of the recordset
name = resource.Body('name')
#: ID of the project which the recordset belongs to
project_id = resource.Body('project_id')
#: DNS record value list
records = resource.Body('records', type=list)
#: Recordset status
#: Valid values include: `PENDING_CREATE`, `ACTIVE`,`PENDING_DELETE`,
#: `ERROR`
status = resource.Body('status')
#: Time to live, default 300, available value 300-2147483647 (seconds)
ttl = resource.Body('ttl', type=int)
#: DNS type of the recordset
#: Valid values include `A`, `AAAA`, `MX`, `CNAME`, `TXT`, `NS`,
#: `SSHFP`, `SPF`, `SRV`, `PTR`
type = resource.Body('type')
#: Timestamp when the zone was last updated
updated_at = resource.Body('updated_at')
#: The id of the Zone which this recordset belongs to
zone_id = resource.URI('zone_id')
#: The name of the Zone which this recordset belongs to
zone_name = resource.Body('zone_name')

96
openstack/dns/v2/zone.py Normal file
View File

@ -0,0 +1,96 @@
# 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 exceptions
from openstack import resource
from openstack import utils
class Zone(resource.Resource):
"""DNS ZONE Resource"""
resources_key = 'zones'
base_path = '/zones'
# capabilities
allow_create = True
allow_fetch = True
allow_commit = True
allow_delete = True
allow_list = True
commit_method = "PATCH"
_query_mapping = resource.QueryParameters(
'name', 'type', 'email', 'status', 'description', 'ttl',
'limit', 'marker'
)
#: Properties
#: current action in progress on the resource
action = resource.Body('action')
#: Attributes
#: Key:Value pairs of information about this zone, and the pool the user
#: would like to place the zone in. This information can be used by the
#: scheduler to place zones on the correct pool.
attributes = resource.Body('attributes', type=dict)
#: Timestamp when the zone was created
created_at = resource.Body('created_at')
#: Zone description
#: *Type: str*
description = resource.Body('description')
#: The administrator email of this zone
#: *Type: str*
email = resource.Body('email')
#: Links contains a `self` pertaining to this zone or a `next` pertaining
#: to next page
links = resource.Body('links', type=dict)
#: The master list for slaver server to fetch DNS
masters = resource.Body('masters', type=list)
#: Zone name
name = resource.Body('name')
#: The pool which manages the zone, assigned by system
pool_id = resource.Body('pool_id')
#: The project id which the zone belongs to
project_id = resource.Body('project_id')
#: Serial number in the SOA record set in the zone,
#: which identifies the change on the primary DNS server
#: *Type: int*
serial = resource.Body('serial', type=int)
#: Zone status
#: Valid values include `PENDING_CREATE`, `ACTIVE`,
#: `PENDING_DELETE`, `ERROR`
status = resource.Body('status')
#: SOA TTL time, unit is seconds, default 300, TTL range 300-2147483647
#: *Type: int*
ttl = resource.Body('ttl', type=int)
#: Zone type,
#: Valid values include `PRIMARY`, `SECONDARY`
#: *Type: str*
type = resource.Body('type')
#: Timestamp when the zone was last updated
updated_at = resource.Body('updated_at')
def _action(self, session, action, body):
"""Preform actions given the message body.
"""
url = utils.urljoin(self.base_path, self.id, 'tasks', action)
response = session.post(
url,
json=body)
exceptions.raise_from_response(response)
return response
def abandon(self, session):
self._action(session, 'abandon', None)
def xfr(self, session):
self._action(session, 'xfr', None)

View File

@ -0,0 +1,86 @@
# 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 exceptions
from openstack import resource
class ZoneExport(resource.Resource):
"""DNS Zone Exports Resource"""
resource_key = ''
resources_key = 'exports'
base_path = '/zones/tasks/export'
# capabilities
allow_create = True
allow_fetch = True
allow_delete = True
allow_list = True
_query_mapping = resource.QueryParameters(
'zone_id', 'message', 'status'
)
#: Properties
#: Timestamp when the zone was created
created_at = resource.Body('created_at')
#: Links contains a `self` pertaining to this zone or a `next` pertaining
#: to next page
links = resource.Body('links', type=dict)
#: Message
message = resource.Body('message')
#: Returns the total_count of resources matching this filter
metadata = resource.Body('metadata', type=list)
#: The project id which the zone belongs to
project_id = resource.Body('project_id')
#: Current status of the zone export
status = resource.Body('status')
#: Timestamp when the zone was last updated
updated_at = resource.Body('updated_at')
#: Version of the resource
version = resource.Body('version', type=int)
#: ID for the zone that was created by this export
zone_id = resource.Body('zone_id')
def create(self, session, prepend_key=True, base_path=None):
"""Create a remote resource based on this instance.
:param session: The session to use for making this request.
:type session: :class:`~keystoneauth1.adapter.Adapter`
:param prepend_key: A boolean indicating whether the resource_key
should be prepended in a resource creation
request. Default to True.
:param str base_path: Base part of the URI for creating resources, if
different from
:data:`~openstack.resource.Resource.base_path`.
:return: This :class:`Resource` instance.
:raises: :exc:`~openstack.exceptions.MethodNotSupported` if
:data:`Resource.allow_create` is not set to ``True``.
"""
if not self.allow_create:
raise exceptions.MethodNotSupported(self, "create")
session = self._get_session(session)
microversion = self._get_microversion_for(session, 'create')
# Create ZoneExport requires empty body
# skip _prepare_request completely, since we need just empty body
request = resource._Request(
self.base_path,
None,
None
)
response = session.post(request.url,
json=request.body, headers=request.headers,
microversion=microversion)
self.microversion = microversion
self._translate_response(response)
return self

View File

@ -0,0 +1,86 @@
# 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 exceptions
from openstack import resource
class ZoneImport(resource.Resource):
"""DNS Zone Import Resource"""
resource_key = ''
resources_key = 'imports'
base_path = '/zones/tasks/import'
# capabilities
allow_create = True
allow_fetch = True
allow_delete = True
allow_list = True
_query_mapping = resource.QueryParameters(
'zone_id', 'message', 'status'
)
#: Properties
#: Timestamp when the zone was created
created_at = resource.Body('created_at')
#: Links contains a `self` pertaining to this zone or a `next` pertaining
#: to next page
links = resource.Body('links', type=dict)
#: Message
message = resource.Body('message')
#: Returns the total_count of resources matching this filter
metadata = resource.Body('metadata', type=list)
#: The project id which the zone belongs to
project_id = resource.Body('project_id')
#: Current status of the zone import
status = resource.Body('status')
#: Timestamp when the zone was last updated
updated_at = resource.Body('updated_at')
#: Version of the resource
version = resource.Body('version', type=int)
#: ID for the zone that was created by this import
zone_id = resource.Body('zone_id')
def create(self, session, prepend_key=True, base_path=None):
"""Create a remote resource based on this instance.
:param session: The session to use for making this request.
:type session: :class:`~keystoneauth1.adapter.Adapter`
:param prepend_key: A boolean indicating whether the resource_key
should be prepended in a resource creation
request. Default to True.
:param str base_path: Base part of the URI for creating resources, if
different from
:data:`~openstack.resource.Resource.base_path`.
:return: This :class:`Resource` instance.
:raises: :exc:`~openstack.exceptions.MethodNotSupported` if
:data:`Resource.allow_create` is not set to ``True``.
"""
if not self.allow_create:
raise exceptions.MethodNotSupported(self, "create")
session = self._get_session(session)
microversion = self._get_microversion_for(session, 'create')
# Create ZoneImport requires empty body and 'text/dns' as content-type
# skip _prepare_request completely, since we need just empty body
request = resource._Request(
self.base_path,
None,
{'content-type': 'text/dns'}
)
response = session.post(request.url,
json=request.body, headers=request.headers,
microversion=microversion)
self.microversion = microversion
self._translate_response(response)
return self

View File

@ -0,0 +1,72 @@
# 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 ZoneTransferBase(resource.Resource):
"""DNS Zone Transfer Request/Accept Base Resource"""
_query_mapping = resource.QueryParameters(
'status'
)
#: Properties
#: Timestamp when the resource was created
created_at = resource.Body('created_at')
#: Key that is used as part of the zone transfer accept process.
#: This is only shown to the creator, and must be communicated out of band.
key = resource.Body('key')
#: The project id which the zone belongs to
project_id = resource.Body('project_id')
#: Current status of the zone import
status = resource.Body('status')
#: Timestamp when the resource was last updated
updated_at = resource.Body('updated_at')
#: Version of the resource
version = resource.Body('version', type=int)
#: ID for the zone that is being exported
zone_id = resource.Body('zone_id')
class ZoneTransferRequest(ZoneTransferBase):
"""DNS Zone Transfer Request Resource"""
base_path = '/zones/tasks/transfer_requests'
resources_key = 'transfer_requests'
# capabilities
allow_create = True
allow_fetch = True
allow_delete = True
allow_list = True
allow_commit = True
#: Description
description = resource.Body('description')
#: A project ID that the request will be limited to.
#: No other project will be allowed to accept this request.
target_project_id = resource.Body('target_project_id')
#: Name for the zone that is being exported
zone_name = resource.Body('zone_name')
class ZoneTransferAccept(ZoneTransferBase):
"""DNS Zone Transfer Accept Resource"""
base_path = '/zones/tasks/transfer_accepts'
resources_key = 'transfer_accepts'
# capabilities
allow_create = True
allow_fetch = True
allow_list = True
#: Name for the zone that is being exported
zone_transfer_request_id = resource.Body('zone_transfer_request_id')

View File

@ -0,0 +1,52 @@
# 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 random
from openstack import connection
from openstack.tests.functional import base
class TestZone(base.BaseFunctionalTest):
def setUp(self):
super(TestZone, self).setUp()
self.require_service('dns')
self.conn = connection.from_config(cloud_name=base.TEST_CLOUD_NAME)
# Note: zone deletion is not an immediate operation, so each time
# chose a new zone name for a test
# getUniqueString is not guaranteed to return unique string between
# different tests of the same class.
self.ZONE_NAME = 'example-{0}.org.'.format(random.randint(1, 100))
self.zone = self.conn.dns.create_zone(
name=self.ZONE_NAME,
email='joe@example.org',
type='PRIMARY',
ttl=7200,
description='example zone'
)
self.addCleanup(self.conn.dns.delete_zone, self.zone)
def tearDown(self):
if self.zone:
self.conn.dns.delete_zone(self.zone)
super(TestZone, self).tearDown()
def test_get_zone(self):
zone = self.conn.dns.get_zone(self.zone)
self.assertEqual(self.zone, zone)
def test_list_zones(self):
names = [f.name for f in self.conn.dns.zones()]
self.assertIn(self.ZONE_NAME, names)

View File

View File

View File

@ -0,0 +1,56 @@
# 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.tests.unit import base
from openstack.dns.v2 import floating_ip as fip
IDENTIFIER = 'RegionOne:id'
EXAMPLE = {
'status': 'PENDING',
'ptrdname': 'smtp.example.com.',
'description': 'This is a floating ip for 127.0.0.1',
'links': {
'self': 'dummylink/reverse/floatingips/RegionOne:id'
},
'ttl': 600,
'address': '172.24.4.10',
'action': 'CREATE',
'id': IDENTIFIER
}
class TestFloatingIP(base.TestCase):
def test_basic(self):
sot = fip.FloatingIP()
self.assertEqual('', sot.resource_key)
self.assertEqual('floatingips', sot.resources_key)
self.assertEqual('/reverse/floatingips', sot.base_path)
self.assertTrue(sot.allow_list)
self.assertFalse(sot.allow_create)
self.assertTrue(sot.allow_fetch)
self.assertTrue(sot.allow_commit)
self.assertFalse(sot.allow_delete)
self.assertEqual('PATCH', sot.commit_method)
def test_make_it(self):
sot = fip.FloatingIP(**EXAMPLE)
self.assertEqual(IDENTIFIER, sot.id)
self.assertEqual(EXAMPLE['ptrdname'], sot.ptrdname)
self.assertEqual(EXAMPLE['description'], sot.description)
self.assertEqual(EXAMPLE['ttl'], sot.ttl)
self.assertEqual(EXAMPLE['address'], sot.address)
self.assertEqual(EXAMPLE['action'], sot.action)
self.assertEqual(EXAMPLE['status'], sot.status)

View File

@ -0,0 +1,197 @@
# 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.dns.v2 import _proxy
from openstack.dns.v2 import zone
from openstack.dns.v2 import zone_import
from openstack.dns.v2 import zone_export
from openstack.dns.v2 import zone_transfer
from openstack.dns.v2 import recordset
from openstack.dns.v2 import floating_ip
from openstack.tests.unit import test_proxy_base
class TestDnsProxy(test_proxy_base.TestProxyBase):
def setUp(self):
super(TestDnsProxy, self).setUp()
self.proxy = _proxy.Proxy(self.session)
class TestDnsZone(TestDnsProxy):
def test_zone_create(self):
self.verify_create(self.proxy.create_zone, zone.Zone,
method_kwargs={'name': 'id'},
expected_kwargs={'name': 'id',
'prepend_key': False})
def test_zone_delete(self):
self.verify_delete(self.proxy.delete_zone,
zone.Zone, True)
def test_zone_find(self):
self.verify_find(self.proxy.find_zone, zone.Zone)
def test_zone_get(self):
self.verify_get(self.proxy.get_zone, zone.Zone)
def test_zones(self):
self.verify_list(self.proxy.zones, zone.Zone)
def test_zone_update(self):
self.verify_update(self.proxy.update_zone, zone.Zone)
def test_zone_abandon(self):
self._verify("openstack.dns.v2.zone.Zone.abandon",
self.proxy.abandon_zone,
method_args=[{'zone': 'id'}])
def test_zone_xfr(self):
self._verify("openstack.dns.v2.zone.Zone.xfr",
self.proxy.xfr_zone,
method_args=[{'zone': 'id'}])
class TestDnsRecordset(TestDnsProxy):
def test_recordset_create(self):
self.verify_create(self.proxy.create_recordset, recordset.Recordset,
method_kwargs={'zone': 'id'},
expected_kwargs={'zone_id': 'id',
'prepend_key': False})
def test_recordset_delete(self):
self.verify_delete(self.proxy.delete_recordset,
recordset.Recordset, True)
def test_recordset_update(self):
self.verify_update(self.proxy.update_recordset, recordset.Recordset)
def test_recordset_get(self):
self.verify_get(self.proxy.get_recordset, recordset.Recordset,
method_kwargs={'zone': 'zid'},
expected_kwargs={'zone_id': 'zid'}
)
def test_recordsets(self):
self.verify_list(self.proxy.recordsets, recordset.Recordset,
base_path='/recordsets')
def test_recordsets_zone(self):
self.verify_list(self.proxy.recordsets, recordset.Recordset,
method_kwargs={'zone': 'zid'},
expected_kwargs={'zone_id': 'zid'})
class TestDnsFloatIP(TestDnsProxy):
def test_floating_ips(self):
self.verify_list(self.proxy.floating_ips, floating_ip.FloatingIP)
def test_floating_ip_get(self):
self.verify_get(self.proxy.get_floating_ip, floating_ip.FloatingIP)
def test_floating_ip_update(self):
self.verify_update(self.proxy.update_floating_ip,
floating_ip.FloatingIP)
def test_zone_create(self):
self.verify_create(self.proxy.create_zone, zone.Zone,
method_kwargs={'name': 'id'},
expected_kwargs={'name': 'id',
'prepend_key': False})
class TestDnsZoneImport(TestDnsProxy):
def test_zone_import_delete(self):
self.verify_delete(self.proxy.delete_zone_import,
zone_import.ZoneImport, True)
def test_zone_import_get(self):
self.verify_get(self.proxy.get_zone_import, zone_import.ZoneImport)
def test_zone_imports(self):
self.verify_list(self.proxy.zone_imports, zone_import.ZoneImport)
def test_zone_import_create(self):
self.verify_create(self.proxy.create_zone_import,
zone_import.ZoneImport,
method_kwargs={'name': 'id'},
expected_kwargs={'name': 'id',
'prepend_key': False})
class TestDnsZoneExport(TestDnsProxy):
def test_zone_export_delete(self):
self.verify_delete(self.proxy.delete_zone_export,
zone_export.ZoneExport, True)
def test_zone_export_get(self):
self.verify_get(self.proxy.get_zone_export, zone_export.ZoneExport)
def test_zone_export_get_text(self):
self.verify_get(self.proxy.get_zone_export_text,
zone_export.ZoneExport,
value=[{'id': 'zone_export_id_value'}],
expected_kwargs={
'base_path': '/zones/tasks/export/%(id)s/export'
})
def test_zone_exports(self):
self.verify_list(self.proxy.zone_exports, zone_export.ZoneExport)
def test_zone_export_create(self):
self.verify_create(self.proxy.create_zone_export,
zone_export.ZoneExport,
method_args=[{'id': 'zone_id_value'}],
method_kwargs={'name': 'id'},
expected_kwargs={'name': 'id',
'zone_id': 'zone_id_value',
'prepend_key': False})
class TestDnsZoneTransferRequest(TestDnsProxy):
def test_zone_transfer_request_delete(self):
self.verify_delete(self.proxy.delete_zone_transfer_request,
zone_transfer.ZoneTransferRequest, True)
def test_zone_transfer_request_get(self):
self.verify_get(self.proxy.get_zone_transfer_request,
zone_transfer.ZoneTransferRequest)
def test_zone_transfer_requests(self):
self.verify_list(self.proxy.zone_transfer_requests,
zone_transfer.ZoneTransferRequest)
def test_zone_transfer_request_create(self):
self.verify_create(self.proxy.create_zone_transfer_request,
zone_transfer.ZoneTransferRequest,
method_args=[{'id': 'zone_id_value'}],
method_kwargs={'name': 'id'},
expected_kwargs={'name': 'id',
'zone_id': 'zone_id_value',
'prepend_key': False})
def test_zone_transfer_request_update(self):
self.verify_update(self.proxy.update_zone_transfer_request,
zone_transfer.ZoneTransferRequest)
class TestDnsZoneTransferAccept(TestDnsProxy):
def test_zone_transfer_accept_get(self):
self.verify_get(self.proxy.get_zone_transfer_accept,
zone_transfer.ZoneTransferAccept)
def test_zone_transfer_accepts(self):
self.verify_list(self.proxy.zone_transfer_accepts,
zone_transfer.ZoneTransferAccept)
def test_zone_transfer_accept_create(self):
self.verify_create(self.proxy.create_zone_transfer_accept,
zone_transfer.ZoneTransferAccept)

View File

@ -0,0 +1,69 @@
# 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.tests.unit import base
from openstack.dns.v2 import recordset
IDENTIFIER = 'NAME'
EXAMPLE = {
'description': 'This is an example record set.',
'updated_at': None,
'records': [
'10.1.0.2'
],
'ttl': 3600,
'id': IDENTIFIER,
'name': 'example.org.',
'project_id': '4335d1f0-f793-11e2-b778-0800200c9a66',
'zone_id': '2150b1bf-dee2-4221-9d85-11f7886fb15f',
'zone_name': 'example.com.',
'created_at': '2014-10-24T19:59:44.000000',
'version': 1,
'type': 'A',
'status': 'ACTIVE',
'action': 'NONE'
}
class TestRecordset(base.TestCase):
def test_basic(self):
sot = recordset.Recordset()
self.assertEqual('recordset', sot.resource_key)
self.assertEqual('recordsets', sot.resources_key)
self.assertEqual('/zones/%(zone_id)s/recordsets', sot.base_path)
self.assertTrue(sot.allow_list)
self.assertTrue(sot.allow_create)
self.assertTrue(sot.allow_fetch)
self.assertTrue(sot.allow_commit)
self.assertTrue(sot.allow_delete)
self.assertDictEqual({'data': 'data',
'description': 'description',
'limit': 'limit',
'marker': 'marker',
'name': 'name',
'status': 'status',
'ttl': 'ttl',
'type': 'type'},
sot._query_mapping._mapping)
def test_make_it(self):
sot = recordset.Recordset(**EXAMPLE)
self.assertEqual(IDENTIFIER, sot.id)
self.assertEqual(EXAMPLE['description'], sot.description)
self.assertEqual(EXAMPLE['ttl'], sot.ttl)
self.assertEqual(EXAMPLE['type'], sot.type)
self.assertEqual(EXAMPLE['name'], sot.name)
self.assertEqual(EXAMPLE['status'], sot.status)

View File

@ -0,0 +1,87 @@
# 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 keystoneauth1 import adapter
import mock
from openstack.tests.unit import base
from openstack.dns.v2 import zone
IDENTIFIER = 'NAME'
EXAMPLE = {
'attributes': {
'tier': 'gold', 'ha': 'true'
},
'id': IDENTIFIER,
'name': 'test.org',
'email': 'joe@example.org',
'type': 'PRIMARY',
'ttl': 7200,
'description': 'This is an example zone.',
'status': 'ACTIVE'
}
class TestZone(base.TestCase):
def setUp(self):
super(TestZone, self).setUp()
self.resp = mock.Mock()
self.resp.body = None
self.resp.json = mock.Mock(return_value=self.resp.body)
self.resp.status_code = 200
self.sess = mock.Mock(spec=adapter.Adapter)
self.sess.post = mock.Mock(return_value=self.resp)
self.sess.default_microversion = None
def test_basic(self):
sot = zone.Zone()
self.assertEqual(None, sot.resource_key)
self.assertEqual('zones', sot.resources_key)
self.assertEqual('/zones', sot.base_path)
self.assertTrue(sot.allow_list)
self.assertTrue(sot.allow_create)
self.assertTrue(sot.allow_fetch)
self.assertTrue(sot.allow_commit)
self.assertTrue(sot.allow_delete)
self.assertEqual('PATCH', sot.commit_method)
self.assertDictEqual({'description': 'description',
'email': 'email',
'limit': 'limit',
'marker': 'marker',
'name': 'name',
'status': 'status',
'ttl': 'ttl',
'type': 'type'},
sot._query_mapping._mapping)
def test_make_it(self):
sot = zone.Zone(**EXAMPLE)
self.assertEqual(IDENTIFIER, sot.id)
self.assertEqual(EXAMPLE['email'], sot.email)
self.assertEqual(EXAMPLE['description'], sot.description)
self.assertEqual(EXAMPLE['ttl'], sot.ttl)
self.assertEqual(EXAMPLE['type'], sot.type)
self.assertEqual(EXAMPLE['name'], sot.name)
self.assertEqual(EXAMPLE['status'], sot.status)
def test_abandon(self):
sot = zone.Zone(**EXAMPLE)
self.assertIsNone(sot.abandon(self.sess))
self.sess.post.assert_called_with(
'zones/NAME/tasks/abandon',
json=None
)

View File

@ -0,0 +1,80 @@
# 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 mock
from keystoneauth1 import adapter
from openstack.tests.unit import base
from openstack.dns.v2 import zone_export
IDENTIFIER = '074e805e-fe87-4cbb-b10b-21a06e215d41'
EXAMPLE = {
'status': 'COMPLETE',
'zone_id': '6625198b-d67d-47dc-8d29-f90bd60f3ac4',
'links': {
'self': 'http://127.0.0.1:9001/v2/zones/tasks/exports/074e805e-f',
'href': 'http://127.0.0.1:9001/v2/zones/6625198b-d67d-'
},
'created_at': '2015-05-08T15:43:42.000000',
'updated_at': '2015-05-08T15:43:43.000000',
'version': 2,
'location': 'designate://v2/zones/tasks/exports/8ec17fe1/export',
'message': 'example.com. exported',
'project_id': 'noauth-project',
'id': IDENTIFIER
}
@mock.patch.object(zone_export.ZoneExport, '_translate_response', mock.Mock())
class TestZoneExport(base.TestCase):
def test_basic(self):
sot = zone_export.ZoneExport()
self.assertEqual('', sot.resource_key)
self.assertEqual('exports', sot.resources_key)
self.assertEqual('/zones/tasks/export', sot.base_path)
self.assertTrue(sot.allow_list)
self.assertTrue(sot.allow_create)
self.assertTrue(sot.allow_fetch)
self.assertFalse(sot.allow_commit)
self.assertTrue(sot.allow_delete)
self.assertDictEqual({'limit': 'limit',
'marker': 'marker',
'message': 'message',
'status': 'status',
'zone_id': 'zone_id'},
sot._query_mapping._mapping)
def test_make_it(self):
sot = zone_export.ZoneExport(**EXAMPLE)
self.assertEqual(IDENTIFIER, sot.id)
self.assertEqual(EXAMPLE['created_at'], sot.created_at)
self.assertEqual(EXAMPLE['updated_at'], sot.updated_at)
self.assertEqual(EXAMPLE['version'], sot.version)
self.assertEqual(EXAMPLE['message'], sot.message)
self.assertEqual(EXAMPLE['project_id'], sot.project_id)
self.assertEqual(EXAMPLE['status'], sot.status)
self.assertEqual(EXAMPLE['zone_id'], sot.zone_id)
def test_create(self):
sot = zone_export.ZoneExport()
response = mock.Mock()
response.json = mock.Mock(return_value='')
self.session = mock.Mock(spec=adapter.Adapter)
self.session.default_microversion = '1.1'
sot.create(self.session)
self.session.post.assert_called_once_with(
mock.ANY, json=None,
headers=None,
microversion=self.session.default_microversion)

View File

@ -0,0 +1,79 @@
# 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 mock
from keystoneauth1 import adapter
from openstack.tests.unit import base
from openstack.dns.v2 import zone_import
IDENTIFIER = '074e805e-fe87-4cbb-b10b-21a06e215d41'
EXAMPLE = {
'status': 'COMPLETE',
'zone_id': '6625198b-d67d-47dc-8d29-f90bd60f3ac4',
'links': {
'self': 'http://127.0.0.1:9001/v2/zones/tasks/imports/074e805e-f',
'href': 'http://127.0.0.1:9001/v2/zones/6625198b-d67d-'
},
'created_at': '2015-05-08T15:43:42.000000',
'updated_at': '2015-05-08T15:43:43.000000',
'version': 2,
'message': 'example.com. imported',
'project_id': 'noauth-project',
'id': IDENTIFIER
}
@mock.patch.object(zone_import.ZoneImport, '_translate_response', mock.Mock())
class TestZoneImport(base.TestCase):
def test_basic(self):
sot = zone_import.ZoneImport()
self.assertEqual('', sot.resource_key)
self.assertEqual('imports', sot.resources_key)
self.assertEqual('/zones/tasks/import', sot.base_path)
self.assertTrue(sot.allow_list)
self.assertTrue(sot.allow_create)
self.assertTrue(sot.allow_fetch)
self.assertFalse(sot.allow_commit)
self.assertTrue(sot.allow_delete)
self.assertDictEqual({'limit': 'limit',
'marker': 'marker',
'message': 'message',
'status': 'status',
'zone_id': 'zone_id'},
sot._query_mapping._mapping)
def test_make_it(self):
sot = zone_import.ZoneImport(**EXAMPLE)
self.assertEqual(IDENTIFIER, sot.id)
self.assertEqual(EXAMPLE['created_at'], sot.created_at)
self.assertEqual(EXAMPLE['updated_at'], sot.updated_at)
self.assertEqual(EXAMPLE['version'], sot.version)
self.assertEqual(EXAMPLE['message'], sot.message)
self.assertEqual(EXAMPLE['project_id'], sot.project_id)
self.assertEqual(EXAMPLE['status'], sot.status)
self.assertEqual(EXAMPLE['zone_id'], sot.zone_id)
def test_create(self):
sot = zone_import.ZoneImport()
response = mock.Mock()
response.json = mock.Mock(return_value='')
self.session = mock.Mock(spec=adapter.Adapter)
self.session.default_microversion = '1.1'
sot.create(self.session)
self.session.post.assert_called_once_with(
mock.ANY, json=None,
headers={'content-type': 'text/dns'},
microversion=self.session.default_microversion)

View File

@ -0,0 +1,103 @@
# 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.tests.unit import base
from openstack.dns.v2 import zone_transfer
IDENTIFIER = '074e805e-fe87-4cbb-b10b-21a06e215d41'
EXAMPLE_REQUEST = {
'created_at': '2014-07-17T20:34:40.882579',
'description': 'some description',
'id': IDENTIFIER,
'key': '9Z2R50Y0',
'project_id': '1',
'status': 'ACTIVE',
'target_project_id': '123456',
'updated_at': None,
'zone_id': '6b78734a-aef1-45cd-9708-8eb3c2d26ff8',
'zone_name': 'qa.dev.example.com.',
}
EXAMPLE_ACCEPT = {
'status': 'COMPLETE',
'zone_id': 'b4542f5a-f1ea-4ec1-b850-52db9dc3f465',
'created_at': '2016-06-22 06:13:55',
'updated_at': 'null',
'key': 'FUGXMZ5N',
'project_id': '2e43de7ce3504a8fb90a45382532c37e',
'id': IDENTIFIER,
'zone_transfer_request_id': '794fdf58-6e1d-41da-8b2d-16b6d10c8827'
}
class TestZoneTransferRequest(base.TestCase):
def test_basic(self):
sot = zone_transfer.ZoneTransferRequest()
# self.assertEqual('', sot.resource_key)
self.assertEqual('transfer_requests', sot.resources_key)
self.assertEqual('/zones/tasks/transfer_requests', sot.base_path)
self.assertTrue(sot.allow_list)
self.assertTrue(sot.allow_create)
self.assertTrue(sot.allow_fetch)
self.assertTrue(sot.allow_commit)
self.assertTrue(sot.allow_delete)
self.assertDictEqual({'limit': 'limit',
'marker': 'marker',
'status': 'status'},
sot._query_mapping._mapping)
def test_make_it(self):
sot = zone_transfer.ZoneTransferRequest(**EXAMPLE_REQUEST)
self.assertEqual(IDENTIFIER, sot.id)
self.assertEqual(EXAMPLE_REQUEST['created_at'], sot.created_at)
self.assertEqual(EXAMPLE_REQUEST['updated_at'], sot.updated_at)
self.assertEqual(EXAMPLE_REQUEST['description'], sot.description)
self.assertEqual(EXAMPLE_REQUEST['key'], sot.key)
self.assertEqual(EXAMPLE_REQUEST['project_id'], sot.project_id)
self.assertEqual(EXAMPLE_REQUEST['status'], sot.status)
self.assertEqual(EXAMPLE_REQUEST['target_project_id'],
sot.target_project_id)
self.assertEqual(EXAMPLE_REQUEST['zone_id'], sot.zone_id)
self.assertEqual(EXAMPLE_REQUEST['zone_name'], sot.zone_name)
class TestZoneTransferAccept(base.TestCase):
def test_basic(self):
sot = zone_transfer.ZoneTransferAccept()
# self.assertEqual('', sot.resource_key)
self.assertEqual('transfer_accepts', sot.resources_key)
self.assertEqual('/zones/tasks/transfer_accepts', sot.base_path)
self.assertTrue(sot.allow_list)
self.assertTrue(sot.allow_create)
self.assertTrue(sot.allow_fetch)
self.assertFalse(sot.allow_commit)
self.assertFalse(sot.allow_delete)
self.assertDictEqual({'limit': 'limit',
'marker': 'marker',
'status': 'status'},
sot._query_mapping._mapping)
def test_make_it(self):
sot = zone_transfer.ZoneTransferAccept(**EXAMPLE_ACCEPT)
self.assertEqual(IDENTIFIER, sot.id)
self.assertEqual(EXAMPLE_ACCEPT['created_at'], sot.created_at)
self.assertEqual(EXAMPLE_ACCEPT['updated_at'], sot.updated_at)
self.assertEqual(EXAMPLE_ACCEPT['key'], sot.key)
self.assertEqual(EXAMPLE_ACCEPT['project_id'], sot.project_id)
self.assertEqual(EXAMPLE_ACCEPT['status'], sot.status)
self.assertEqual(EXAMPLE_ACCEPT['zone_id'], sot.zone_id)
self.assertEqual(EXAMPLE_ACCEPT['zone_transfer_request_id'],
sot.zone_transfer_request_id)

View File

@ -207,6 +207,7 @@ class TestProxyBase(base.TestCase):
if 'paginated' in kwargs:
expected_kwargs.update({"paginated": kwargs.pop('paginated')})
method_kwargs = kwargs.pop("method_kwargs", {})
expected_kwargs["base_path"] = kwargs.pop("base_path", None)
self._verify2(mock_method, test_method,
method_kwargs=method_kwargs,
expected_args=[resource_type],

View File

@ -0,0 +1,5 @@
---
features:
- |
Adds support for `dns
<https://developer.openstack.org/api-ref/dns/>`_ service.