Retire Packaging Deb project repos

This commit is part of a series to retire the Packaging Deb
project. Step 2 is to remove all content from the project
repos, replacing it with a README notification where to find
ongoing work, and how to recover the repo if needed at some
future point (as in
https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project).

Change-Id: I23a2ff2335d997b37d7d934bb0f782ad25760dd9
This commit is contained in:
Tony Breeds
2017-09-12 15:57:46 -06:00
parent ea41cef9a1
commit 9ca012aef8
140 changed files with 14 additions and 13220 deletions

26
.gitignore vendored
View File

@@ -1,26 +0,0 @@
*.pyc
*.dat
TAGS
*.egg
*.egg-info
.eggs
build
.coverage
.tox
cover
venv
.venv
*.sublime-workspace
*.sqlite
var/*
etc/*.conf
etc/*.ini
AUTHORS
ChangeLog
doc/source/reference/api/*
doc/build/*
dist
designateclient/versioninfo
.testrepository
*.log
.idea/

View File

@@ -1,4 +0,0 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/python-designateclient.git

View File

@@ -1,10 +0,0 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_LOG_CAPTURE=${OS_LOG_CAPTURE:-1} \
OS_DEBUG=${OS_DEBUG:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-160} \
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./designateclient/tests} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@@ -1,16 +0,0 @@
If you would like to contribute to the development of OpenStack,
you must follow the steps documented at:
http://docs.openstack.org/infra/manual/developers.html
Once those steps have been completed, changes to OpenStack
should be submitted for review via the Gerrit tool, following
the workflow documented at:
http://docs.openstack.org/infra/manual/developers.html#development-workflow
Pull requests submitted through GitHub will be ignored.
Bugs should be filed on Launchpad, not GitHub:
https://bugs.launchpad.net/python-designateclient

176
LICENSE
View File

@@ -1,176 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

14
README Normal file
View File

@@ -0,0 +1,14 @@
This project is no longer maintained.
The contents of this repository are still available in the Git
source code management system. To see the contents of this
repository before it reached its end of life, please check out the
previous commit with "git checkout HEAD^1".
For ongoing work on maintaining OpenStack packages in the Debian
distribution, please see the Debian OpenStack packaging team at
https://wiki.debian.org/OpenStack/.
For any further questions, please email
openstack-dev@lists.openstack.org or join #openstack-dev on
Freenode.

View File

@@ -1,42 +0,0 @@
========================
Team and repository tags
========================
.. image:: http://governance.openstack.org/badges/python-designateclient.svg
:target: http://governance.openstack.org/reference/tags/index.html
.. Change things from this point on
Python bindings to the Designate API
=====================================
.. image:: https://img.shields.io/pypi/v/python-designateclient.svg
:target: https://pypi.python.org/pypi/python-designateclient/
:alt: Latest Version
.. image:: https://img.shields.io/pypi/dm/python-designateclient.svg
:target: https://pypi.python.org/pypi/python-designateclient/
:alt: Downloads
This is a client library for Designate built on the Designate API. It
provides a Python API (the ``designateclient`` module) and a command-line tool
(``designate``).
Development takes place via the usual OpenStack processes as outlined in the
`developer guide <http://docs.openstack.org/infra/manual/developers.html>`_. The master
repository is in `Git <http://git.openstack.org/cgit/openstack/python-designateclient>`_.
See release notes and more at `<http://docs.openstack.org/developer/python-designateclient/>`_.
* License: Apache License, Version 2.0
* `PyPi`_ - package installation
* `Online Documentation`_
* `Bugs`_ - issue tracking
* `Source`_
* `How to Contribute`_
.. _PyPi: https://pypi.python.org/pypi/python-designateclient
.. _Online Documentation: http://docs.openstack.org/developer/python-designateclient
.. _Bugs: https://bugs.launchpad.net/python-designateclient
.. _Source: https://git.openstack.org/cgit/openstack/python-designateclient
.. _How to Contribute: http://docs.openstack.org/infra/manual/developers.html

View File

@@ -1,21 +0,0 @@
#!/usr/bin/env python
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 sys
from designateclient.shell import DesignateShell
shell = DesignateShell()
sys.exit(shell.run(sys.argv[1:]))

View File

@@ -1,19 +0,0 @@
# Copyright 2017 Huawei, Inc. All rights reserved.
#
# 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 designateclient import version
__version__ = version.version_info.version_string()

View File

@@ -1,139 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 abc
import warnings
from keystoneauth1 import exceptions as ks_exceptions
from osc_lib.command import command
import six
from designateclient import exceptions
from designateclient import utils
from designateclient.v1 import Client
@six.add_metaclass(abc.ABCMeta)
class Command(command.Command):
def run(self, parsed_args):
warnings.simplefilter('once', category=DeprecationWarning)
warnings.warn(
'The "designate" CLI is being deprecated in favour of the '
'"openstack" CLI plugin. All designate API v2 commands are '
'implemented there. When the v1 API is removed this CLI will '
'stop functioning',
DeprecationWarning)
warnings.resetwarnings()
warnings.simplefilter('ignore', category=DeprecationWarning)
self.client = Client(
region_name=self.app.options.os_region_name,
service_type=self.app.options.os_service_type,
endpoint_type=self.app.options.os_endpoint_type,
session=self.app.session,
all_tenants=self.app.options.all_tenants,
edit_managed=self.app.options.edit_managed,
endpoint=self.app.options.os_endpoint)
warnings.resetwarnings()
try:
return super(Command, self).run(parsed_args)
except exceptions.RemoteError as e:
columns = ['Code', 'Type']
values = [e.code, e.type]
if e.message:
columns.append('Message')
values.append(e.message)
if e.errors:
columns.append('Errors')
values.append(e.errors)
self.error_output(parsed_args, columns, values)
except ks_exceptions.EndpointNotFound as e:
self.app.log.error('No endpoint was found. You must provide a '
'username or user id via --os-username, '
'--os-user-id, env[OS_USERNAME] or '
'env[OS_USER_ID]')
return 1
def error_output(self, parsed_args, column_names, data):
self.formatter.emit_one(column_names,
data,
self.app.stdout,
parsed_args)
self.app.log.error('The requested action did not complete '
'successfully')
@abc.abstractmethod
def execute(self, parsed_args):
"""
Execute something, this is since we overload self.take_action()
in order to format the data
This method __NEEDS__ to be overloaded!
:param parsed_args: The parsed args that are given by take_action()
"""
def post_execute(self, data):
"""
Format the results locally if needed, by default we just return data
:param data: Whatever is returned by self.execute()
"""
return data
def take_action(self, parsed_args):
results = self.execute(parsed_args)
return self.post_execute(results)
def find_resourceid_by_name_or_id(self, resource_plural, name_or_id):
resource_client = getattr(self.client, resource_plural)
return utils.find_resourceid_by_name_or_id(resource_client, name_or_id)
class ListCommand(Command, command.Lister):
columns = None
def post_execute(self, results):
if len(results) > 0:
columns = self.columns or utils.get_columns(results)
data = [utils.get_item_properties(i, columns) for i in results]
return columns, data
else:
return [], ()
class GetCommand(Command, command.ShowOne):
def post_execute(self, results):
return list(six.iterkeys(results)), list(six.itervalues(results))
class CreateCommand(Command, command.ShowOne):
def post_execute(self, results):
return list(six.iterkeys(results)), list(six.itervalues(results))
class UpdateCommand(Command, command.ShowOne):
def post_execute(self, results):
return list(six.iterkeys(results)), list(six.itervalues(results))
class DeleteCommand(Command, command.ShowOne):
def post_execute(self, results):
return [], []

View File

@@ -1,38 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 logging
from designateclient.cli import base
LOG = logging.getLogger(__name__)
class PingCommand(base.GetCommand):
"""Ping a service on a given host"""
def get_parser(self, prog_name):
parser = super(PingCommand, self).get_parser(prog_name)
parser.add_argument('--service', help="Service name (e.g. central)",
required=True)
parser.add_argument('--host', help="Hostname", required=True)
return parser
def execute(self, parsed_args):
return self.client.diagnostics.ping(parsed_args.service,
parsed_args.host)

View File

@@ -1,144 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 logging
from designateclient.cli import base
from designateclient.v1.domains import Domain
LOG = logging.getLogger(__name__)
class ListDomainsCommand(base.ListCommand):
"""List Domains"""
columns = ['id', 'name', 'serial']
def execute(self, parsed_args):
return self.client.domains.list()
class GetDomainCommand(base.GetCommand):
"""Get Domain"""
def get_parser(self, prog_name):
parser = super(GetDomainCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Domain ID or name.")
return parser
def execute(self, parsed_args):
id = self.find_resourceid_by_name_or_id('domains', parsed_args.id)
return self.client.domains.get(id)
class CreateDomainCommand(base.CreateCommand):
"""Create Domain"""
def get_parser(self, prog_name):
parser = super(CreateDomainCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="Domain name.", required=True)
parser.add_argument('--email', help="Domain email.", required=True)
parser.add_argument('--ttl', type=int, help="Time to live (seconds).")
parser.add_argument('--description', help="Description.")
return parser
def execute(self, parsed_args):
domain = Domain(
name=parsed_args.name,
email=parsed_args.email,
)
if parsed_args.description:
domain.description = parsed_args.description
if parsed_args.ttl is not None:
domain.ttl = parsed_args.ttl
return self.client.domains.create(domain)
class UpdateDomainCommand(base.UpdateCommand):
"""Update Domain"""
def get_parser(self, prog_name):
parser = super(UpdateDomainCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Domain ID or name.")
parser.add_argument('--name', help="Domain name.")
parser.add_argument('--email', help="Domain email.")
parser.add_argument('--ttl', type=int, help="Time to live (seconds).")
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description.")
description_group.add_argument('--no-description', action='store_true')
return parser
def execute(self, parsed_args):
# TODO(kiall): API needs updating.. this get is silly
id = self.find_resourceid_by_name_or_id('domains', parsed_args.id)
domain = self.client.domains.get(id)
if parsed_args.name:
domain.name = parsed_args.name
if parsed_args.email:
domain.email = parsed_args.email
if parsed_args.ttl is not None:
domain.ttl = parsed_args.ttl
if parsed_args.no_description:
domain.description = None
elif parsed_args.description:
domain.description = parsed_args.description
return self.client.domains.update(domain)
class DeleteDomainCommand(base.DeleteCommand):
"""Delete Domain"""
def get_parser(self, prog_name):
parser = super(DeleteDomainCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Domain ID or name.")
return parser
def execute(self, parsed_args):
id = self.find_resourceid_by_name_or_id('domains', parsed_args.id)
return self.client.domains.delete(id)
class ListDomainServersCommand(base.ListCommand):
"""List Domain Servers"""
columns = ['name']
def get_parser(self, prog_name):
parser = super(ListDomainServersCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Domain ID or name.")
return parser
def execute(self, parsed_args):
id = self.find_resourceid_by_name_or_id('domains', parsed_args.id)
return self.client.domains.list_domain_servers(id)

View File

@@ -1,83 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 logging
from designateclient.cli import base
LOG = logging.getLogger(__name__)
class GetQuotaCommand(base.GetCommand):
"""Get Quota"""
def get_parser(self, prog_name):
parser = super(GetQuotaCommand, self).get_parser(prog_name)
parser.add_argument('tenant_id', help="Tenant ID")
return parser
def execute(self, parsed_args):
return self.client.quotas.get(parsed_args.tenant_id)
class UpdateQuotaCommand(base.UpdateCommand):
"""Update Quota"""
def get_parser(self, prog_name):
parser = super(UpdateQuotaCommand, self).get_parser(prog_name)
parser.add_argument('tenant_id', help="Tenant ID.")
parser.add_argument('--domains', help="Allowed domains.", type=int)
parser.add_argument('--domain-recordsets',
help="Allowed domain records.",
type=int)
parser.add_argument('--recordset-records',
help="Allowed recordset records.",
type=int)
parser.add_argument('--domain-records',
help="Allowed domain records.",
type=int)
parser.add_argument('--api-export-size',
help="Allowed zone export recordsets.",
type=int)
return parser
def execute(self, parsed_args):
# TODO(kiall): API needs updating.. this get is silly
quota = self.client.quotas.get(parsed_args.tenant_id)
for key, old in quota.items():
new = getattr(parsed_args, key)
if new is not None and new != old:
quota[key] = new
return self.client.quotas.update(parsed_args.tenant_id, quota)
class ResetQuotaCommand(base.DeleteCommand):
"""Reset Quota"""
def get_parser(self, prog_name):
parser = super(ResetQuotaCommand, self).get_parser(prog_name)
parser.add_argument('tenant_id', help="Tenant ID.")
return parser
def execute(self, parsed_args):
self.client.quotas.reset(parsed_args.tenant_id)

View File

@@ -1,187 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 logging
from designateclient.cli import base
from designateclient.v1.records import Record
LOG = logging.getLogger(__name__)
class ListRecordsCommand(base.ListCommand):
"""List Records"""
columns = ['id', 'type', 'name', 'data']
def get_parser(self, prog_name):
parser = super(ListRecordsCommand, self).get_parser(prog_name)
parser.add_argument('domain_id', help="Domain ID or name.")
return parser
def execute(self, parsed_args):
domain_id = self.find_resourceid_by_name_or_id(
'domains', parsed_args.domain_id)
return self.client.records.list(domain_id)
class GetRecordCommand(base.GetCommand):
"""Get Record"""
def get_parser(self, prog_name):
parser = super(GetRecordCommand, self).get_parser(prog_name)
parser.add_argument('domain_id', help="Domain ID or name.")
parser.add_argument('id', help="Record ID.")
return parser
def execute(self, parsed_args):
domain_id = self.find_resourceid_by_name_or_id(
'domains', parsed_args.domain_id)
return self.client.records.get(domain_id, parsed_args.id)
class CreateRecordCommand(base.CreateCommand):
"""Create Record"""
def get_parser(self, prog_name):
parser = super(CreateRecordCommand, self).get_parser(prog_name)
parser.add_argument('domain_id', help="Domain ID or name.")
parser.add_argument(
'--name', help="Record (relative|absolute) name.", required=True)
parser.add_argument('--type', help="Record type.", required=True)
parser.add_argument('--data', help="Record data.", required=True)
parser.add_argument('--ttl', type=int, help="Record TTL.")
parser.add_argument('--priority', type=int, help="Record priority.")
parser.add_argument('--description', help="Description.")
return parser
def execute(self, parsed_args):
domain_id = self.find_resourceid_by_name_or_id(
'domains', parsed_args.domain_id)
if not parsed_args.name.endswith('.'):
# Relative name?
domain_name = self.client.domains.get(domain_id)['name']
absolute = parsed_args.name + '.'
relative = absolute + domain_name
if absolute.endswith('.' + domain_name):
# Relative name or absolute name missing final period?
msg = ('"%s" is a relative name but looks like an absolute '
'name, use --name "%s" or "%s"'
% (parsed_args.name, absolute, relative))
raise ValueError(msg)
parsed_args.name = relative
record = Record(
name=parsed_args.name,
type=parsed_args.type,
data=parsed_args.data,
)
if parsed_args.ttl is not None:
record.ttl = parsed_args.ttl
if parsed_args.priority is not None:
record.priority = parsed_args.priority
if parsed_args.description:
record.description = parsed_args.description
return self.client.records.create(domain_id, record)
class UpdateRecordCommand(base.UpdateCommand):
"""Update Record"""
def get_parser(self, prog_name):
parser = super(UpdateRecordCommand, self).get_parser(prog_name)
parser.add_argument('domain_id', help="Domain ID or name.")
parser.add_argument('id', help="Record ID.")
parser.add_argument('--name', help="Record name.")
parser.add_argument('--type', help="Record type.")
parser.add_argument('--data', help="Record data.")
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description.")
description_group.add_argument('--no-description', action='store_true')
ttl_group = parser.add_mutually_exclusive_group()
ttl_group.add_argument('--ttl', type=int,
help="Record time to live (seconds).")
ttl_group.add_argument('--no-ttl', action='store_true')
priotity_group = parser.add_mutually_exclusive_group()
priotity_group.add_argument('--priority', type=int,
help="Record priority.")
priotity_group.add_argument('--no-priority', action='store_true')
return parser
def execute(self, parsed_args):
# TODO(kiall): API needs updating.. this get is silly
record = self.client.records.get(parsed_args.domain_id, parsed_args.id)
if parsed_args.name:
record.name = parsed_args.name
if parsed_args.type:
record.type = parsed_args.type
if parsed_args.data:
record.data = parsed_args.data
if parsed_args.no_ttl:
record.ttl = None
elif parsed_args.ttl is not None:
record.ttl = parsed_args.ttl
if parsed_args.no_priority:
record.priority = None
elif parsed_args.priority is not None:
record.priority = parsed_args.priority
if parsed_args.no_description:
record.description = None
elif parsed_args.description:
record.description = parsed_args.description
domain_id = self.find_resourceid_by_name_or_id(
'domains', parsed_args.domain_id)
return self.client.records.update(domain_id, record)
class DeleteRecordCommand(base.DeleteCommand):
"""Delete Record"""
def get_parser(self, prog_name):
parser = super(DeleteRecordCommand, self).get_parser(prog_name)
parser.add_argument('domain_id', help="Domain ID or name.")
parser.add_argument('id', help="Record ID.")
return parser
def execute(self, parsed_args):
domain_id = self.find_resourceid_by_name_or_id(
'domains', parsed_args.domain_id)
return self.client.records.delete(domain_id, parsed_args.id)

View File

@@ -1,71 +0,0 @@
# Copyright 2013 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# Author: Patrick Galbraith <patg@patg.net>
#
# 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 designateclient.cli import base
class DomainCountCommand(base.GetCommand):
"""Get counts for total domains"""
def execute(self, parsed_args):
return self.client.reports.count_domains()
class RecordCountCommand(base.GetCommand):
"""Get counts for total records"""
def execute(self, parsed_args):
return self.client.reports.count_records()
class TenantCountCommand(base.GetCommand):
"""Get counts for total tenants"""
def execute(self, parsed_args):
return self.client.reports.count_tenants()
class CountsCommand(base.GetCommand):
"""Get count totals for all tenants, domains and records"""
def execute(self, parsed_args):
return self.client.reports.count_all()
class TenantsCommand(base.ListCommand):
"""Get list of tenants and domain count for each"""
columns = ['domain_count', 'id']
def execute(self, parsed_args):
return self.client.reports.tenants_all()
class TenantCommand(base.ListCommand):
"""Get a list of domains for given tenant"""
columns = ['domain']
def get_parser(self, prog_name):
parser = super(TenantCommand, self).get_parser(prog_name)
parser.add_argument('--report-tenant-id',
help="The tenant_id being reported on.",
required=True)
return parser
def execute(self, parsed_args):
return self.client.reports.tenant_domains(parsed_args.report_tenant_id)

View File

@@ -1,98 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 logging
from designateclient.cli import base
from designateclient.v1.servers import Server
LOG = logging.getLogger(__name__)
class ListServersCommand(base.ListCommand):
"""List Servers"""
columns = ['id', 'name']
def execute(self, parsed_args):
return self.client.servers.list()
class GetServerCommand(base.GetCommand):
"""Get Server"""
def get_parser(self, prog_name):
parser = super(GetServerCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Server ID.")
return parser
def execute(self, parsed_args):
return self.client.servers.get(parsed_args.id)
class CreateServerCommand(base.CreateCommand):
"""Create Server"""
def get_parser(self, prog_name):
parser = super(CreateServerCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="Server name.", required=True)
return parser
def execute(self, parsed_args):
server = Server(
name=parsed_args.name,
)
return self.client.servers.create(server)
class UpdateServerCommand(base.UpdateCommand):
"""Update Server"""
def get_parser(self, prog_name):
parser = super(UpdateServerCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Server ID.")
parser.add_argument('--name', help="Server name.")
return parser
def execute(self, parsed_args):
# TODO(kiall): API needs updating.. this get is silly
server = self.client.servers.get(parsed_args.id)
if parsed_args.name:
server.name = parsed_args.name
return self.client.servers.update(server)
class DeleteServerCommand(base.DeleteCommand):
"""Delete Server"""
def get_parser(self, prog_name):
parser = super(DeleteServerCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Server ID.")
return parser
def execute(self, parsed_args):
return self.client.servers.delete(parsed_args.id)

View File

@@ -1,63 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 logging
from designateclient.cli import base
LOG = logging.getLogger(__name__)
class SyncAllCommand(base.DeleteCommand):
"""Sync Everything"""
def execute(self, parsed_args):
self.client.sync.sync_all()
LOG.info('Synchronization of all domains scheduled')
class SyncDomainCommand(base.DeleteCommand):
"""Sync a single Domain"""
def get_parser(self, prog_name):
parser = super(SyncDomainCommand, self).get_parser(prog_name)
parser.add_argument('domain_id', help="Domain ID")
return parser
def execute(self, parsed_args):
self.client.sync.sync_domain(parsed_args.domain_id)
LOG.info('Synchronization of domain scheduled')
class SyncRecordCommand(base.DeleteCommand):
"""Sync a single Record"""
def get_parser(self, prog_name):
parser = super(SyncRecordCommand, self).get_parser(prog_name)
parser.add_argument('domain_id', help="Domain ID")
parser.add_argument('record_id', help="Record ID")
return parser
def execute(self, parsed_args):
self.client.sync.sync_record(parsed_args.domain_id,
parsed_args.record_id)
LOG.info('Synchronization of record scheduled')

View File

@@ -1,37 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 logging
from designateclient.cli import base
LOG = logging.getLogger(__name__)
class TouchDomainCommand(base.DeleteCommand):
"""Touch a single Domain"""
def get_parser(self, prog_name):
parser = super(TouchDomainCommand, self).get_parser(prog_name)
parser.add_argument('domain_id', help="Domain ID")
return parser
def execute(self, parsed_args):
self.client.touch.domain(parsed_args.domain_id)
LOG.info('Domain touched successfully')

View File

@@ -1,135 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 abc
import json
import six
from six.moves.urllib import parse
from stevedore import extension
from designateclient import exceptions
@six.add_metaclass(abc.ABCMeta)
class Controller(object):
def __init__(self, client):
self.client = client
def build_url(self, url, criterion=None, marker=None, limit=None):
params = criterion or {}
if marker is not None:
params['marker'] = marker
if limit is not None:
params['limit'] = limit
q = parse.urlencode(params) if params else ''
return '%(url)s%(params)s' % {
'url': url,
'params': '?%s' % q
}
def _serialize(self, kwargs):
headers = kwargs.get('headers')
content_type = headers.get('Content-Type') if headers else None
if 'data' in kwargs and content_type in {None, 'application/json'}:
kwargs['data'] = json.dumps(kwargs['data'])
def _post(self, url, response_key=None, **kwargs):
self._serialize(kwargs)
resp, body = self.client.session.post(url, **kwargs)
if response_key is not None:
return body[response_key]
return body
def _get(self, url, response_key=None):
resp, body = self.client.session.get(url)
if response_key is not None:
return body[response_key]
return body
def _patch(self, url, response_key=None, **kwargs):
self._serialize(kwargs)
resp, body = self.client.session.patch(url, **kwargs)
if response_key is not None:
return body[response_key]
return body
def _put(self, url, response_key=None, **kwargs):
self._serialize(kwargs)
resp, body = self.client.session.put(url, **kwargs)
if response_key is not None:
return body[response_key]
return body
def _delete(self, url, response_key=None, **kwargs):
resp, body = self.client.session.delete(url, **kwargs)
if response_key is not None:
return body[response_key]
return body
@six.add_metaclass(abc.ABCMeta)
class CrudController(Controller):
@abc.abstractmethod
def list(self, *args, **kw):
"""
List a resource
"""
@abc.abstractmethod
def get(self, *args, **kw):
"""
Get a resource
"""
@abc.abstractmethod
def create(self, *args, **kw):
"""
Create a resource
"""
@abc.abstractmethod
def update(self, *args, **kw):
"""
Update a resource
"""
@abc.abstractmethod
def delete(self, *args, **kw):
"""
Delete a resource
"""
def get_versions():
mgr = extension.ExtensionManager('designateclient.versions')
return dict([(ep.name, ep.plugin) for ep in mgr.extensions])
def Client(version, *args, **kwargs): # noqa
versions = get_versions()
if version not in versions:
msg = 'Version %s is not supported, use one of (%s)' % (
version, list(six.iterkeys(versions)))
raise exceptions.UnsupportedVersion(msg)
return versions[version](*args, **kwargs)

View File

@@ -1,84 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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.
class Base(Exception):
def __init__(self, message=None):
if not message:
message = self.__class__.__name__
super(Base, self).__init__(message)
class UnsupportedVersion(Base):
pass
class ResourceNotFound(Base):
pass
class NoUniqueMatch(Base):
pass
class RemoteError(Base):
def __init__(self, message=None, code=None, type=None, errors=None,
request_id=None):
err_message = self._get_error_message(message, type, errors)
self.message = err_message
self.code = code
self.type = type
self.errors = errors
self.request_id = request_id
super(RemoteError, self).__init__(err_message)
def _get_error_message(self, _message, _type, _errors):
# Try to get a useful error msg if 'message' has nothing
if not _message:
if _errors and 'errors' in _errors:
err_msg = list()
for err in _errors['errors']:
if 'message' in err:
err_msg.append(err['message'])
_message = '. '.join(err_msg)
elif _type:
_message = str(_type)
return _message
class Unknown(RemoteError):
pass
class BadRequest(RemoteError):
pass
class Forbidden(RemoteError):
pass
class Conflict(RemoteError):
pass
class NotFound(RemoteError):
pass
class OverQuota(RemoteError):
pass

View File

@@ -1,7 +0,0 @@
import logging
logging.basicConfig(
filename='functional-tests.log',
filemode='w',
level=logging.DEBUG,
)

View File

@@ -1,46 +0,0 @@
"""
Copyright 2015 Rackspace
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 tempest.lib.cli import base
from tempest.lib.exceptions import CommandFailed
from designateclient.functionaltests import client
from designateclient.functionaltests import config
class BaseDesignateTest(base.ClientTestBase):
def _get_clients(self):
config.read_config()
return client.DesignateCLI.as_user('default')
def ensure_tld_exists(self, tld):
try:
self.clients.as_user('admin').tld_create(tld)
except CommandFailed:
pass
def _is_entity_in_list(self, entity, entity_list):
"""Determines if the given entity exists in the given list.
Uses the id for comparison.
Certain entities (e.g. zone import, export) cannot be made
comparable in a list of CLI output results, because the fields
in a list command can be different from those in a show command.
"""
return any([entity_record.id == entity.id
for entity_record in entity_list])

View File

@@ -1,388 +0,0 @@
"""
Copyright 2015 Rackspace
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 logging
import os
from tempest.lib.cli import base
from designateclient.functionaltests.config import cfg
from designateclient.functionaltests.models import FieldValueModel
from designateclient.functionaltests.models import ListModel
LOG = logging.getLogger(__name__)
def build_option_string(options):
"""Format a string of option flags (--key 'value').
This will quote the values, in case spaces are included.
Any values that are None are excluded entirely.
Usage::
build_option_string({
"--email": "me@example.com",
"--name": "example.com."
"--ttl": None,
})
Returns::
"--email 'me@example.com' --name 'example.com.'
"""
return " ".join("{0} '{1}'".format(flag, value)
for flag, value in options.items()
if value is not None)
def build_flags_string(flags):
"""Format a string of value-less flags.
Pass in a dictionary mapping flags to booleans. Those flags set to true
are included in the returned string.
Usage::
build_flags_string({
'--no-ttl': True,
'--no-name': False,
'--verbose': True,
})
Returns::
'--no-ttl --verbose'
"""
flags = {flag: is_set for flag, is_set in flags.items() if is_set}
return " ".join(flags.keys())
class ZoneCommands(object):
"""This is a mixin that provides zone commands to DesignateCLI"""
def zone_list(self, *args, **kwargs):
return self.parsed_cmd('zone list', ListModel, *args, **kwargs)
def zone_show(self, id, *args, **kwargs):
return self.parsed_cmd('zone show %s' % id, FieldValueModel, *args,
**kwargs)
def zone_delete(self, id, *args, **kwargs):
return self.parsed_cmd('zone delete %s' % id, FieldValueModel, *args,
**kwargs)
def zone_create(self, name, email=None, ttl=None, description=None,
type=None, masters=None, *args, **kwargs):
options_str = build_option_string({
"--email": email,
"--ttl": ttl,
"--description": description,
"--masters": masters,
"--type": type,
})
cmd = 'zone create {0} {1}'.format(name, options_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_set(self, id, email=None, ttl=None, description=None,
type=None, masters=None, *args, **kwargs):
options_str = build_option_string({
"--email": email,
"--ttl": ttl,
"--description": description,
"--masters": masters,
"--type": type,
})
cmd = 'zone set {0} {1}'.format(id, options_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
class ZoneTransferCommands(object):
"""A mixin for DesignateCLI to add zone transfer commands"""
def zone_transfer_request_list(self, *args, **kwargs):
cmd = 'zone transfer request list'
return self.parsed_cmd(cmd, ListModel, *args, **kwargs)
def zone_transfer_request_create(self, zone_id, target_project_id=None,
description=None, *args, **kwargs):
options_str = build_option_string({
"--target-project-id": target_project_id,
"--description": description,
})
cmd = 'zone transfer request create {0} {1}'.format(
zone_id, options_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_transfer_request_show(self, id, *args, **kwargs):
cmd = 'zone transfer request show {0}'.format(id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_transfer_request_set(self, id, description=None, *args, **kwargs):
options_str = build_option_string({"--description": description})
cmd = 'zone transfer request set {0} {1}'.format(options_str, id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_transfer_request_delete(self, id, *args, **kwargs):
cmd = 'zone transfer request delete {0}'.format(id)
return self.parsed_cmd(cmd, *args, **kwargs)
def zone_transfer_accept_request(self, id, key, *args, **kwargs):
options_str = build_option_string({
"--transfer-id": id,
"--key": key,
})
cmd = 'zone transfer accept request {0}'.format(options_str)
return self.parsed_cmd(cmd, *args, **kwargs)
def zone_transfer_accept_show(self, id, *args, **kwargs):
cmd = 'zone transfer accept show {0}'.format(id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
class ZoneExportCommands(object):
"""A mixin for DesignateCLI to add zone export commands"""
def zone_export_list(self, *args, **kwargs):
cmd = 'zone export list'
return self.parsed_cmd(cmd, ListModel, *args, **kwargs)
def zone_export_create(self, zone_id, *args, **kwargs):
cmd = 'zone export create {0}'.format(
zone_id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_export_show(self, zone_export_id, *args, **kwargs):
cmd = 'zone export show {0}'.format(zone_export_id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_export_delete(self, zone_export_id, *args, **kwargs):
cmd = 'zone export delete {0}'.format(zone_export_id)
return self.parsed_cmd(cmd, *args, **kwargs)
def zone_export_showfile(self, zone_export_id, *args, **kwargs):
cmd = 'zone export showfile {0}'.format(zone_export_id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
class ZoneImportCommands(object):
"""A mixin for DesignateCLI to add zone import commands"""
def zone_import_list(self, *args, **kwargs):
cmd = 'zone import list'
return self.parsed_cmd(cmd, ListModel, *args, **kwargs)
def zone_import_create(self, zone_file_path, *args, **kwargs):
cmd = 'zone import create {0}'.format(zone_file_path)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_import_show(self, zone_import_id, *args, **kwargs):
cmd = 'zone import show {0}'.format(zone_import_id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_import_delete(self, zone_import_id, *args, **kwargs):
cmd = 'zone import delete {0}'.format(zone_import_id)
return self.parsed_cmd(cmd, *args, **kwargs)
class RecordsetCommands(object):
def recordset_show(self, zone_id, id, *args, **kwargs):
cmd = 'recordset show {0} {1}'.format(zone_id, id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def recordset_list(self, zone_id, *args, **kwargs):
cmd = 'recordset list {0}'.format(zone_id)
return self.parsed_cmd(cmd, ListModel, *args, **kwargs)
def recordset_create(self, zone_id, name, records=None, type=None,
description=None, ttl=None, *args, **kwargs):
options_str = build_option_string({
'--records': records,
'--type': type,
'--description': description,
'--ttl': ttl,
})
cmd = 'recordset create {0} {1} {2}'.format(zone_id, name, options_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def recordset_set(self, zone_id, id, records=None, type=None,
description=None, ttl=None, no_description=False,
no_ttl=False, *args, **kwargs):
options_str = build_option_string({
'--records': records,
'--type': type,
'--description': description,
'--ttl': ttl,
})
flags_str = build_flags_string({
'--no-description': no_description,
'--no-ttl': no_ttl,
})
cmd = 'recordset set {0} {1} {2} {3}'.format(
zone_id, id, flags_str, options_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def recordset_delete(self, zone_id, id, *args, **kwargs):
cmd = 'recordset delete {0} {1}'.format(zone_id, id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
class TLDCommands(object):
def tld_list(self, *args, **kwargs):
return self.parsed_cmd('tld list', ListModel, *args, **kwargs)
def tld_show(self, id, *args, **kwargs):
return self.parsed_cmd('tld show {0}'.format(id), FieldValueModel,
*args, **kwargs)
def tld_delete(self, id, *args, **kwargs):
return self.parsed_cmd('tld delete {0}'.format(id), *args, **kwargs)
def tld_create(self, name, description=None, *args, **kwargs):
options_str = build_option_string({
'--name': name,
'--description': description,
})
cmd = 'tld create {0}'.format(options_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def tld_set(self, id, name=None, description=None, no_description=False,
*args, **kwargs):
options_str = build_option_string({
'--name': name,
'--description': description,
})
flags_str = build_flags_string({'--no-description': no_description})
cmd = 'tld set {0} {1} {2}'.format(id, options_str, flags_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
class BlacklistCommands(object):
def zone_blacklist_list(self, *args, **kwargs):
cmd = 'zone blacklist list'
return self.parsed_cmd(cmd, ListModel, *args, **kwargs)
def zone_blacklist_create(self, pattern, description=None, *args,
**kwargs):
options_str = build_option_string({
'--pattern': pattern,
'--description': description,
})
cmd = 'zone blacklist create {0}'.format(options_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_blacklist_set(self, id, pattern=None, description=None,
no_description=False, *args, **kwargs):
options_str = build_option_string({
'--pattern': pattern,
'--description': description,
})
flags_str = build_flags_string({'--no-description': no_description})
cmd = 'zone blacklist set {0} {1} {2}'.format(id, options_str,
flags_str)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_blacklist_show(self, id, *args, **kwargs):
cmd = 'zone blacklist show {0}'.format(id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
def zone_blacklist_delete(self, id, *args, **kwargs):
cmd = 'zone blacklist delete {0}'.format(id)
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
class DesignateCLI(base.CLIClient, ZoneCommands, ZoneTransferCommands,
ZoneExportCommands, ZoneImportCommands, RecordsetCommands,
TLDCommands, BlacklistCommands):
# instantiate this once to minimize requests to keystone
_CLIENTS = None
def __init__(self, *args, **kwargs):
super(DesignateCLI, self).__init__(*args, **kwargs)
# grab the project id. this is used for zone transfer requests
resp = FieldValueModel(self.openstack('token issue'))
self.project_id = resp.project_id
@property
def using_auth_override(self):
return bool(cfg.CONF.identity.override_endpoint)
@classmethod
def get_clients(cls):
if not cls._CLIENTS:
cls._init_clients()
return cls._CLIENTS
@classmethod
def _init_clients(cls):
cls._CLIENTS = {
'default': DesignateCLI(
cli_dir=cfg.CONF.designateclient.directory,
username=cfg.CONF.identity.username,
password=cfg.CONF.identity.password,
tenant_name=cfg.CONF.identity.tenant_name,
uri=cfg.CONF.identity.uri,
),
'alt': DesignateCLI(
cli_dir=cfg.CONF.designateclient.directory,
username=cfg.CONF.identity.alt_username,
password=cfg.CONF.identity.alt_password,
tenant_name=cfg.CONF.identity.alt_tenant_name,
uri=cfg.CONF.identity.uri,
),
'admin': DesignateCLI(
cli_dir=cfg.CONF.designateclient.directory,
username=cfg.CONF.identity.admin_username,
password=cfg.CONF.identity.admin_password,
tenant_name=cfg.CONF.identity.admin_tenant_name,
uri=cfg.CONF.identity.uri,
)
}
@classmethod
def as_user(self, user):
clients = self.get_clients()
if user in clients:
return clients[user]
raise Exception("User '{0}' does not exist".format(user))
def parsed_cmd(self, cmd, model=None, *args, **kwargs):
if self.using_auth_override:
# use --os-url and --os-token
func = self._openstack_noauth
else:
# use --os-username --os-tenant-name --os-password --os-auth-url
func = self.openstack
out = func(cmd, *args, **kwargs)
LOG.debug(out)
if model is not None:
return model(out)
return out
def _openstack_noauth(self, cmd, *args, **kwargs):
exe = os.path.join(cfg.CONF.designateclient.directory, 'openstack')
options = build_option_string({
'--os-url': cfg.CONF.identity.override_endpoint,
'--os-token': cfg.CONF.identity.override_token,
})
cmd = options + " " + cmd
return base.execute(exe, cmd, *args, **kwargs)

View File

@@ -1,69 +0,0 @@
"""
Copyright 2015 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import os
from oslo_config import cfg
cfg.CONF.register_group(cfg.OptGroup(
name='identity', title="Configuration for Keystone auth"
))
cfg.CONF.register_group(cfg.OptGroup(
name='designateclient', title="Configuration for the Designate client"
))
cfg.CONF.register_opts([
cfg.StrOpt('uri', help="The Keystone v2 endpoint"),
cfg.StrOpt('uri_v3', help="The Keystone v3 endpoint"),
cfg.StrOpt('auth_version', default='v2'),
cfg.StrOpt('region', default='RegionOne'),
cfg.StrOpt('username'),
cfg.StrOpt('tenant_name'),
cfg.StrOpt('password', secret=True),
cfg.StrOpt('domain_name'),
cfg.StrOpt('alt_username'),
cfg.StrOpt('alt_tenant_name'),
cfg.StrOpt('alt_password', secret=True),
cfg.StrOpt('alt_domain_name'),
cfg.StrOpt('admin_username'),
cfg.StrOpt('admin_tenant_name'),
cfg.StrOpt('admin_password', secret=True),
cfg.StrOpt('admin_domain_name'),
cfg.StrOpt("override_endpoint",
help="use this url instead of the url in the service catalog"),
cfg.StrOpt("override_token",
help="with the override endpoint, pass this token to the api"),
], group='identity')
cfg.CONF.register_opts([
cfg.StrOpt('directory',
help='the directory containing the client executable'),
], group='designateclient')
def find_config_file():
return os.environ.get(
'TEMPEST_CONFIG', '/opt/stack/tempest/etc/tempest.conf')
def read_config():
cfg.CONF(args=[], default_config_files=[find_config_file()])

View File

@@ -1,48 +0,0 @@
"""
Copyright 2015 Rackspace
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
import string
def random_digits(n=8):
return "".join([random.choice(string.digits) for _ in range(n)])
def random_tld(name='testtld'):
return "{0}{1}".format(name, random_digits())
def random_zone_name(name='testdomain', tld='com'):
return "{0}{1}.{2}.".format(name, random_digits(), tld)
def random_a_recordset_name(zone_name, recordset_name='testrecord'):
return "{0}{1}.{2}".format(recordset_name, random_digits(), zone_name)
def random_blacklist(name='testblacklist'):
return '{0}{1}'.format(name, random_digits())
def random_zone_file(name='testzoneimport'):
return "$ORIGIN {0}{1}.com.\n" \
"$TTL 300\n" \
"{0}{1}.com. 300 IN SOA ns.{0}{1}.com. " \
"nsadmin.{0}{1}.com. 42 42 42 42 42\n" \
"{0}{1}.com. 300 IN NS ns.{0}{1}.com.\n" \
"{0}{1}.com. 300 IN MX 10 mail.{0}{1}.com.\n" \
"ns.{0}{1}.com. 300 IN A 10.0.0.1\n" \
"mail.{0}{1}.com. 300 IN A 10.0.0.2\n".format(name, random_digits())

View File

@@ -1,96 +0,0 @@
"""
Copyright 2015 Rackspace
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 six
from tempest.lib.cli import output_parser
class Model(object):
def __str__(self):
return str(self.__dict__)
class FieldValueModel(Model):
"""This converts cli output from messy lists/dicts to neat attributes."""
def __init__(self, out):
"""This parses output with fields and values like:
+----------------+------------------------------+
| Field | Value |
+----------------+------------------------------+
| action | CREATE |
| created_at | 2015-08-20T17:22:17.000000 |
| description | None |
+----------------+------------------------------+
These are then accessible as:
model.action
model.created_at
model.description
"""
table = output_parser.table(out)
# Because the output_parser handles Values with multiple lines
# in additional Field/Value pairs with Field name '', the following
# code is necessary to aggregate Values.
#
# The list of Field/Value pairs is in-order, so we can append Value
# continuation to the previously seen Field, with a newline separator.
value_lines = []
prev_field = None
for field, value in table['values']:
if field == '':
value_lines.append(value)
setattr(self, prev_field, '\n'.join(value_lines))
else:
setattr(self, field, value)
prev_field = field
value_lines = [value]
class ListEntryModel(Model):
def __init__(self, fields, values):
for k, v in six.moves.zip(fields, values):
setattr(self, k, v)
class ListModel(Model, list):
def __init__(self, out):
"""This parses an output table with any number of headers, and any
number of entries:
+--------------------------------------+----------+---------+
| id | name | type |
+--------------------------------------+----------+---------+
| e658a875-1024-4f88-a347-e5b244ec5a10 | aaa.com. | PRIMARY |
+--------------------------------------+----------+---------+
| 98d1fb5f-2954-448e-988e-6f1df0f24c52 | bbb.com. | PRIMARY |
+--------------------------------------+----------+---------+
These are then accessible as:
model[0].name == 'aaa.com.'
model[1].name == 'bbb.com.'
"""
table = output_parser.table(out)
for entry in table['values']:
self.append(ListEntryModel(table['headers'], entry))

View File

@@ -1,213 +0,0 @@
"""
Copyright 2015 Rackspace
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 __future__ import absolute_import
from __future__ import print_function
import sys
import tempfile
import traceback
import fixtures
from tempest.lib.exceptions import CommandFailed
from testtools.runtest import MultipleExceptions
from designateclient.functionaltests.client import DesignateCLI
class BaseFixture(fixtures.Fixture):
def __init__(self, user='default', *args, **kwargs):
"""args/kwargs are forwarded to a create method on DesignateCLI"""
super(BaseFixture, self).__init__()
self.args = args
self.kwargs = kwargs
self.client = DesignateCLI.as_user(user)
def setUp(self):
# Sometimes, exceptions are raised in _setUp methods on fixtures.
# testtools pushes the exception into a MultipleExceptions object along
# with an artificial SetupError, which produces bad error messages.
# This just logs those stack traces to stderr for easier debugging.
try:
super(BaseFixture, self).setUp()
except MultipleExceptions as e:
for i, exc_info in enumerate(e.args):
print('--- printing MultipleExceptions traceback {} of {} ---'
.format(i + 1, len(e.args)), file=sys.stderr)
traceback.print_exception(*exc_info)
raise
class ZoneFixture(BaseFixture):
"""See DesignateCLI.zone_create for __init__ args"""
def _setUp(self):
super(ZoneFixture, self)._setUp()
self.zone = self.client.zone_create(*self.args, **self.kwargs)
self.addCleanup(self.cleanup_zone, self.client, self.zone.id)
@classmethod
def cleanup_zone(cls, client, zone_id):
try:
client.zone_delete(zone_id)
except CommandFailed:
pass
class TransferRequestFixture(BaseFixture):
"""See DesignateCLI.zone_transfer_request_create for __init__ args"""
def __init__(self, zone, user='default', target_user='alt', *args,
**kwargs):
super(TransferRequestFixture, self).__init__(user, *args, **kwargs)
self.zone = zone
self.target_client = DesignateCLI.as_user(target_user)
# the client has a bug such that it requires --target-project-id.
# when this bug is fixed, please remove this
self.kwargs['target_project_id'] = self.target_client.project_id
def _setUp(self):
super(TransferRequestFixture, self)._setUp()
self.transfer_request = self.client.zone_transfer_request_create(
zone_id=self.zone.id,
*self.args, **self.kwargs
)
self.addCleanup(self.cleanup_transfer_request, self.client,
self.transfer_request.id)
self.addCleanup(ZoneFixture.cleanup_zone, self.client, self.zone.id)
self.addCleanup(ZoneFixture.cleanup_zone, self.target_client,
self.zone.id)
@classmethod
def cleanup_transfer_request(cls, client, transfer_request_id):
try:
client.zone_transfer_request_delete(transfer_request_id)
except CommandFailed:
pass
class ExportFixture(BaseFixture):
"""See DesignateCLI.zone_export_create for __init__ args"""
def __init__(self, zone, user='default', *args, **kwargs):
super(ExportFixture, self).__init__(user, *args, **kwargs)
self.zone = zone
def _setUp(self):
super(ExportFixture, self)._setUp()
self.zone_export = self.client.zone_export_create(
zone_id=self.zone.id,
*self.args, **self.kwargs
)
self.addCleanup(self.cleanup_zone_export, self.client,
self.zone_export.id)
self.addCleanup(ZoneFixture.cleanup_zone, self.client, self.zone.id)
@classmethod
def cleanup_zone_export(cls, client, zone_export_id):
try:
client.zone_export_delete(zone_export_id)
except CommandFailed:
pass
class ImportFixture(BaseFixture):
"""See DesignateCLI.zone_import_create for __init__ args"""
def __init__(self, zone_file_contents, user='default', *args, **kwargs):
super(ImportFixture, self).__init__(user, *args, **kwargs)
self.zone_file_contents = zone_file_contents
def _setUp(self):
super(ImportFixture, self)._setUp()
with tempfile.NamedTemporaryFile() as f:
f.write(self.zone_file_contents)
f.flush()
self.zone_import = self.client.zone_import_create(
zone_file_path=f.name,
*self.args, **self.kwargs
)
self.addCleanup(self.cleanup_zone_import, self.client,
self.zone_import.id)
self.addCleanup(ZoneFixture.cleanup_zone, self.client,
self.zone_import.zone_id)
@classmethod
def cleanup_zone_import(cls, client, zone_import_id):
try:
client.zone_import_delete(zone_import_id)
except CommandFailed:
pass
class RecordsetFixture(BaseFixture):
"""See DesignateCLI.recordset_create for __init__ args"""
def _setUp(self):
super(RecordsetFixture, self)._setUp()
self.recordset = self.client.recordset_create(
*self.args, **self.kwargs)
self.addCleanup(self.cleanup_recordset, self.client,
self.recordset.zone_id, self.recordset.id)
@classmethod
def cleanup_recordset(cls, client, zone_id, recordset_id):
try:
client.recordset_delete(zone_id, recordset_id)
except CommandFailed:
pass
class TLDFixture(BaseFixture):
"""See DesignateCLI.tld_create for __init__ args"""
def __init__(self, user='admin', *args, **kwargs):
super(TLDFixture, self).__init__(user=user, *args, **kwargs)
def _setUp(self):
super(TLDFixture, self)._setUp()
self.tld = self.client.tld_create(*self.args, **self.kwargs)
self.addCleanup(self.cleanup_tld, self.client, self.tld.id)
@classmethod
def cleanup_tld(cls, client, tld_id):
try:
client.tld_delete(tld_id)
except CommandFailed:
pass
class BlacklistFixture(BaseFixture):
"""See DesignateCLI.zone_blacklist_create for __init__ args"""
def __init__(self, user='admin', *args, **kwargs):
super(BlacklistFixture, self).__init__(user=user, *args, **kwargs)
def _setUp(self):
super(BlacklistFixture, self)._setUp()
self.blacklist = self.client.zone_blacklist_create(*self.args,
**self.kwargs)
self.addCleanup(self.cleanup_blacklist, self.client, self.blacklist.id)
@classmethod
def cleanup_blacklist(cls, client, blacklist_id):
try:
client.zone_blacklist_delete(blacklist_id)
except CommandFailed:
pass

View File

@@ -1,98 +0,0 @@
"""
Copyright 2015 Rackspace
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 tempest.lib.exceptions import CommandFailed
from designateclient.functionaltests.base import BaseDesignateTest
from designateclient.functionaltests.datagen import random_blacklist
from designateclient.functionaltests.v2.fixtures import BlacklistFixture
class TestBlacklist(BaseDesignateTest):
def setUp(self):
super(TestBlacklist, self).setUp()
pattern = random_blacklist()
self.blacklist = self.useFixture(BlacklistFixture(
pattern=pattern,
description='A random blacklist',
)).blacklist
self.assertEqual(self.blacklist.pattern, pattern)
self.assertEqual(self.blacklist.description, 'A random blacklist')
def test_zone_blacklist_list(self):
blacklists = self.clients.as_user('admin').zone_blacklist_list()
self.assertGreater(len(blacklists), 0)
def test_zone_blacklist_create_and_show(self):
client = self.clients.as_user('admin')
blacklist = client.zone_blacklist_show(self.blacklist.id)
self.assertEqual(self.blacklist.created_at, blacklist.created_at)
self.assertEqual(self.blacklist.description, blacklist.description)
self.assertEqual(self.blacklist.id, blacklist.id)
self.assertEqual(self.blacklist.pattern, blacklist.pattern)
self.assertEqual(self.blacklist.updated_at, blacklist.updated_at)
def test_zone_blacklist_delete(self):
client = self.clients.as_user('admin')
client.zone_blacklist_delete(self.blacklist.id)
self.assertRaises(CommandFailed, client.zone_blacklist_show,
self.blacklist.id)
def test_zone_blacklist_set(self):
client = self.clients.as_user('admin')
updated_pattern = random_blacklist('updatedblacklist')
blacklist = client.zone_blacklist_set(
id=self.blacklist.id,
pattern=updated_pattern,
description='An updated blacklist',
)
self.assertEqual(blacklist.created_at, self.blacklist.created_at)
self.assertEqual(blacklist.description, 'An updated blacklist')
self.assertEqual(blacklist.id, self.blacklist.id)
self.assertEqual(blacklist.pattern, updated_pattern)
self.assertNotEqual(blacklist.updated_at, self.blacklist.updated_at)
def test_zone_blacklist_set_no_description(self):
client = self.clients.as_user('admin')
blacklist = client.zone_blacklist_set(
id=self.blacklist.id,
no_description=True,
)
self.assertEqual(blacklist.description, 'None')
def test_cannot_set_description_with_no_description_flag(self):
client = self.clients.as_user('admin')
self.assertRaises(CommandFailed, client.zone_blacklist_set,
self.blacklist.id,
pattern=random_blacklist(),
description='new description',
no_description=True)
class TestBlacklistNegative(BaseDesignateTest):
def test_invalid_blacklist_command(self):
client = self.clients.as_user('admin')
cmd = 'zone blacklist notacommand'
self.assertRaises(CommandFailed, client.openstack, cmd)
def test_blacklist_create_invalid_flag(self):
client = self.clients.as_user('admin')
cmd = 'zone blacklist create --pattern helloworld --notaflag invalid'
self.assertRaises(CommandFailed, client.openstack, cmd)

View File

@@ -1,111 +0,0 @@
"""
Copyright 2015 Rackspace
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 tempest.lib.exceptions import CommandFailed
from designateclient.functionaltests.base import BaseDesignateTest
from designateclient.functionaltests.datagen import random_a_recordset_name
from designateclient.functionaltests.datagen import random_zone_name
from designateclient.functionaltests.v2.fixtures import RecordsetFixture
from designateclient.functionaltests.v2.fixtures import ZoneFixture
class TestRecordset(BaseDesignateTest):
def setUp(self):
super(TestRecordset, self).setUp()
self.ensure_tld_exists('com')
self.zone = self.useFixture(ZoneFixture(
name=random_zone_name(),
email='test@example.com',
)).zone
name = random_a_recordset_name(self.zone.name)
self.recordset = self.useFixture(RecordsetFixture(
zone_id=self.zone.id,
name=name,
records='1.2.3.4',
description='An a recordset',
type='A',
ttl=1234,
)).recordset
self.assertEqual(self.recordset.name, name)
self.assertEqual(self.recordset.records, '1.2.3.4')
self.assertEqual(self.recordset.description, 'An a recordset')
self.assertEqual(self.recordset.type, 'A')
self.assertEqual(self.recordset.ttl, '1234')
def test_recordset_list(self):
rsets = self.clients.recordset_list(self.zone.id)
self.assertGreater(len(rsets), 0)
def test_recordset_create_and_show(self):
rset = self.clients.recordset_show(self.zone.id, self.recordset.id)
self.assertTrue(hasattr(self.recordset, 'action'))
self.assertTrue(hasattr(rset, 'action'))
self.assertEqual(self.recordset.created_at, rset.created_at)
self.assertEqual(self.recordset.description, rset.description)
self.assertEqual(self.recordset.id, rset.id)
self.assertEqual(self.recordset.name, rset.name)
self.assertEqual(self.recordset.records, rset.records)
self.assertEqual(self.recordset.status, rset.status)
self.assertEqual(self.recordset.ttl, rset.ttl)
self.assertEqual(self.recordset.type, rset.type)
self.assertEqual(self.recordset.updated_at, rset.updated_at)
self.assertEqual(self.recordset.version, rset.version)
self.assertEqual(self.recordset.zone_id, self.zone.id)
def test_recordset_delete(self):
rset = self.clients.recordset_delete(self.zone.id, self.recordset.id)
self.assertEqual(rset.action, 'DELETE')
self.assertEqual(rset.status, 'PENDING')
def test_recordset_set(self):
rset = self.clients.recordset_set(
self.zone.id,
self.recordset.id,
records='2.3.4.5',
ttl=2345,
description='Updated description',
)
self.assertEqual(rset.records, '2.3.4.5')
self.assertEqual(rset.ttl, '2345')
self.assertEqual(rset.description, 'Updated description')
def test_recordset_set_clear_ttl_and_description(self):
rset = self.clients.recordset_set(
self.zone.id,
self.recordset.id,
no_description=True,
no_ttl=True,
)
self.assertEqual(rset.description, 'None')
self.assertEqual(rset.ttl, 'None')
class TestRecordsetNegative(BaseDesignateTest):
def test_invalid_option_on_recordset_create(self):
cmd = 'recordset create de47d30b-41c5-4e38-b2c5-e0b908e19ec7 ' \
'aaa.desig.com. --type A --records 1.2.3.4 ' \
'--invalid "not valid"'
self.assertRaises(CommandFailed, self.clients.openstack, cmd)
def test_invalid_recordset_command(self):
cmd = 'recordset hopefullynotvalid'
self.assertRaises(CommandFailed, self.clients.openstack, cmd)

View File

@@ -1,82 +0,0 @@
"""
Copyright 2015 Rackspace
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 tempest.lib.exceptions import CommandFailed
from designateclient.functionaltests.base import BaseDesignateTest
from designateclient.functionaltests.datagen import random_tld
from designateclient.functionaltests.v2.fixtures import TLDFixture
class TestTld(BaseDesignateTest):
def setUp(self):
super(TestTld, self).setUp()
tld_name = random_tld()
self.tld = self.useFixture(TLDFixture(
name=tld_name,
description='A random tld',
)).tld
self.assertEqual(self.tld.name, tld_name)
self.assertEqual(self.tld.description, 'A random tld')
def test_tld_list(self):
tlds = self.clients.as_user('admin').tld_list()
self.assertGreater(len(tlds), 0)
def test_tld_create_and_show(self):
tld = self.clients.as_user('admin').tld_show(self.tld.id)
self.assertEqual(tld.name, self.tld.name)
self.assertEqual(tld.created_at, self.tld.created_at)
self.assertEqual(tld.id, self.tld.id)
self.assertEqual(tld.name, self.tld.name)
self.assertEqual(tld.updated_at, self.tld.updated_at)
def test_tld_delete(self):
client = self.clients.as_user('admin')
client.tld_delete(self.tld.id)
self.assertRaises(CommandFailed, client.tld_show, self.tld.id)
def test_tld_set(self):
client = self.clients.as_user('admin')
updated_name = random_tld('updated')
tld = client.tld_set(self.tld.id, name=updated_name,
description='An updated tld')
self.assertEqual(tld.description, 'An updated tld')
self.assertEqual(tld.name, updated_name)
def test_tld_set_no_description(self):
client = self.clients.as_user('admin')
tld = client.tld_set(self.tld.id, no_description=True)
self.assertEqual(tld.description, 'None')
def test_no_set_tld_with_description_and_no_description(self):
client = self.clients.as_user('admin')
self.assertRaises(CommandFailed, client.tld_set, self.tld.id,
description='An updated tld',
no_description=True)
class TestTldNegative(BaseDesignateTest):
def test_tld_invalid_commmand(self):
client = self.clients.as_user('admin')
self.assertRaises(CommandFailed, client.openstack, 'tld notacommand')
def test_tld_create_invalid_flag(self):
client = self.clients.as_user('admin')
self.assertRaises(CommandFailed, client.openstack,
'tld create --notanoption "junk"')

View File

@@ -1,130 +0,0 @@
"""
Copyright 2015 Rackspace
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 tempest.lib.exceptions import CommandFailed
from designateclient.functionaltests.base import BaseDesignateTest
from designateclient.functionaltests.datagen import random_zone_name
from designateclient.functionaltests.v2.fixtures import ZoneFixture
class TestZone(BaseDesignateTest):
def setUp(self):
super(TestZone, self).setUp()
self.ensure_tld_exists('com')
self.fixture = self.useFixture(ZoneFixture(
name=random_zone_name(),
email='test@example.com',
))
self.zone = self.fixture.zone
def test_zone_list(self):
zones = self.clients.zone_list()
self.assertGreater(len(zones), 0)
def test_zone_create_and_show(self):
zone = self.clients.zone_show(self.zone.id)
self.assertTrue(hasattr(zone, 'action'))
self.assertEqual(self.zone.created_at, zone.created_at)
self.assertEqual(self.zone.description, zone.description)
self.assertEqual(self.zone.email, zone.email)
self.assertEqual(self.zone.id, zone.id)
self.assertEqual(self.zone.masters, zone.masters)
self.assertEqual(self.zone.name, zone.name)
self.assertEqual(self.zone.pool_id, zone.pool_id)
self.assertEqual(self.zone.project_id, zone.project_id)
self.assertEqual(self.zone.serial, zone.serial)
self.assertTrue(hasattr(zone, 'status'))
self.assertEqual(self.zone.transferred_at, zone.transferred_at)
self.assertEqual(self.zone.ttl, zone.ttl)
self.assertEqual(self.zone.type, zone.type)
self.assertEqual(self.zone.updated_at, zone.updated_at)
self.assertEqual(self.zone.version, zone.version)
def test_zone_delete(self):
zone = self.clients.zone_delete(self.zone.id)
self.assertEqual(zone.action, 'DELETE')
self.assertEqual(zone.status, 'PENDING')
def test_zone_set(self):
ttl = int(self.zone.ttl) + 123
email = 'updated{0}'.format(self.zone.email)
description = 'new description'
zone = self.clients.zone_set(self.zone.id, ttl=ttl, email=email,
description=description)
self.assertEqual(ttl, int(zone.ttl))
self.assertEqual(email, zone.email)
self.assertEqual(description, zone.description)
def test_invalid_option_on_zone_create(self):
cmd = 'zone create %s --invalid "not a valid option"'.format(
random_zone_name())
self.assertRaises(CommandFailed, self.clients.openstack, cmd)
def test_invalid_zone_command(self):
cmd = 'zone hopefullynotacommand'
self.assertRaises(CommandFailed, self.clients.openstack, cmd)
class TestsPassingZoneFlags(BaseDesignateTest):
def setUp(self):
super(TestsPassingZoneFlags, self).setUp()
self.ensure_tld_exists('com')
def test_zone_create_primary_with_all_args(self):
zone_name = random_zone_name()
fixture = self.useFixture(ZoneFixture(
name=zone_name,
email='primary@example.com',
description='A primary zone',
ttl=2345,
type='PRIMARY',
))
zone = fixture.zone
self.assertEqual(zone_name, zone.name)
self.assertEqual('primary@example.com', zone.email)
self.assertEqual('A primary zone', zone.description)
self.assertEqual('2345', zone.ttl)
self.assertEqual('PRIMARY', zone.type)
def test_zone_create_secondary_with_all_args(self):
zone_name = random_zone_name()
fixture = self.useFixture(ZoneFixture(
name=zone_name,
description='A secondary zone',
type='SECONDARY',
masters='127.0.0.1',
))
zone = fixture.zone
self.assertEqual(zone_name, zone.name)
self.assertEqual('A secondary zone', zone.description)
self.assertEqual('SECONDARY', zone.type)
self.assertEqual('127.0.0.1', zone.masters)
def test_zone_set_secondary_masters(self):
fixture = self.useFixture(ZoneFixture(
name=random_zone_name(),
description='A secondary zone',
type='SECONDARY',
masters='127.0.0.1',
))
zone = fixture.zone
self.assertEqual('127.0.0.1', zone.masters)
zone = self.clients.zone_set(zone.id, masters='127.0.0.2')
self.assertEqual('127.0.0.2', zone.masters)

View File

@@ -1,81 +0,0 @@
"""
Copyright 2016 Rackspace
Author: Rahman Syed <rahman.syed@gmail.com>
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 designateclient.functionaltests.base import BaseDesignateTest
from designateclient.functionaltests.datagen import random_zone_name
from designateclient.functionaltests.v2.fixtures import ExportFixture
from designateclient.functionaltests.v2.fixtures import ZoneFixture
class TestZoneExport(BaseDesignateTest):
def setUp(self):
super(TestZoneExport, self).setUp()
self.ensure_tld_exists('com')
fixture = self.useFixture(ZoneFixture(
name=random_zone_name(),
email='test@example.com',
))
self.zone = fixture.zone
def test_list_zone_exports(self):
zone_export = self.useFixture(ExportFixture(
zone=self.zone
)).zone_export
zone_exports = self.clients.zone_export_list()
self.assertGreater(len(zone_exports), 0)
self.assertTrue(self._is_entity_in_list(zone_export, zone_exports))
def test_create_and_show_zone_export(self):
zone_export = self.useFixture(ExportFixture(
zone=self.zone
)).zone_export
fetched_export = self.clients.zone_export_show(zone_export.id)
self.assertEqual(zone_export.created_at, fetched_export.created_at)
self.assertEqual(zone_export.id, fetched_export.id)
self.assertEqual(zone_export.message, fetched_export.message)
self.assertEqual(zone_export.project_id, fetched_export.project_id)
self.assertEqual(zone_export.zone_id, fetched_export.zone_id)
def test_delete_zone_export(self):
zone_export = self.useFixture(ExportFixture(
zone=self.zone
)).zone_export
zone_exports = self.clients.zone_export_list()
self.assertTrue(self._is_entity_in_list(zone_export, zone_exports))
self.clients.zone_export_delete(zone_export.id)
zone_exports = self.clients.zone_export_list()
self.assertFalse(self._is_entity_in_list(zone_export, zone_exports))
def test_show_export_file(self):
zone_export = self.useFixture(ExportFixture(
zone=self.zone
)).zone_export
fetched_export = self.clients.zone_export_showfile(zone_export.id)
self.assertIn('$ORIGIN', fetched_export.data)
self.assertIn('$TTL', fetched_export.data)
self.assertIn('SOA', fetched_export.data)
self.assertIn('NS', fetched_export.data)
self.assertIn(self.zone.name, fetched_export.data)

View File

@@ -1,65 +0,0 @@
"""
Copyright 2016 Rackspace
Author: Rahman Syed <rahman.syed@gmail.com>
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 designateclient.functionaltests.base import BaseDesignateTest
from designateclient.functionaltests.datagen import random_zone_file
from designateclient.functionaltests.v2.fixtures import ImportFixture
class TestZoneImport(BaseDesignateTest):
def setUp(self):
super(TestZoneImport, self).setUp()
self.ensure_tld_exists('com')
self.zone_file_contents = random_zone_file()
def test_list_zone_imports(self):
zone_import = self.useFixture(ImportFixture(
zone_file_contents=self.zone_file_contents
)).zone_import
zone_imports = self.clients.zone_import_list()
self.assertGreater(len(zone_imports), 0)
self.assertTrue(self._is_entity_in_list(zone_import, zone_imports))
def test_create_and_show_zone_import(self):
zone_import = self.useFixture(ImportFixture(
zone_file_contents=self.zone_file_contents
)).zone_import
fetched_import = self.clients.zone_import_show(zone_import.id)
self.assertEqual(zone_import.created_at, fetched_import.created_at)
self.assertEqual(zone_import.id, fetched_import.id)
self.assertEqual(zone_import.project_id, fetched_import.project_id)
# check both statuses to avoid a race condition, causing test failure.
# we don't know when the import completes.
self.assertIn(fetched_import.status, ['PENDING', 'COMPLETE'])
def test_delete_zone_import(self):
zone_import = self.useFixture(ImportFixture(
zone_file_contents=self.zone_file_contents
)).zone_import
zone_imports = self.clients.zone_import_list()
self.assertTrue(self._is_entity_in_list(zone_import, zone_imports))
self.clients.zone_import_delete(zone_import.id)
zone_imports = self.clients.zone_import_list()
self.assertFalse(self._is_entity_in_list(zone_import, zone_imports))

View File

@@ -1,118 +0,0 @@
"""
Copyright 2015 Rackspace
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 unittest
from tempest.lib.exceptions import CommandFailed
from designateclient.functionaltests.base import BaseDesignateTest
from designateclient.functionaltests.client import DesignateCLI
from designateclient.functionaltests.datagen import random_zone_name
from designateclient.functionaltests.v2.fixtures import TransferRequestFixture
from designateclient.functionaltests.v2.fixtures import ZoneFixture
class TestZoneTransferRequest(BaseDesignateTest):
def setUp(self):
super(TestZoneTransferRequest, self).setUp()
self.ensure_tld_exists('com')
fixture = self.useFixture(ZoneFixture(
name=random_zone_name(),
email='test@example.com',
))
self.zone = fixture.zone
def test_list_zone_transfer_request(self):
self.useFixture(TransferRequestFixture(self.zone))
xfrs = self.clients.zone_transfer_request_list()
self.assertGreater(len(xfrs), 0)
def test_create_and_show_zone_transfer_request(self):
transfer_request = self.useFixture(TransferRequestFixture(
zone=self.zone,
user='default',
target_user='alt',
)).transfer_request
fetched_xfr = self.clients.zone_transfer_request_show(
transfer_request.id)
self.assertEqual(fetched_xfr.created_at, transfer_request.created_at)
self.assertEqual(fetched_xfr.description, transfer_request.description)
self.assertEqual(fetched_xfr.id, transfer_request.id)
self.assertEqual(fetched_xfr.key, transfer_request.key)
self.assertEqual(fetched_xfr.links, transfer_request.links)
self.assertEqual(fetched_xfr.target_project_id,
transfer_request.target_project_id)
self.assertEqual(fetched_xfr.updated_at, transfer_request.updated_at)
self.assertEqual(fetched_xfr.status, transfer_request.status)
self.assertEqual(fetched_xfr.zone_id, self.zone.id)
self.assertEqual(fetched_xfr.zone_name, self.zone.name)
def test_delete_zone_transfer_request(self):
transfer_request = self.useFixture(TransferRequestFixture(
zone=self.zone,
user='default',
target_user='alt',
)).transfer_request
self.clients.zone_transfer_request_delete(transfer_request.id)
self.assertRaises(CommandFailed,
self.clients.zone_transfer_request_show,
transfer_request.id)
@unittest.skip("Fails because `zone transfer request set` returns nothing")
def test_set_zone_transfer_request(self):
transfer_request = self.useFixture(TransferRequestFixture(
zone=self.zone,
description="old description",
)).transfer_request
self.assertEqual(transfer_request.description, "old description")
updated_xfr = self.clients.zone_transfer_request_set(
transfer_request.id,
description="updated description")
self.assertEqual(updated_xfr.description, "updated description")
class TestZoneTransferAccept(BaseDesignateTest):
def setUp(self):
super(TestZoneTransferAccept, self).setUp()
self.ensure_tld_exists('com')
fixture = self.useFixture(ZoneFixture(
name=random_zone_name(),
email='test@example.com',
))
self.zone = fixture.zone
self.target_client = DesignateCLI.as_user('alt')
fixture = self.useFixture(TransferRequestFixture(
zone=self.zone,
user='default',
target_user='alt',
target_project_id=self.target_client.project_id,
))
self.transfer_request = fixture.transfer_request
def test_zone_transfer_accept_request(self):
self.target_client.zone_transfer_accept_request(
id=self.transfer_request.id,
key=self.transfer_request.key,
)
self.target_client.zone_show(self.zone.id)
self.assertRaises(CommandFailed, self.clients.zone_show, self.zone.id)

View File

@@ -1,53 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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.
"""OpenStackClient plugin for DNS service."""
from osc_lib import utils as oscutils
from designateclient import shell
DEFAULT_API_VERSION = '2'
API_NAME = 'dns'
API_VERSION_OPTION = 'os_dns_api_version'
API_VERSIONS = {
'2': 'designateclient.v2.client.Client',
}
def make_client(instance):
cls = oscutils.get_client_class(
API_NAME, instance._api_version[API_NAME],
API_VERSIONS)
kwargs = oscutils.build_kwargs_dict('endpoint_type', instance._interface)
return cls(session=instance.session,
region_name=instance._region_name, **kwargs)
def build_option_parser(parser):
"""Hook to add global options."""
parser.add_argument(
'--os-dns-api-version',
metavar='<dns-api-version>',
default=shell.env('OS_DNS_API_VERSION', default="2"),
help='DNS API version, default=' +
DEFAULT_API_VERSION +
' (Env: OS_DNS_API_VERSION)')
return parser

View File

@@ -1,76 +0,0 @@
{
"id": "domain",
"$schema": "http://json-schema.org/draft-03/hyper-schema",
"title": "domain",
"description": "Domain",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Domain Identifier",
"pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$",
"readonly": true
},
"name": {
"type": "string",
"description": "Domain name",
"format": "domain-name",
"maxLength": 255,
"required": true,
"readonly": true
},
"email": {
"type": "string",
"description": "Hostmaster email address",
"format": "email",
"maxLength": 255,
"required": true
},
"ttl": {
"type": "integer",
"description": "Time to live",
"minimum": 1,
"maximum": 2147483647
},
"serial": {
"type": "integer",
"description": "Serial Number",
"minimum": 1,
"maximum": 4294967295,
"readonly": true
},
"description": {
"type": ["string", "null"],
"description": "Description for the Domain",
"maxLength": 160
},
"created_at": {
"type": "string",
"description": "Date and time of domain creation",
"format": "date-time",
"readonly": true
},
"updated_at": {
"type": ["string", "null"],
"description": "Date and time of last domain update",
"format": "date-time",
"readonly": true
}
},
"links": [{
"rel": "self",
"href": "/domains/{id}"
}, {
"rel": "records",
"href": "/domains/{id}/records"
}, {
"rel": "servers",
"href": "/domains/{id}/servers"
}, {
"rel": "collection",
"href": "/domains"
}]
}

View File

@@ -1,246 +0,0 @@
{
"id": "record",
"$schema": "http://json-schema.org/draft-03/hyper-schema",
"title": "record",
"description": "Record",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Record Identifier",
"pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$",
"readonly": true
},
"domain_id": {
"type": "string",
"description": "Domain Identifier",
"pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$",
"readonly": true
},
"name": {
"type": "string",
"description": "DNS Record Name",
"format": "host-name",
"maxLength": 255,
"required": true
},
"type": {
"type": "string",
"description": "DNS Record Type",
"enum": ["A", "AAAA", "CNAME", "MX", "SRV", "TXT", "SPF", "NS", "PTR", "SSHFP", "SOA"],
"required": true
},
"data": {
"type": "string",
"description": "DNS Record Value",
"maxLength": 255,
"required": true
},
"priority": {
"type": ["integer", "null"],
"description": "DNS Record Priority",
"minimum": 0,
"maximum": 65535
},
"ttl": {
"type": ["integer", "null"],
"description": "Time to live",
"minimum": 1,
"maximum": 2147483647
},
"description": {
"type": ["string", "null"],
"description": "Description for the record",
"maxLength": 160
},
"created_at": {
"type": "string",
"description": "Date and time of record creation",
"format": "date-time",
"readonly": true
},
"updated_at": {
"type": ["string", "null"],
"description": "Date and time of last record update",
"format": "date-time",
"readonly": true
}
},
"oneOf": [{
"description": "An A Record",
"properties": {
"type": {
"type": "string",
"enum": ["A"]
},
"data": {
"format": "ip-address",
"required": true
},
"priority": {
"type": "null"
}
}
}, {
"description": "An AAAA Record",
"properties": {
"type": {
"type": "string",
"enum": ["AAAA"]
},
"data": {
"format": "ipv6",
"required": true
},
"priority": {
"type": "null"
}
}
}, {
"description": "A CNAME Record",
"properties": {
"type": {
"type": "string",
"enum": ["CNAME"]
},
"data": {
"format": "host-name",
"required": true
},
"priority": {
"type": "null"
}
}
}, {
"description": "A MX Record",
"properties": {
"type": {
"type": "string",
"enum": ["MX"]
},
"data": {
"format": "host-name",
"required": true
},
"priority": {
"type": "integer",
"required": true
}
}
}, {
"description": "A SRV Record",
"properties": {
"type": {
"type": "string",
"enum": ["SRV"]
},
"name": {
"type": "string",
"pattern": "^(?:_[A-Za-z0-9_\\-]{1,62}\\.){2}"
},
"data": {
"type": "string",
"pattern": "^(?:(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])\\s){2}(?!.{255,})((?!\\-)[A-Za-z0-9_\\-]{1,63}(?<!\\-)\\.)+$"
},
"priority": {
"type": "integer",
"required": true
}
}
}, {
"description": "A TXT Record",
"properties": {
"type": {
"type": "string",
"enum": ["TXT"]
},
"priority": {
"type": "null"
}
}
}, {
"description": "A SPF Record",
"properties": {
"type": {
"type": "string",
"enum": ["SPF"]
},
"priority": {
"type": "null"
}
}
}, {
"description": "A NS Record",
"properties": {
"type": {
"type": "string",
"enum": ["NS"]
},
"data": {
"format": "host-name",
"required": true
},
"priority": {
"type": "null"
}
}
}, {
"description": "A PTR Record",
"properties": {
"type": {
"type": "string",
"enum": ["PTR"]
},
"name": {
"type": "string",
"pattern": "^(?:(?:\\d{1,3}\\.){4}in-addr\\.arpa\\.|(?:[a-f|\\d]\\.){32}ip6\\.arpa\\.)$"
},
"data": {
"format": "host-name",
"required": true
},
"priority": {
"type": "null"
}
}
}, {
"description": "A SSHFP Record",
"properties": {
"type": {
"type": "string",
"enum": ["SSHFP"]
},
"data": {
"pattern": "^[1-2] 1 [0-9A-Fa-f]{40}$",
"required": true
},
"priority": {
"type": "null"
}
}
}, {
"description": "A SOA Record",
"properties": {
"type": {
"type": "string",
"enum": ["SOA"]
},
"priority": {
"type": "null"
}
}
}],
"links": [{
"rel": "self",
"href": "/domains/{domain_id}/records/{id}"
}, {
"rel": "domain",
"href": "/domains/{domain_id}"
}, {
"rel": "collection",
"href": "/domains/{domain_id}/records"
}]
}

View File

@@ -1,44 +0,0 @@
{
"id": "server",
"$schema": "http://json-schema.org/draft-03/hyper-schema",
"title": "server",
"description": "Server",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Server Identifier",
"pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$",
"readonly": true
},
"name": {
"type": "string",
"description": "Server DNS name",
"format": "host-name",
"maxLength": 255,
"required": true
},
"created_at": {
"type": "string",
"description": "Date and time of server creation",
"format": "date-time",
"readonly": true
},
"updated_at": {
"type": ["string", "null"],
"description": "Date and time of last server update",
"format": "date-time",
"readonly": true
}
},
"links": [{
"rel": "self",
"href": "/servers/{id}"
}, {
"rel": "collection",
"href": "/servers"
}]
}

View File

@@ -1,252 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 logging
import os
import traceback
from cliff.app import App
from cliff.commandmanager import CommandManager
from designateclient import utils
from designateclient.version import version_info as version
def env(*vars, **kwargs):
"""Search for the first defined of possibly many env vars
Returns the first environment variable defined in vars, or
returns the default defined in kwargs.
"""
for v in vars:
value = os.environ.get(v)
if value:
return value
return kwargs.get('default', '')
class DesignateShell(App):
CONSOLE_MESSAGE_FORMAT = '%(levelname)s: %(message)s'
DEFAULT_VERBOSE_LEVEL = 0
def __init__(self):
super(DesignateShell, self).__init__(
description='Designate Client',
version=version.version_string(),
command_manager=CommandManager('designateclient.cli'),
)
self.log = logging.getLogger(__name__)
def build_option_parser(self, description, version):
parser = super(DesignateShell, self).build_option_parser(
description, version)
parser.add_argument('--os-username',
default=env('OS_USERNAME'),
help='Name used for authentication with the '
'OpenStack Identity service. '
'Defaults to env[OS_USERNAME].')
parser.add_argument('--os-user-id',
default=env('OS_USER_ID'),
help='User ID used for authentication with the '
'OpenStack Identity service. '
'Defaults to env[OS_USER_ID].')
parser.add_argument('--os-user-domain-id',
default=env('OS_USER_DOMAIN_ID'),
help='Defaults to env[OS_USER_DOMAIN_ID].')
parser.add_argument('--os-user-domain-name',
default=env('OS_USER_DOMAIN_NAME'),
help='Defaults to env[OS_USER_DOMAIN_NAME].')
parser.add_argument('--os-password',
default=env('OS_PASSWORD'),
help='Password used for authentication with the '
'OpenStack Identity service. '
'Defaults to env[OS_PASSWORD].')
parser.add_argument('--os-tenant-name',
default=env('OS_TENANT_NAME'),
help='Tenant to request authorization on. '
'Defaults to env[OS_TENANT_NAME].')
parser.add_argument('--os-tenant-id',
default=env('OS_TENANT_ID'),
help='Tenant to request authorization on. '
'Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os-project-name',
default=env('OS_PROJECT_NAME'),
help='Project to request authorization on. '
'Defaults to env[OS_PROJECT_NAME].')
parser.add_argument('--os-domain-name',
default=env('OS_DOMAIN_NAME'),
help='Project to request authorization on. '
'Defaults to env[OS_DOMAIN_NAME].')
parser.add_argument('--os-domain-id',
default=env('OS_DOMAIN_ID'),
help='Defaults to env[OS_DOMAIN_ID].')
parser.add_argument('--os-project-id',
default=env('OS_PROJECT_ID'),
help='Project to request authorization on. '
'Defaults to env[OS_PROJECT_ID].')
parser.add_argument('--os-project-domain-id',
default=env('OS_PROJECT_DOMAIN_ID'),
help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
parser.add_argument('--os-project-domain-name',
default=env('OS_PROJECT_DOMAIN_NAME'),
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
parser.add_argument('--os-auth-url',
default=env('OS_AUTH_URL'),
help='Specify the Identity endpoint to use for '
'authentication. '
'Defaults to env[OS_AUTH_URL].')
parser.add_argument('--os-region-name',
default=env('OS_REGION_NAME'),
help='Specify the region to use. '
'Defaults to env[OS_REGION_NAME].')
parser.add_argument('--os-token',
default=env('OS_SERVICE_TOKEN'),
help='Specify an existing token to use instead of '
'retrieving one via authentication (e.g. '
'with username & password). '
'Defaults to env[OS_SERVICE_TOKEN].')
parser.add_argument('--os-endpoint',
default=env('OS_DNS_ENDPOINT',
'OS_SERVICE_ENDPOINT'),
help='Specify an endpoint to use instead of '
'retrieving one from the service catalog '
'(via authentication). '
'Defaults to env[OS_DNS_ENDPOINT].')
parser.add_argument('--os-endpoint-type',
default=env('OS_ENDPOINT_TYPE',
default='publicURL'),
help='Defaults to env[OS_ENDPOINT_TYPE].')
parser.add_argument('--os-service-type',
default=env('OS_DNS_SERVICE_TYPE', default='dns'),
help=("Defaults to env[OS_DNS_SERVICE_TYPE], or "
"'dns'."))
parser.add_argument('--os-cacert',
default=env('OS_CACERT'),
help=('CA certificate bundle file. Defaults to '
'env[OS_CACERT].'))
parser.add_argument('--insecure', action='store_true',
help="Explicitly allow 'insecure' SSL requests.")
parser.add_argument('--all-tenants', action='store_true',
help="Allows to list all domains from all "
"tenants.")
parser.add_argument('--edit-managed', action='store_true',
help='Allows to edit records that are marked as '
'managed.')
return parser
def configure_logging(self):
"""Configure logging for the app
Cliff sets some defaults we don't want so re-work it a bit
"""
if self.options.debug:
# --debug forces verbose_level 3
# Set this here so cliff.app.configure_logging() can work
self.options.verbose_level = 3
super(DesignateShell, self).configure_logging()
root_logger = logging.getLogger('')
# Requests logs some stuff at INFO that we don't want
# unless we have DEBUG
requests_log = logging.getLogger("requests")
requests_log.setLevel(logging.ERROR)
# Other modules we don't want DEBUG output for so
# don't reset them below
iso8601_log = logging.getLogger("iso8601")
iso8601_log.setLevel(logging.ERROR)
# Set logging to the requested level
self.dump_stack_trace = False
if self.options.verbose_level == 0:
# --quiet
root_logger.setLevel(logging.ERROR)
elif self.options.verbose_level == 1:
# This is the default case, no --debug, --verbose or --quiet
root_logger.setLevel(logging.WARNING)
elif self.options.verbose_level == 2:
# One --verbose
root_logger.setLevel(logging.INFO)
elif self.options.verbose_level >= 3:
# Two or more --verbose
root_logger.setLevel(logging.DEBUG)
requests_log.setLevel(logging.DEBUG)
if self.options.debug:
# --debug forces traceback
self.dump_stack_trace = True
def initialize_app(self, argv):
super(DesignateShell, self).initialize_app(argv)
self.session = utils.get_session(
auth_url=self.options.os_auth_url,
endpoint=self.options.os_endpoint,
domain_id=self.options.os_domain_id,
domain_name=self.options.os_domain_name,
project_id=self.options.os_project_id or self.options.os_tenant_id,
project_name=(self.options.os_project_name or
self.options.os_tenant_name),
project_domain_name=self.options.os_project_domain_name,
project_domain_id=self.options.os_project_domain_id,
username=self.options.os_username,
user_id=self.options.os_user_id,
password=self.options.os_password,
user_domain_id=self.options.os_user_domain_id,
user_domain_name=self.options.os_user_domain_name,
token=self.options.os_token,
insecure=self.options.insecure,
cacert=self.options.os_cacert
)
def run(self, argv):
try:
return super(DesignateShell, self).run(argv)
except Exception as e:
if not logging.getLogger('').handlers:
logging.basicConfig()
if self.dump_stack_trace:
self.log.error(traceback.format_exc(e))
else:
self.log.error('Exception raised: ' + str(e))
return 1

View File

@@ -1,144 +0,0 @@
# Copyright 2010-2011 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json as json_
import os
import fixtures
from keystoneauth1 import session as keystone_session
from oslotest import base as test
from requests_mock.contrib import fixture as req_fixture
import six
from six.moves.urllib import parse as urlparse
from designateclient import client
from designateclient.utils import AdapterWithTimeout
_TRUE_VALUES = ('True', 'true', '1', 'yes')
class TestCase(test.BaseTestCase):
"""Test case base class for all unit tests."""
def setUp(self):
"""Run before each test method to initialize test environment."""
super(TestCase, self).setUp()
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
try:
test_timeout = int(test_timeout)
except ValueError:
# If timeout value is invalid do not set a timeout.
test_timeout = 0
if test_timeout > 0:
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
self.useFixture(fixtures.NestedTempfile())
self.useFixture(fixtures.TempHomeDir())
if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES:
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES:
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
self.log_fixture = self.useFixture(fixtures.FakeLogger())
class APITestCase(TestCase):
"""Test case base class for all unit tests."""
TEST_URL = "http://127.0.0.1:9001/"
VERSION = None
def setUp(self):
"""Run before each test method to initialize test environment."""
super(TestCase, self).setUp()
self.log_fixture = self.useFixture(fixtures.FakeLogger())
self.requests = self.useFixture(req_fixture.Fixture())
self.client = self.get_client()
def get_base(self, base_url=None):
if not base_url:
base_url = '%sv%s' % (self.TEST_URL, self.VERSION)
return base_url
def stub_url(self, method, parts=None, base_url=None, json=None, **kwargs):
base_url = self.get_base(base_url)
if json:
kwargs['text'] = json_.dumps(json)
headers = kwargs.setdefault('headers', {})
headers['Content-Type'] = 'application/json'
if parts:
url = '/'.join([p.strip('/') for p in [base_url] + parts])
else:
url = base_url
url = url.replace("/?", "?")
self.requests.register_uri(method, url, **kwargs)
def get_client(self, version=None, session=None):
version = version or self.VERSION
session = session or keystone_session.Session()
adapted = AdapterWithTimeout(
session=session, endpoint_override=self.get_base())
return client.Client(version, session=adapted)
def assertRequestBodyIs(self, body=None, json=None):
last_request_body = self.requests.last_request.body
if json:
val = json_.loads(last_request_body)
self.assertEqual(json, val)
elif body:
self.assertEqual(body, last_request_body)
def assertQueryStringIs(self, qs=''):
"""Verify the QueryString matches what is expected.
The qs parameter should be of the format \'foo=bar&abc=xyz\'
"""
expected = urlparse.parse_qs(qs, keep_blank_values=True)
parts = urlparse.urlparse(self.requests.last_request.url)
querystring = urlparse.parse_qs(parts.query, keep_blank_values=True)
self.assertEqual(expected, querystring)
def assertQueryStringContains(self, **kwargs):
"""Verify the query string contains the expected parameters.
This method is used to verify that the query string for the most recent
request made contains all the parameters provided as ``kwargs``, and
that the value of each parameter contains the value for the kwarg. If
the value for the kwarg is an empty string (''), then all that's
verified is that the parameter is present.
"""
parts = urlparse.urlparse(self.requests.last_request.url)
qs = urlparse.parse_qs(parts.query, keep_blank_values=True)
for k, v in six.iteritems(kwargs):
self.assertIn(k, qs)
self.assertIn(v, qs[k])
def assertRequestHeaderEqual(self, name, val):
"""Verify that the last request made contains a header and its value
The request must have already been made.
"""
headers = self.requests.last_request.headers
self.assertEqual(val, headers.get(name))

View File

@@ -1,27 +0,0 @@
# 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.
"""
test_designateclient
----------------------------------
Tests for `designateclient` module.
"""
import designateclient
from designateclient.tests import base
class ClientTestCase(base.TestCase):
def test_module_version(self):
self.assertTrue(hasattr(designateclient, '__version__'))

View File

@@ -1,56 +0,0 @@
# Copyright 2015 Rackspace Inc.
#
# Author: James Li <james.li@rackspace.com>
#
# 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 designateclient import exceptions
from designateclient.tests import base
class RemoteErrorTestCase(base.TestCase):
response_dict = {
'message': None,
'code': 500,
'type': None,
'errors': None,
'request_id': 1234
}
def test_get_error_message(self):
expected_msg = 'something wrong'
self.response_dict['message'] = expected_msg
remote_err = exceptions.RemoteError(**self.response_dict)
self.assertEqual(expected_msg, remote_err.message)
def test_get_error_message_with_errors(self):
expected_msg = "u'nodot.com' is not a 'domainname'"
errors = {"errors": [
{"path": ["name"],
"message": expected_msg,
"validator": "format",
"validator_value": "domainname"}
]
}
self.response_dict['message'] = None
self.response_dict['errors'] = errors
remote_err = exceptions.RemoteError(**self.response_dict)
self.assertEqual(expected_msg, remote_err.message)
def test_get_error_message_with_type(self):
expected_msg = 'invalid_object'
self.response_dict['message'] = None
self.response_dict['errors'] = None
self.response_dict['type'] = expected_msg
remote_err = exceptions.RemoteError(**self.response_dict)
self.assertEqual(expected_msg, remote_err.message)

View File

@@ -1,85 +0,0 @@
# Copyright (c) 2015 Thales Services SAS
# 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 uuid
import mock
from designateclient import exceptions
from designateclient.tests import base
from designateclient import utils
LIST_MOCK_RESPONSE = [
{'id': '13579bdf-0000-0000-abcd-000000000001', 'name': 'abcd'},
{'id': '13579bdf-0000-0000-baba-000000000001', 'name': 'baba'},
{'id': '13579bdf-0000-0000-baba-000000000002', 'name': 'baba'},
]
class UtilsTestCase(base.TestCase):
def _find_resourceid_by_name_or_id(self, name_or_id, by_name=False):
resource_client = mock.Mock()
resource_client.list.return_value = LIST_MOCK_RESPONSE
resourceid = utils.find_resourceid_by_name_or_id(
resource_client, name_or_id)
self.assertEqual(by_name, resource_client.list.called)
return resourceid
def test_find_resourceid_with_hyphen_uuid(self):
expected = str(uuid.uuid4())
observed = self._find_resourceid_by_name_or_id(expected)
self.assertEqual(expected, observed)
def test_find_resourceid_with_nonhyphen_uuid(self):
expected = str(uuid.uuid4())
fakeid = expected.replace('-', '')
observed = self._find_resourceid_by_name_or_id(fakeid)
self.assertEqual(expected, observed)
def test_find_resourceid_with_unique_resource(self):
observed = self._find_resourceid_by_name_or_id('abcd', by_name=True)
self.assertEqual('13579bdf-0000-0000-abcd-000000000001', observed)
def test_find_resourceid_with_nonexistent_resource(self):
self.assertRaises(exceptions.ResourceNotFound,
self._find_resourceid_by_name_or_id,
'taz', by_name=True)
def test_find_resourceid_with_multiple_resources(self):
self.assertRaises(exceptions.NoUniqueMatch,
self._find_resourceid_by_name_or_id,
'baba', by_name=True)
def test_load_schema(self):
schema = utils.load_schema('v1', 'domain')
self.assertIsInstance(schema, dict)
def test_load_schema_missing(self):
self.assertRaises(exceptions.ResourceNotFound, utils.load_schema,
'v1', 'missing')
def test_resource_string_empty_param(self):
self.assertRaises(ValueError, utils.resource_string)
def test_resource_string(self):
name = ['schemas', 'v1', 'domain.json']
resource_string = utils.resource_string(*name)
self.assertIsNotNone(resource_string)
def test_resource_string_missing(self):
name = ['schemas', 'v1', 'missing']
self.assertRaises(exceptions.ResourceNotFound, utils.resource_string,
*name)

View File

@@ -1,53 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# 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 uuid
from designateclient.tests import base
class CrudMixin(object):
path_prefix = None
def new_ref(self, **kwargs):
kwargs.setdefault('id', uuid.uuid4().hex)
return kwargs
def stub_entity(self, method, parts=None, entity=None, id=None, **kwargs):
if entity:
kwargs['json'] = entity
if not parts:
parts = [self.RESOURCE]
if self.path_prefix:
parts.insert(0, self.path_prefix)
if id:
if not parts:
parts = []
parts.append(id)
self.stub_url(method, parts=parts, **kwargs)
def assertList(self, expected, actual):
self.assertEqual(len(expected), len(actual))
for i in expected:
self.assertIn(i, actual)
class APIV1TestCase(base.APITestCase):
VERSION = "1"

View File

@@ -1,124 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# 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 designateclient.tests import test_v1
from designateclient import utils
from designateclient import v1
from keystoneauth1 import session as keystone_session
class TestClient(test_v1.APIV1TestCase):
def test_all_tenants(self):
# Create a client with the all_tenants flag set to True
client = v1.Client(all_tenants=True)
# Verify this has been picked up
self.assertTrue(client.all_tenants)
def test_all_tenants_not_supplied(self):
# Create a client without supplying any all_tenants flag
client = v1.Client()
# Verify all_tenants is False
self.assertFalse(client.all_tenants)
self.assertIsNotNone(client.all_tenants)
def test_all_tenants_through_session(self):
# Create a session with the all_tenants flag set to True
session = utils.get_session(
auth_url='Anything',
endpoint='Anything',
domain_id='Anything',
domain_name='Anything',
project_id='Anything',
project_name='Anything',
project_domain_name='Anything',
project_domain_id='Anything',
username='Anything',
user_id='Anything',
password='Anything',
user_domain_id='Anything',
user_domain_name='Anything',
token=None,
insecure=False,
cacert=None,
all_tenants=True)
# Create a client using the pre-created session
client = v1.Client(session=session)
# Verify the all_tenants flag has been picked up
self.assertTrue(client.all_tenants)
def test_edit_managed(self):
# Create a client with the edit_managed flag set to True
client = v1.Client(edit_managed=True)
# Verify this has been picked up
self.assertTrue(client.edit_managed)
def test_edit_managed_not_supplied(self):
# Create a client without supplying any edit_managed flag
client = v1.Client()
# Verify edit_managed is False
self.assertFalse(client.edit_managed)
self.assertIsNotNone(client.edit_managed)
def test_edit_managed_through_session(self):
# Create a session with the edit_managed flag set to True
session = utils.get_session(
auth_url='Anything',
endpoint='Anything',
domain_id='Anything',
domain_name='Anything',
project_id='Anything',
project_name='Anything',
project_domain_name='Anything',
project_domain_id='Anything',
username='Anything',
user_id='Anything',
password='Anything',
user_domain_id='Anything',
user_domain_name='Anything',
token=None,
insecure=False,
cacert=None,
edit_managed=True)
# Create a client using the pre-created session
client = v1.Client(session=session)
# Verify the edit_managed flag has been picked up
self.assertTrue(client.edit_managed)
def test_timeout_new_session(self):
client = v1.Client(
auth_url="http://127.0.0.1:22/",
timeout=1,
)
assert client.session.timeout == 1
def test_timeout_override_session_timeout(self):
# The adapter timeout should override the session timeout
session = keystone_session.Session(timeout=10)
client = v1.Client(
auth_url="http://127.0.0.1:22/",
session=session,
timeout=2,
)
self.assertEqual(2, client.session.timeout)

View File

@@ -1,30 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 mock import patch
from designateclient.tests import test_v1
from designateclient.v1 import diagnostics
class TestDiagnostics(test_v1.APIV1TestCase, test_v1.CrudMixin):
@patch.object(diagnostics.DiagnosticsController, "ping")
def test_ping(self, ping):
args = mock.MagicMock()
args.service = "foo"
args.host = "host1"
self.client.diagnostics.ping(args.host, args.service)
self.client.diagnostics.ping.assert_called_with("host1", "foo")

View File

@@ -1,184 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 uuid
from mock import patch
from designateclient.tests import test_v1
from designateclient import utils
from designateclient.v1 import domains
from designateclient import warlock
Domain = warlock.model_factory(utils.load_schema('v1', 'domain'))
class TestDomain(test_v1.APIV1TestCase, test_v1.CrudMixin):
RESOURCE = 'domains'
def new_ref(self, **kwargs):
ref = super(TestDomain, self).new_ref(**kwargs)
ref.setdefault("name", uuid.uuid4().hex)
ref.setdefault("email", "abc@example.com.")
ref.setdefault("ttl", 3600)
return ref
def test_create(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "domain1.com.",
"email": "nsadmin@example.org",
"ttl": 60}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
response = self.client.domains.create(values["name"])
self.assertEqual(ref['id'], response['id'])
def test_create_with_description(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "domain1.com.",
"email": "nsadmin@example.org",
"ttl": 60,
"description": "fully qualified domain"}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
response = self.client.domains.create(values["name"])
self.assertEqual(ref['id'], response['id'])
def test_create_with_description_too_long(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "domain1.com.",
"email": "nsadmin@example.org",
"ttl": 60,
"description": "d" * 161}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.assertRaises(ValueError, self.client.domains.create,
values["name"])
def test_create_with_zero_ttl(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "domain1.com.",
"email": "nsadmin@example.org",
"ttl": 0}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.assertRaises(ValueError, self.client.domains.create,
values["name"])
def test_create_with_negative_ttl(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "domain1.com.",
"email": "nsadmin@example.org",
"ttl": -1}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.assertRaises(ValueError, self.client.domains.create,
values["name"])
def test_create_with_no_ttl(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "domain1.com.",
"email": "nsadmin@example.org",
"ttl": ""}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.assertRaises(ValueError, self.client.domains.create,
values["name"])
def test_create_with_name_too_long(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "domain" + "a" * 255 + ".com.",
"email": "nsadmin@example.org",
"ttl": 60}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.assertRaises(ValueError, self.client.domains.create,
values["name"])
def test_list(self):
items = [
self.new_ref(email="abc@example.org",
id="89acac79-38e7-497d-807c-a011e1310438"),
self.new_ref(email="root@example.org",
id="89acac79-38e7-497d-807c-a011e1310435")
]
self.stub_url("GET", parts=[self.RESOURCE], json={"domains": items})
listed = self.client.domains.list()
self.assertList(items, listed)
self.assertQueryStringIs("")
def test_get(self):
ref = self.new_ref(email="abc@example.org",
id="89acac79-38e7-497d-807c-a011e1310438")
self.stub_entity("GET", entity=ref, id=ref["id"])
response = self.client.domains.get(ref["id"])
self.assertEqual(ref, response)
def test_delete(self):
ref = self.new_ref(email="abc@example.org",
id="89acac79-38e7-497d-807c-a011e1310438")
self.stub_entity("DELETE", entity=ref, id=ref["id"])
self.client.domains.delete(ref["id"])
self.assertRequestBodyIs(None)
def test_update(self):
ref = self.new_ref(id="89acac79-38e7-497d-807c-a011e1310438")
self.stub_entity("PUT", entity=ref, id=ref["id"])
values = ref.copy()
self.client.domains.update(Domain(values))
@patch.object(domains.DomainsController, "list_domain_servers")
def test_list_domain_servers(self, domains_get):
domains_get.return_value = [{"id": "foo", "name": "ns1.example.com."}]
ref = [{
"id": "foo",
"name": "ns1.example.com.",
}]
parts = ["domains", "foo", "servers"]
self.stub_url("GET", parts=parts, json={"servers": ref})
response = self.client.domains.list_domain_servers("foo")
self.assertEqual(ref, response)

View File

@@ -1,48 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 mock import patch
from designateclient.tests import test_v1
from designateclient.v1 import quotas
class TestQuota(test_v1.APIV1TestCase, test_v1.CrudMixin):
@patch.object(quotas.QuotasController, "get")
def test_get(self, quota_get):
QUOTA = {"domains": 10,
"recordset_records": 20,
"domain_records": 500,
"domain_recordsets": 500}
quota_get.return_value = QUOTA
response = self.client.quotas.get("foo")
self.assertEqual(QUOTA, response)
@patch.object(quotas.QuotasController, "update")
def test_update(self, quota_update):
args = mock.MagicMock()
args.tenant_id = "1234"
args.value = {"domains": 1000}
self.client.quotas.update(args.tenant_id, args.value)
self.client.quotas.update.assert_called_with(args.tenant_id,
args.value)
@patch.object(quotas.QuotasController, "reset")
def test_reset(self, quota_reset):
args = mock.MagicMock()
args.tenant_id = "1234"
self.client.quotas.reset(args.tenant_id)
self.client.quotas.reset.assert_called_with("1234")

View File

@@ -1,222 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 uuid
from designateclient.tests import test_v1
from designateclient import utils
from designateclient import warlock
Record = warlock.model_factory(utils.load_schema('v1', 'record'))
DOMAIN = {
"id": str(uuid.uuid4()),
"name": "example.com."
}
class TestRecords(test_v1.APIV1TestCase, test_v1.CrudMixin):
RESOURCE = 'records'
def new_ref(self, **kwargs):
ref = super(TestRecords, self).new_ref(**kwargs)
ref.setdefault("name", uuid.uuid4().hex)
ref.setdefault("type", "A")
ref.setdefault("data", "10.0.0.1")
return ref
def test_create_record(self):
ref = self.new_ref(id="2e32e609-3a4f-45ba-bdef-e50eacd345ad")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_AAAA_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677778888",
type="AAAA",
data="2001:db8:0:1234:0:5678:9:12")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_MX_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677778989",
type="MX",
data="mail.example.com.",
priority=10)
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_CNAME_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677778890",
type="CNAME",
data="example.com.")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_TXT_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677778889",
type="TXT",
data="This is a TXT record")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_SRV_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677778888",
type="SRV",
data="0 5060 sip.example.com.",
priority=30)
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_NS_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677779999",
type="NS",
data="ns1.example.com.")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_PTR_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677778891",
type="PTR",
data="www.example.com.")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_SPF_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677778899",
type="SPF",
data="v=spf1 +mx a:colo.example.com/28 -all")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_create_SSHFP_record(self):
ref = self.new_ref(id="11112222-3333-4444-5555-666677778888",
type="SSHFP",
data="2 1 6c3c958af43d953f91f40e0d84157f4fe7b4a898")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.records.create(DOMAIN['id'], Record(values))
self.assertRequestBodyIs(json=values)
def test_get(self):
ref = self.new_ref(id="2e32e609-3a4f-45ba-bdef-e50eacd345ad")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_entity("GET", entity=ref, id=ref["id"], parts=parts)
response = self.client.records.get(DOMAIN["id"], ref["id"])
self.assertEqual(ref, response)
def test_list(self):
items = [
self.new_ref(id="2e32e609-3a4f-45ba-bdef-e50eacd345ad"),
self.new_ref(id="11112222-3333-4444-5555-666677778888")
]
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_url("GET", parts=parts, json={"records": items})
listed = self.client.records.list(DOMAIN["id"])
self.assertList(items, listed)
self.assertQueryStringIs("")
def test_update(self):
ref = self.new_ref(id="2e32e609-3a4f-45ba-bdef-e50eacd345ad",
type="A",
data="192.0.2.5")
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_entity("PUT", entity=ref, id=ref["id"], parts=parts)
values = ref.copy()
del values["id"]
self.client.records.update(DOMAIN["id"], Record(ref))
def test_delete(self):
ref = self.new_ref()
parts = ["domains", DOMAIN["id"], self.RESOURCE]
self.stub_entity("DELETE", id=ref["id"], parts=parts)
self.client.records.delete(DOMAIN["id"], ref["id"])
self.assertRequestBodyIs(None)

View File

@@ -1,54 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 mock import patch
from designateclient.tests import test_v1
from designateclient.v1 import reports
class TestReports(test_v1.APIV1TestCase, test_v1.CrudMixin):
@patch.object(reports.ReportsController, "count_all")
def test_count_all(self, count_all):
self.client.reports.count_all()
self.client.reports.count_all.assert_called_with()
@patch.object(reports.ReportsController, "count_domains")
def test_count_domain(self, count_domains):
self.client.reports.count_domains()
self.client.reports.count_domains.assert_called_once_with()
@patch.object(reports.ReportsController, "count_tenants")
def test_count_tenants(self, count_tenants):
self.client.reports.count_tenants()
self.client.reports.count_tenants.assert_called_once_with()
@patch.object(reports.ReportsController, "count_records")
def test_count_records(self, count_records):
self.client.reports.count_records()
self.client.reports.count_records.assert_called_once_with()
@patch.object(reports.ReportsController, "tenants_all")
def test_tenants_all(self, tenants_all):
self.client.reports.tenants_all()
self.client.reports.tenants_all.assert_called_once_with()
@patch.object(reports.ReportsController, "tenant_domains")
def test_tenant_domains(self, tenant_domains):
args = mock.MagicMock()
args.other_tenant_id = "uuid"
self.client.reports.tenant_domains(args.other_tenant_id)
self.client.reports.tenant_domains.assert_called_once_with("uuid")

View File

@@ -1,95 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 uuid
import mock
from mock import patch
from designateclient.tests import test_v1
from designateclient.v1 import servers
class TestServers(test_v1.APIV1TestCase, test_v1.CrudMixin):
RESOURCE = 'servers'
def new_ref(self, **kwargs):
ref = super(TestServers, self).new_ref(**kwargs)
ref.setdefault("name", uuid.uuid4().hex)
return ref
def test_list(self):
items = [
self.new_ref(name="ns1.example.org.",
id="89acac79-38e7-497d-807c-a011e1310438"),
self.new_ref(name="ns2.example.org.",
id="89acac79-38e7-497d-807c-a011e1310435")
]
self.stub_url("GET", parts=[self.RESOURCE], json={"servers": items})
listed = self.client.servers.list()
self.assertList(items, listed)
self.assertQueryStringIs("")
def test_get(self):
ref = self.new_ref(name="ns1.example.org.",
id="89acac79-38e7-497d-807c-a011e1310438")
self.stub_entity("GET", entity=ref, id=ref["id"])
response = self.client.servers.get(ref["id"])
self.assertEqual(ref, response)
def test_create(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "ns1.example.org."}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.servers.create({"name": "ns1.example.org."})
self.assertRequestBodyIs(json=values)
def test_create_with_name_too_long(self):
ref = {"id": "89acac79-38e7-497d-807c-a011e1310438",
"name": "ns1." + "foo" * 85 + ".org."}
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.assertRaises(ValueError, self.client.servers.create,
{"name": "ns1.example.org."})
@patch.object(servers.ServersController, "update")
def test_update(self, server_update):
ref = self.new_ref()
self.stub_entity("PUT", entity=ref, id=ref["id"])
mock_server = mock.MagicMock()
self.client.servers.update(mock_server)
self.client.servers.update.assert_called_with(mock_server)
def test_delete(self):
ref = self.new_ref()
self.stub_entity("DELETE", id=ref["id"])
self.client.servers.delete(ref["id"])
self.assertRequestBodyIs(None)

View File

@@ -1,42 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 mock import patch
from designateclient.tests import test_v1
from designateclient.v1 import sync
class TestSync(test_v1.APIV1TestCase, test_v1.CrudMixin):
@patch.object(sync.SyncController, "sync_all")
def test_sync_all(self, sync_all):
self.client.sync.sync_all()
self.client.sync.sync_all.assert_called_with()
@patch.object(sync.SyncController, "sync_domain")
def test_sync_domain(self, sync_domain):
args = mock.MagicMock()
args.tenant_id = "1234"
self.client.sync.sync_domain(args.tenant_id)
self.client.sync.sync_domain.assert_called_with("1234")
@patch.object(sync.SyncController, "sync_record")
def test_sync_record(self, sync_record):
args = mock.MagicMock()
args.tenant_id = "1234"
args.record_id = "uuid"
self.client.sync.sync_record(args.tenant_id, args.record_id)
self.client.sync.sync_record.assert_called_with("1234", "uuid")

View File

@@ -1,29 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 mock import patch
from designateclient.tests import test_v1
from designateclient.v1 import touch
class TestTouch(test_v1.APIV1TestCase, test_v1.CrudMixin):
@patch.object(touch.TouchController, "domain")
def test_domain(self, domain):
args = mock.MagicMock()
args.domain_id = "1234"
self.client.touch.domain(args.domain_id)
self.client.touch.domain.assert_called_with("1234")

View File

@@ -1,53 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 uuid
from designateclient.tests import base
class CrudMixin(object):
path_prefix = None
def new_ref(self, **kwargs):
kwargs.setdefault('id', uuid.uuid4().hex)
return kwargs
def stub_entity(self, method, parts=None, entity=None, id=None, **kwargs):
if entity:
kwargs['json'] = entity
if not parts:
parts = [self.RESOURCE]
if self.path_prefix:
parts.insert(0, self.path_prefix)
if id:
if not parts:
parts = []
parts.append(id)
self.stub_url(method, parts=parts, **kwargs)
def assertList(self, expected, actual):
self.assertEqual(len(expected), len(actual))
for i in expected:
self.assertIn(i, actual)
class APIV2TestCase(base.APITestCase):
VERSION = "2"

View File

@@ -1,88 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 uuid
from designateclient.tests import v2
class TestBlacklists(v2.APIV2TestCase, v2.CrudMixin):
RESOURCE = 'blacklists'
def new_ref(self, **kwargs):
ref = super(TestBlacklists, self).new_ref(**kwargs)
ref.setdefault("pattern", uuid.uuid4().hex)
return ref
def test_create(self):
ref = self.new_ref()
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.blacklists.create(**values)
self.assertRequestBodyIs(json=values)
def test_create_with_description(self):
ref = self.new_ref(description="My Blacklist")
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.blacklists.create(**values)
self.assertRequestBodyIs(json=values)
def test_get(self):
ref = self.new_ref()
self.stub_entity("GET", entity=ref, id=ref["id"])
response = self.client.blacklists.get(ref["id"])
self.assertEqual(ref, response)
def test_list(self):
items = [
self.new_ref(),
self.new_ref()
]
self.stub_url("GET", parts=[self.RESOURCE], json={"blacklists": items})
listed = self.client.blacklists.list()
self.assertList(items, listed)
self.assertQueryStringIs("")
def test_update(self):
ref = self.new_ref()
self.stub_entity("PATCH", entity=ref, id=ref["id"])
values = ref.copy()
del values["id"]
self.client.blacklists.update(ref["id"], values)
self.assertRequestBodyIs(json=values)
def test_delete(self):
ref = self.new_ref()
self.stub_entity("DELETE", id=ref["id"])
self.client.blacklists.delete(ref["id"])
self.assertRequestBodyIs(None)

View File

@@ -1,46 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Federico Ceratto <federico.ceratto@hp.com>
#
# 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
from keystoneauth1 import session as keystone_session
from designateclient.tests.base import TestCase
from designateclient.v2.client import Client
class TestClient(TestCase):
def test_init(self):
self.assertRaises(ValueError, Client)
def test_init_with_session(self):
session = keystone_session.Session()
adapted = adapter.Adapter(session=session)
client = Client(session=adapted)
assert client.session
def test_init_with_session_timeout(self):
session = keystone_session.Session()
client = Client(
session=session,
timeout=1)
assert client.session.timeout == 1
def test_init_with_auth(self):
session = keystone_session.Session()
client = Client(
auth='http://127.0.0.1:22/',
session=session)
assert client.session.auth

View File

@@ -1,25 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.tests import v2
class TestLimits(v2.APIV2TestCase, v2.CrudMixin):
def test_get(self):
ref = {"max_zones": "foo"}
self.stub_url("GET", parts=["limits"], json=ref)
limits = self.client.limits.get()
self.assertEqual(ref, limits)

View File

@@ -1,35 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 mock import patch
from designateclient.tests import v2
from designateclient.v2 import zones
class TestLimits(v2.APIV2TestCase, v2.CrudMixin):
@patch.object(zones.ZoneController, "list")
def test_get(self, zones_get):
zones_get.return_value = [{"id": "foo"}]
ref = [{
"hostname": "ns1.example.com.",
"priority": 1
}]
parts = ["zones", "foo", "nameservers"]
self.stub_url("GET", parts=parts, json={"nameservers": ref})
response = self.client.nameservers.list("foo")
self.assertEqual(ref, response)

View File

@@ -1,237 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 uuid
from mock import patch
import testtools
from designateclient import exceptions
from designateclient.tests import v2
from designateclient.v2 import zones
ZONE = {
"id": str(uuid.uuid4()),
"name": "example.com."
}
class TestRecordSets(v2.APIV2TestCase, v2.CrudMixin):
RESOURCE = 'recordsets'
def new_ref(self, **kwargs):
ref = super(TestRecordSets, self).new_ref(**kwargs)
ref.setdefault("name", uuid.uuid4().hex)
ref.setdefault("type", "A")
ref.setdefault("records", ["10.0.0.1"])
return ref
def test_create_absolute_with_zone_dict(self):
ref = self.new_ref()
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.recordsets.create(
ZONE,
"%s.%s" % (values["name"], ZONE["name"]),
values["type"],
values["records"])
values["name"] = "%s.%s" % (ref["name"], ZONE["name"])
self.assertRequestBodyIs(json=values)
@patch.object(zones.ZoneController, "get")
def test_create_absolute_with_zone_name(self, zone_get):
ref = self.new_ref()
zone_get.return_value = ZONE
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.recordsets.create(
ZONE["name"],
"%s.%s" % (values["name"], ZONE["name"]),
values["type"],
values["records"])
values["name"] = "%s.%s" % (ref["name"], ZONE["name"])
self.assertRequestBodyIs(json=values)
@patch.object(zones.ZoneController, "get")
def test_create_non_absolute_with_zone_name(self, zone_get):
ref = self.new_ref()
zone_get.return_value = ZONE
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.recordsets.create(
ZONE["name"],
values["name"],
values["type"],
values["records"])
values["name"] = "%s.%s" % (ref["name"], ZONE["name"])
self.assertRequestBodyIs(json=values)
@patch.object(zones.ZoneController, "list")
def test_create_non_absolute_with_zone_name_non_unique(self, zone_list):
zone_list.return_value = [
1,
2
]
ref = self.new_ref()
values = ref.copy()
del values["id"]
with testtools.ExpectedException(exceptions.NoUniqueMatch):
self.client.recordsets.create(
ZONE["name"],
"%s.%s" % (values["name"], ZONE["name"]),
values["type"],
values["records"])
def test_create_absolute_with_zone_id(self):
ref = self.new_ref()
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.recordsets.create(
ZONE["id"],
"%s.%s" % (values["name"], ZONE["name"]),
values["type"],
values["records"])
values["name"] = "%s.%s" % (ref["name"], ZONE["name"])
self.assertRequestBodyIs(json=values)
@patch.object(zones.ZoneController, "get")
def test_create_non_absolute_with_zone_id(self, zone_get):
ref = self.new_ref()
zone_get.return_value = ZONE
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.recordsets.create(
ZONE["id"],
values["name"],
values["type"],
values["records"])
values["name"] = "%s.%s" % (ref["name"], ZONE["name"])
self.assertRequestBodyIs(json=values)
def test_create_with_description(self):
ref = self.new_ref(description="Foo")
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.recordsets.create(
ZONE["id"],
"%s.%s" % (values["name"], ZONE["name"]),
values["type"],
values["records"],
description=values["description"])
values["name"] = "%s.%s" % (ref["name"], ZONE["name"])
self.assertRequestBodyIs(json=values)
def test_create_with_ttl(self):
ref = self.new_ref(ttl=60)
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_url("POST", parts=parts, json=ref)
values = ref.copy()
del values["id"]
self.client.recordsets.create(
ZONE["id"],
"%s.%s" % (values["name"], ZONE["name"]),
values["type"],
values["records"],
ttl=values["ttl"])
values["name"] = "%s.%s" % (ref["name"], ZONE["name"])
self.assertRequestBodyIs(json=values)
def test_get(self):
ref = self.new_ref()
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_entity("GET", entity=ref, id=ref["id"], parts=parts)
response = self.client.recordsets.get(ZONE["id"], ref["id"])
self.assertEqual(ref, response)
def test_list(self):
items = [
self.new_ref(),
self.new_ref()
]
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_url("GET", parts=parts, json={"recordsets": items})
listed = self.client.recordsets.list(ZONE["id"])
self.assertList(items, listed)
self.assertQueryStringIs("")
def test_update(self):
ref = self.new_ref()
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_entity("PUT", entity=ref, id=ref["id"], parts=parts)
values = ref.copy()
del values["id"]
self.client.recordsets.update(ZONE["id"], ref["id"], values)
self.assertRequestBodyIs(json=values)
def test_delete(self):
ref = self.new_ref()
parts = ["zones", ZONE["id"], self.RESOURCE]
self.stub_entity("DELETE", id=ref["id"], parts=parts)
self.client.recordsets.delete(ZONE["id"], ref["id"])
self.assertRequestBodyIs(None)

View File

@@ -1,62 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 uuid
from designateclient.tests import v2
FIP_ID = '%s:%s' % (str(uuid.uuid4()), "RegionOne")
class TestFloatingIP(v2.APIV2TestCase, v2.CrudMixin):
def test_set(self):
name = "foo.com."
ref = {
"ptrdname": name,
"description": "foo"
}
parts = ["reverse", "floatingips", FIP_ID]
self.stub_url("PATCH", parts=parts, json=ref)
self.client.floatingips.set(FIP_ID, name, "foo")
def test_list(self):
ref = [
{"ptrdname": "foo.com."}
]
self.stub_url("GET", parts=["reverse", "floatingips"],
json={"floatingips": ref})
self.client.floatingips.list()
def test_get(self):
ref = {
"ptrdname": "foo.com."
}
parts = ["reverse", "floatingips", FIP_ID]
self.stub_url("GET", parts=parts, json=ref)
self.client.floatingips.get(FIP_ID)
def test_unset(self):
parts = ["reverse", "floatingips", FIP_ID]
self.stub_url("PATCH", parts=parts, json={"ptdrname": None})
self.client.floatingips.unset(FIP_ID)
self.assertRequestBodyIs(None)

View File

@@ -1,46 +0,0 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.tests import v2
class TestServiceStatuses(v2.APIV2TestCase, v2.CrudMixin):
RESOURCE = 'service_statuses'
def new_ref(self, **kwargs):
ref = super(TestServiceStatuses, self).new_ref(**kwargs)
ref["name"] = "foo"
return ref
def test_get(self):
ref = self.new_ref()
self.stub_entity("GET", entity=ref, id=ref["id"])
response = self.client.service_statuses.get(ref["id"])
self.assertEqual(ref, response)
def test_list(self):
items = [
self.new_ref(),
self.new_ref()
]
self.stub_url("GET", parts=[self.RESOURCE],
json={"service_statuses": items})
listed = self.client.service_statuses.list()
self.assertList(items, listed)
self.assertQueryStringIs("")

View File

@@ -1,109 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Federico Ceratto <federico.ceratto@hp.com>
#
# 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.identity import generic
from keystoneauth1 import session as keystone_session
from mock import Mock
from designateclient.tests import v2
from designateclient.v2.client import Client
def create_session(timeout=None):
auth = generic.Password(auth_url='', username='', password='',
tenant_name='')
return keystone_session.Session(auth=auth, timeout=timeout)
class TestTimeout(v2.APIV2TestCase, v2.CrudMixin):
def setUp(self):
super(TestTimeout, self).setUp()
# Mock methods in KeyStone's Session
self._saved_methods = (
keystone_session.Session.get_auth_headers,
keystone_session.Session.get_endpoint,
keystone_session.Session._send_request,
)
resp = Mock()
resp.text = ''
resp.status_code = 200
keystone_session.Session.get_auth_headers = Mock(
return_value=[]
)
keystone_session.Session.get_endpoint = Mock(
return_value='foo'
)
keystone_session.Session._send_request = Mock(
return_value=resp,
)
self.mock_send_request = keystone_session.Session._send_request
def tearDown(self):
super(TestTimeout, self).tearDown()
(
keystone_session.Session.get_auth_headers,
keystone_session.Session.get_endpoint,
keystone_session.Session._send_request,
) = self._saved_methods
def _call_request_and_check_timeout(self, client, timeout):
"""call the mocked _send_request() and check if the timeout was set
"""
client.limits.get()
self.assertTrue(self.mock_send_request.called)
kw = self.mock_send_request.call_args[1]
if timeout is None:
self.assertNotIn('timeout', kw)
else:
self.assertEqual(timeout, kw['timeout'])
def test_no_timeout(self):
session = create_session(timeout=None)
client = Client(session=session)
self.assertIsNone(session.timeout)
self.assertIsNone(client.session.timeout)
self._call_request_and_check_timeout(client, None)
def test_timeout_in_session(self):
session = create_session(timeout=1)
client = Client(session=session)
self.assertEqual(1, session.timeout)
self.assertIsNone(client.session.timeout)
self._call_request_and_check_timeout(client, 1)
def test_timeout_override_session_timeout(self):
# The adapter timeout should override the session timeout
session = create_session(timeout=10)
self.assertEqual(10, session.timeout)
client = Client(session=session, timeout=2)
self.assertEqual(2, client.session.timeout)
self._call_request_and_check_timeout(client, 2)
def test_timeout_update(self):
session = create_session(timeout=1)
client = Client(session=session)
self.assertEqual(1, session.timeout)
self.assertIsNone(client.session.timeout)
self._call_request_and_check_timeout(client, 1)
session.timeout = 2
self.assertEqual(2, session.timeout)
self._call_request_and_check_timeout(client, 2)

View File

@@ -1,103 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 uuid
from designateclient.tests import v2
class TestTlds(v2.APIV2TestCase, v2.CrudMixin):
RESOURCE = 'tlds'
def new_ref(self, **kwargs):
ref = super(TestTlds, self).new_ref(**kwargs)
ref.setdefault("name", uuid.uuid4().hex)
return ref
def test_create(self):
ref = self.new_ref()
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.tlds.create(**values)
self.assertRequestBodyIs(json=values)
def test_create_with_description(self):
ref = self.new_ref(description="My TLD")
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.tlds.create(**values)
self.assertRequestBodyIs(json=values)
def test_get(self):
ref = self.new_ref()
self.stub_entity("GET", entity=ref, id=ref["id"])
response = self.client.tlds.get(ref["id"])
self.assertEqual(ref, response)
def test_get_by_name(self):
ref = self.new_ref(name="www")
self.stub_entity("GET", entity=ref, id=ref["id"])
self.stub_url("GET", parts=[self.RESOURCE], json={"tlds": [ref]})
response = self.client.tlds.get(ref['name'])
self.assertEqual("GET", self.requests.request_history[0].method)
self.assertEqual(
"http://127.0.0.1:9001/v2/tlds?name=www",
self.requests.request_history[0].url)
self.assertEqual(ref, response)
def test_list(self):
items = [
self.new_ref(),
self.new_ref()
]
self.stub_url("GET", parts=[self.RESOURCE], json={"tlds": items})
listed = self.client.tlds.list()
self.assertList(items, listed)
self.assertQueryStringIs("")
def test_update(self):
ref = self.new_ref()
self.stub_entity("PATCH", entity=ref, id=ref["id"])
values = ref.copy()
del values["id"]
self.client.tlds.update(ref["id"], values)
self.assertRequestBodyIs(json=values)
def test_delete(self):
ref = self.new_ref()
self.stub_entity("DELETE", id=ref["id"])
self.client.tlds.delete(ref["id"])
self.assertRequestBodyIs(None)

View File

@@ -1,382 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 time
import uuid
from designateclient.tests import v2
class TestZones(v2.APIV2TestCase, v2.CrudMixin):
RESOURCE = 'zones'
def new_ref(self, **kwargs):
ref = super(TestZones, self).new_ref(**kwargs)
ref.setdefault("name", uuid.uuid4().hex)
ref.setdefault("type", "PRIMARY")
return ref
def test_create_with_description(self):
ref = self.new_ref(email="root@example.com", description="Foo")
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.zones.create(
values["name"],
email=values["email"],
description=values["description"])
self.assertRequestBodyIs(json=values)
def test_create_primary(self):
ref = self.new_ref(email="root@example.com")
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.zones.create(
values["name"],
email=values["email"])
self.assertRequestBodyIs(json=values)
def test_create_primary_with_ttl(self):
ref = self.new_ref(email="root@example.com", ttl=60)
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.zones.create(
values["name"],
email=values["email"],
ttl=values["ttl"])
self.assertRequestBodyIs(json=values)
def test_create_secondary(self):
ref = self.new_ref(type="SECONDARY", masters=["10.0.0.1"])
self.stub_url("POST", parts=[self.RESOURCE], json=ref)
values = ref.copy()
del values["id"]
self.client.zones.create(
values["name"],
type_=values["type"],
masters=values["masters"])
self.assertRequestBodyIs(json=values)
def test_get(self):
ref = self.new_ref()
self.stub_entity("GET", entity=ref, id=ref["id"])
response = self.client.zones.get(ref["id"])
self.assertEqual(ref, response)
def test_list(self):
items = [
self.new_ref(),
self.new_ref()
]
self.stub_url("GET", parts=[self.RESOURCE], json={"zones": items})
listed = self.client.zones.list()
self.assertList(items, listed)
self.assertQueryStringIs("")
def test_update(self):
ref = self.new_ref()
self.stub_entity("PATCH", entity=ref, id=ref["id"])
values = ref.copy()
del values["id"]
self.client.zones.update(ref["id"], values)
self.assertRequestBodyIs(json=values)
def test_delete(self):
ref = self.new_ref()
self.stub_entity("DELETE", id=ref["id"])
self.client.zones.delete(ref["id"])
self.assertRequestBodyIs(None)
def test_task_abandon(self):
ref = self.new_ref()
parts = [self.RESOURCE, ref["id"], "tasks", "abandon"]
self.stub_url("POST", parts=parts)
self.client.zones.abandon(ref["id"])
self.assertRequestBodyIs(None)
def test_task_axfr(self):
ref = self.new_ref()
parts = [self.RESOURCE, ref["id"], "tasks", "xfr"]
self.stub_url("POST", parts=parts)
self.client.zones.axfr(ref["id"])
self.assertRequestBodyIs(None)
class TestZoneTransfers(v2.APIV2TestCase, v2.CrudMixin):
def test_create_request(self):
zone = "098bee04-fe30-4a83-8ccd-e0c496755816"
project = "123"
ref = {
"target_project_id": project
}
parts = ["zones", zone, "tasks", "transfer_requests"]
self.stub_url('POST', parts=parts, json=ref)
self.client.zone_transfers.create_request(zone, project)
self.assertRequestBodyIs(json=ref)
def test_create_request_with_description(self):
zone = "098bee04-fe30-4a83-8ccd-e0c496755816"
project = "123"
ref = {
"target_project_id": project,
"description": "My Foo"
}
parts = ["zones", zone, "tasks", "transfer_requests"]
self.stub_url('POST', parts=parts, json=ref)
self.client.zone_transfers.create_request(
zone, project, ref["description"])
self.assertRequestBodyIs(json=ref)
def test_get_request(self):
transfer = "098bee04-fe30-4a83-8ccd-e0c496755816"
project = "098bee04-fe30-4a83-8ccd-e0c496755817"
ref = {
"target_project_id": project
}
parts = ["zones", "tasks", "transfer_requests", transfer]
self.stub_url('GET', parts=parts, json=ref)
self.client.zone_transfers.get_request(transfer)
self.assertRequestBodyIs("")
def test_list_request(self):
project = "098bee04-fe30-4a83-8ccd-e0c496755817"
ref = [{
"target_project_id": project
}]
parts = ["zones", "tasks", "transfer_requests"]
self.stub_url('GET', parts=parts, json={"transfer_requests": ref})
self.client.zone_transfers.list_requests()
self.assertRequestBodyIs("")
def test_update_request(self):
transfer = "098bee04-fe30-4a83-8ccd-e0c496755816"
project = "098bee04-fe30-4a83-8ccd-e0c496755817"
ref = {
"target_project_id": project
}
parts = ["zones", "tasks", "transfer_requests", transfer]
self.stub_url('PATCH', parts=parts, json=ref)
self.client.zone_transfers.update_request(transfer, ref)
self.assertRequestBodyIs(json=ref)
def test_delete_request(self):
transfer = "098bee04-fe30-4a83-8ccd-e0c496755816"
parts = ["zones", "tasks", "transfer_requests", transfer]
self.stub_url('DELETE', parts=parts)
self.client.zone_transfers.delete_request(transfer)
self.assertRequestBodyIs("")
def test_accept_request(self):
transfer = "098bee04-fe30-4a83-8ccd-e0c496755816"
key = "foo123"
ref = {
"status": "COMPLETE"
}
parts = ["zones", "tasks", "transfer_accepts"]
self.stub_url('POST', parts=parts, json=ref)
request = {
"key": key,
"zone_transfer_request_id": transfer
}
self.client.zone_transfers.accept_request(transfer, key)
self.assertRequestBodyIs(json=request)
def test_get_accept(self):
accept_id = "098bee04-fe30-4a83-8ccd-e0c496755816"
ref = {
"status": "COMPLETE"
}
parts = ["zones", "tasks", "transfer_accepts", accept_id]
self.stub_url('GET', parts=parts, json=ref)
response = self.client.zone_transfers.get_accept(accept_id)
self.assertEqual(ref, response)
def test_list_accepts(self):
accept_id = "098bee04-fe30-4a83-8ccd-e0c496755816"
ref = {
"id": accept_id,
"status": "COMPLETE"
}
parts = ["zones", "tasks", "transfer_accepts"]
self.stub_url('GET', parts=parts, json={"transfer_accepts": ref})
self.client.zone_transfers.list_accepts()
self.assertRequestBodyIs("")
class TestZoneExports(v2.APIV2TestCase, v2.CrudMixin):
def new_ref(self, **kwargs):
ref = super(TestZoneExports, self).new_ref(**kwargs)
ref.setdefault("zone_id", uuid.uuid4().hex)
ref.setdefault("created_at", time.strftime("%c"))
ref.setdefault("updated_at", time.strftime("%c"))
ref.setdefault("status", 'PENDING')
ref.setdefault("version", '1')
return ref
def test_create_export(self):
zone = uuid.uuid4().hex
ref = {}
parts = ["zones", zone, "tasks", "export"]
self.stub_url('POST', parts=parts, json=ref)
self.client.zone_exports.create(zone)
self.assertRequestBodyIs(json=ref)
def test_get_export(self):
ref = self.new_ref()
parts = ["zones", "tasks", "exports", ref["id"]]
self.stub_url('GET', parts=parts, json=ref)
self.stub_entity("GET", parts=parts, entity=ref, id=ref["id"])
response = self.client.zone_exports.get_export_record(ref["id"])
self.assertEqual(ref, response)
def test_list_exports(self):
items = [
self.new_ref(),
self.new_ref()
]
parts = ["zones", "tasks", "exports"]
self.stub_url('GET', parts=parts, json={"exports": items})
listed = self.client.zone_exports.list()
self.assertList(items, listed["exports"])
self.assertQueryStringIs("")
def test_delete_export(self):
ref = self.new_ref()
parts = ["zones", "tasks", "exports", ref["id"]]
self.stub_url('DELETE', parts=parts, json=ref)
self.stub_entity("DELETE", parts=parts, id=ref["id"])
self.client.zone_exports.delete(ref["id"])
self.assertRequestBodyIs(None)
def test_get_export_file(self):
ref = self.new_ref()
parts = ["zones", "tasks", "exports", ref["id"], "export"]
self.stub_url('GET', parts=parts, json=ref)
self.stub_entity("GET", parts=parts, entity=ref, id=ref["id"])
response = self.client.zone_exports.get_export(ref["id"])
self.assertEqual(ref, response)
class TestZoneImports(v2.APIV2TestCase, v2.CrudMixin):
def new_ref(self, **kwargs):
ref = super(TestZoneImports, self).new_ref(**kwargs)
ref.setdefault("zone_id", uuid.uuid4().hex)
ref.setdefault("created_at", time.strftime("%c"))
ref.setdefault("updated_at", time.strftime("%c"))
ref.setdefault("status", 'PENDING')
ref.setdefault("message", 'Importing...')
ref.setdefault("version", '1')
return ref
def test_create_import(self):
zonefile = '$ORIGIN example.com'
parts = ["zones", "tasks", "imports"]
self.stub_url('POST', parts=parts, json=zonefile)
self.client.zone_imports.create(zonefile)
self.assertRequestBodyIs(body=zonefile)
def test_get_import(self):
ref = self.new_ref()
parts = ["zones", "tasks", "imports", ref["id"]]
self.stub_url('GET', parts=parts, json=ref)
self.stub_entity("GET", parts=parts, entity=ref, id=ref["id"])
response = self.client.zone_imports.get_import_record(ref["id"])
self.assertEqual(ref, response)
def test_list_imports(self):
items = [
self.new_ref(),
self.new_ref()
]
parts = ["zones", "tasks", "imports"]
self.stub_url('GET', parts=parts, json={"imports": items})
listed = self.client.zone_imports.list()
self.assertList(items, listed["imports"])
self.assertQueryStringIs("")
def test_delete_import(self):
ref = self.new_ref()
parts = ["zones", "tasks", "imports", ref["id"]]
self.stub_url('DELETE', parts=parts, json=ref)
self.stub_entity("DELETE", parts=parts, id=ref["id"])
self.client.zone_imports.delete(ref["id"])
self.assertRequestBodyIs(None)

View File

@@ -1,198 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 json
import os
import uuid
from debtcollector import removals
from keystoneauth1 import adapter
from keystoneauth1.identity import generic
from keystoneauth1 import session as ks_session
from keystoneauth1 import token_endpoint
import pkg_resources
import six
from designateclient import exceptions
def resource_string(*args, **kwargs):
if len(args) == 0:
raise ValueError()
package = kwargs.pop('package', None)
if not package:
package = 'designateclient'
resource_path = os.path.join('resources', *args)
if not pkg_resources.resource_exists(package, resource_path):
raise exceptions.ResourceNotFound('Could not find the requested '
'resource: %s' % resource_path)
return pkg_resources.resource_string(package, resource_path)
def load_schema(version, name, package=None):
schema_string = resource_string('schemas', version, '%s.json' % name,
package=package)
return json.loads(schema_string.decode('utf-8'))
def get_item_properties(item, fields, mixed_case_fields=[], formatters={}):
"""Return a tuple containing the item properties.
:param item: a single item resource (e.g. Server, Tenant, etc)
:param fields: tuple of strings with the desired field names
:param mixed_case_fields: tuple of field names to preserve case
:param formatters: dictionary mapping field names to callables
to format the values
"""
row = []
for field in fields:
if field in formatters:
row.append(formatters[field](item))
else:
if field in mixed_case_fields:
field_name = field.replace(' ', '_')
else:
field_name = field.lower().replace(' ', '_')
if not hasattr(item, field_name) and \
(isinstance(item, dict) and field_name in item):
data = item[field_name]
else:
data = getattr(item, field_name, '')
if data is None:
data = ''
row.append(data)
return tuple(row)
def get_columns(data):
"""
Some row's might have variable count of columns, ensure that we have the
same.
:param data: Results in [{}, {]}]
"""
columns = set()
def _seen(col):
columns.add(str(col))
six.moves.map(lambda item: six.moves.map(_seen,
list(six.iterkeys(item))), data)
return list(columns)
@removals.removed_kwarg('all_tenants', removal_version='1.3.0')
@removals.removed_kwarg('edit_managed', removal_version='1.3.0')
def get_session(auth_url, endpoint, domain_id, domain_name, project_id,
project_name, project_domain_name, project_domain_id, username,
user_id, password, user_domain_id, user_domain_name, token,
insecure, cacert, all_tenants=False, edit_managed=False):
# NOTE: all_tenants and edit_managed are here for backwards compat
# reasons, do not add additional modifiers here.
session = ks_session.Session()
# Build + Attach Authentication Plugin
auth_args = {
'auth_url': auth_url,
'domain_id': domain_id,
'domain_name': domain_name,
'project_id': project_id,
'project_name': project_name,
'project_domain_name': project_domain_name,
'project_domain_id': project_domain_id,
}
if token and endpoint:
session.auth = token_endpoint.Token(endpoint, token)
elif token:
auth_args.update({
'token': token
})
session.auth = generic.Token(**auth_args)
else:
auth_args.update({
'username': username,
'user_id': user_id,
'password': password,
'user_domain_id': user_domain_id,
'user_domain_name': user_domain_name,
})
session.auth = generic.Password(**auth_args)
# SSL/TLS Server Cert Verification
if insecure is True:
session.verify = False
else:
session.verify = cacert
# NOTE: all_tenants and edit_managed are here for backwards compat
# reasons, do not add additional modifiers here.
session.all_tenants = all_tenants
session.edit_managed = edit_managed
return session
def find_resourceid_by_name_or_id(resource_client, name_or_id):
"""Find resource id from its id or name."""
try:
# Try to return an uuid
return str(uuid.UUID(name_or_id))
except ValueError:
# Not an uuid => assume it is resource name
pass
resources = resource_client.list()
candidate_ids = [r['id'] for r in resources if r.get('name') == name_or_id]
if not candidate_ids:
raise exceptions.ResourceNotFound(
'Could not find resource with name "%s"' % name_or_id)
elif len(candidate_ids) > 1:
str_ids = ','.join(candidate_ids)
raise exceptions.NoUniqueMatch(
'Multiple resources with name "%s": %s' % (name_or_id, str_ids))
return candidate_ids[0]
class AdapterWithTimeout(adapter.Adapter):
"""adapter.Adapter wraps around a Session.
The user can pass a timeout keyword that will apply only to
the Designate Client, in order:
- timeout keyword passed to ``request()``
- timeout keyword passed to ``AdapterWithTimeout()``
- timeout attribute on keystone session
"""
def __init__(self, *args, **kw):
self.timeout = kw.pop('timeout', None)
super(self.__class__, self).__init__(*args, **kw)
def request(self, *args, **kwargs):
if self.timeout is not None:
kwargs.setdefault('timeout', self.timeout)
return super(AdapterWithTimeout, self).request(*args, **kwargs)

View File

@@ -1,161 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 debtcollector import removals
from stevedore import extension
from designateclient import exceptions
from designateclient import utils
from designateclient import version
@removals.removed_class(
'designateclient.v1.Client',
replacement='designateclient.v2.client.Client',
message='Designate v1 API is being retired, and the v1 Client class will '
'stop functioning. Please update code to the '
'designateclient.v2.client.Client class. The API is deprecated',
version='2.2.0',
removal_version='?',
stacklevel=3)
class Client(object):
"""Client for the Designate v1 API"""
def __init__(self, endpoint=None, username=None, user_id=None,
user_domain_id=None, user_domain_name=None, password=None,
tenant_name=None, tenant_id=None, domain_name=None,
domain_id=None, project_name=None,
project_id=None, project_domain_name=None,
project_domain_id=None, auth_url=None, token=None,
endpoint_type='publicURL', region_name=None,
service_type='dns', insecure=False, session=None,
cacert=None, all_tenants=None, edit_managed=None,
timeout=None):
"""
:param endpoint: Endpoint URL
:param token: A token instead of username / password
:param insecure: Allow "insecure" HTTPS requests
"""
if endpoint:
endpoint = endpoint.rstrip('/')
if not endpoint.endswith('v1'):
endpoint = "%s/v1" % endpoint
# Compatibility code to mimic the old behaviour of the client
if session is None:
session = utils.get_session(
auth_url=auth_url,
endpoint=endpoint,
domain_id=domain_id,
domain_name=domain_name,
project_id=project_id or tenant_id,
project_name=project_name or tenant_name,
project_domain_name=project_domain_name,
project_domain_id=project_domain_id,
username=username,
user_id=user_id,
password=password,
user_domain_id=user_domain_id,
user_domain_name=user_domain_name,
token=token,
insecure=insecure,
cacert=cacert,
)
# NOTE: all_tenants and edit_managed are pulled from the session for
# backwards compat reasons, do not pull additional modifiers from
# here. Once removed, the kwargs above should default to False.
if all_tenants is None:
self.all_tenants = getattr(session, 'all_tenants', False)
else:
self.all_tenants = all_tenants
if edit_managed is None:
self.edit_managed = getattr(session, 'edit_managed', False)
else:
self.edit_managed = edit_managed
# Since we have to behave nicely like a legacy client/bindings we use
# an adapter around the session to not modify it's state.
interface = endpoint_type.rstrip('URL')
self.session = utils.AdapterWithTimeout(
session,
auth=session.auth,
endpoint_override=endpoint,
region_name=region_name,
service_type=service_type,
interface=interface,
user_agent='python-designateclient-%s' % version.version_info,
version='1',
timeout=timeout,
)
def _load_controller(ext):
controller = ext.plugin(client=self)
setattr(self, ext.name, controller)
# Load all controllers
mgr = extension.ExtensionManager('designateclient.v1.controllers')
mgr.map(_load_controller)
def wrap_api_call(self, func, *args, **kw):
"""
Wrap a self.<rest function> with exception handling
:param func: The function to wrap
"""
kw['raise_exc'] = False
kw.setdefault('headers', {})
kw['headers'].setdefault('Content-Type', 'application/json')
if self.all_tenants:
kw['headers'].update({'X-Auth-All-Projects': 'true'})
if self.edit_managed:
kw['headers'].update({'X-Designate-Edit-Managed-Records': 'true'})
# Trigger the request
response = func(*args, **kw)
# Decode is response, if possible
try:
response_payload = response.json()
except ValueError:
response_payload = {}
if response.status_code == 400:
raise exceptions.BadRequest(**response_payload)
elif response.status_code in (401, 403, 413):
raise exceptions.Forbidden(**response_payload)
elif response.status_code == 404:
raise exceptions.NotFound(**response_payload)
elif response.status_code == 409:
raise exceptions.Conflict(**response_payload)
elif response.status_code >= 500:
raise exceptions.Unknown(**response_payload)
else:
return response
def get(self, path, **kw):
return self.wrap_api_call(self.session.get, path, **kw)
def post(self, path, **kw):
return self.wrap_api_call(self.session.post, path, **kw)
def put(self, path, **kw):
return self.wrap_api_call(self.session.put, path, **kw)
def delete(self, path, **kw):
return self.wrap_api_call(self.session.delete, path, **kw)

View File

@@ -1,27 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 designateclient import client
class DiagnosticsController(client.Controller):
def ping(self, service, host):
"""
Ping a service on a given host
"""
response = self.client.get('/diagnostics/ping/%s/%s' %
(service, host))
return response.json()

View File

@@ -1,92 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 json
from designateclient import client
from designateclient import utils
from designateclient import warlock
Domain = warlock.model_factory(utils.load_schema('v1', 'domain'))
Server = warlock.model_factory(utils.load_schema('v1', 'server'))
class DomainsController(client.CrudController):
def list(self):
"""
Retrieve a list of domains
:returns: A list of :class:`Domain`
"""
response = self.client.get('/domains')
return [Domain(i) for i in response.json()['domains']]
def get(self, domain_id):
"""
Retrieve a domain
:param domain_id: Domain Identifier
:returns: :class:`Domain`
"""
response = self.client.get('/domains/%s' % domain_id)
return Domain(response.json())
def create(self, domain):
"""
Create a domain
:param domain: A :class:`Domain` to create
:returns: :class:`Domain`
"""
response = self.client.post('/domains', data=json.dumps(domain))
return Domain(response.json())
def update(self, domain):
"""
Update a domain
:param domain: A :class:`Domain` to update
:returns: :class:`Domain`
"""
response = self.client.put('/domains/%s' % domain.id,
data=json.dumps(domain.changes))
return Domain(response.json())
def delete(self, domain):
"""
Delete a domain
:param domain: A :class:`Domain`, or Domain Identifier to delete
"""
if isinstance(domain, Domain):
self.client.delete('/domains/%s' % domain.id)
else:
self.client.delete('/domains/%s' % domain)
def list_domain_servers(self, domain_id):
"""
Retrieve the list of nameservers for a domain
:param domain_id: Domain Identifier
:returns: A list of :class:`Server`
"""
response = self.client.get('/domains/%s/servers' % domain_id)
return [Server(i) for i in response.json()['servers']]

View File

@@ -1,38 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 json
from designateclient import client
class QuotasController(client.Controller):
def get(self, tenant_id):
"""
Ping a service on a given host
"""
response = self.client.get('/quotas/%s' % tenant_id)
return response.json()
def update(self, tenant_id, values):
response = self.client.put('/quotas/%s' % tenant_id,
data=json.dumps(values))
return response.json()
def reset(self, tenant_id):
response = self.client.delete('/quotas/%s' % tenant_id)
return response

View File

@@ -1,115 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 json
from designateclient import client
from designateclient import utils
from designateclient.v1.domains import Domain
from designateclient import warlock
Record = warlock.model_factory(utils.load_schema('v1', 'record'))
class RecordsController(client.CrudController):
def list(self, domain):
"""
Retrieve a list of records
:param domain: :class:`Domain` or Domain Identifier
:returns: A list of :class:`Record`
"""
domain_id = domain.id if isinstance(domain, Domain) else domain
response = self.client.get('/domains/%(domain_id)s/records' % {
'domain_id': domain_id
})
return [Record(i) for i in response.json()['records']]
def get(self, domain, record_id):
"""
Retrieve a record
:param domain: :class:`Domain` or Domain Identifier
:param record_id: Record Identifier
:returns: :class:`Record`
"""
domain_id = domain.id if isinstance(domain, Domain) else domain
uri = '/domains/%(domain_id)s/records/%(record_id)s' % {
'domain_id': domain_id,
'record_id': record_id
}
response = self.client.get(uri)
return Record(response.json())
def create(self, domain, record):
"""
Create a record
:param domain: :class:`Domain` or Domain Identifier
:param record: A :class:`Record` to create
:returns: :class:`Record`
"""
domain_id = domain.id if isinstance(domain, Domain) else domain
uri = '/domains/%(domain_id)s/records' % {
'domain_id': domain_id
}
response = self.client.post(uri, data=json.dumps(record))
return Record(response.json())
def update(self, domain, record):
"""
Update a record
:param domain: :class:`Domain` or Domain Identifier
:param record: A :class:`Record` to update
:returns: :class:`Record`
"""
domain_id = domain.id if isinstance(domain, Domain) else domain
uri = '/domains/%(domain_id)s/records/%(record_id)s' % {
'domain_id': domain_id,
'record_id': record.id
}
response = self.client.put(uri, data=json.dumps(record.changes))
return Record(response.json())
def delete(self, domain, record):
"""
Delete a record
:param domain: :class:`Domain` or Domain Identifier
:param record: A :class:`Record`, or Record Identifier to delete
"""
domain_id = domain.id if isinstance(domain, Domain) else domain
record_id = record.id if isinstance(record, Record) else record
uri = '/domains/%(domain_id)s/records/%(record_id)s' % {
'domain_id': domain_id,
'record_id': record_id
}
self.client.delete(uri)

View File

@@ -1,67 +0,0 @@
# Copyright 2013 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# Author: Patrick Galbraith <patg@patg.net>
#
# 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 designateclient import client
class ReportsController(client.Controller):
def count_all(self):
"""
Domain, Records and tenant total count
"""
response = self.client.get('/reports/counts')
return response.json()
def count_domains(self):
"""
Domain total count
"""
response = self.client.get('/reports/counts/domains')
return response.json()
def count_tenants(self):
"""
Tenant total count
"""
response = self.client.get('/reports/counts/tenants')
return response.json()
def count_records(self):
"""
Record total count
"""
response = self.client.get('/reports/counts/records')
return response.json()
def tenants_all(self):
"""
Per tenant count
"""
response = self.client.get('/reports/tenants')
return response.json()['tenants']
def tenant_domains(self, other_tenant_id):
"""
Tenant's domain count
"""
response = self.client.get('/reports/tenants/%s' %
other_tenant_id)
return [{'domain': d} for d in response.json()['domains']]

View File

@@ -1,81 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 json
from designateclient import client
from designateclient import utils
from designateclient import warlock
Server = warlock.model_factory(utils.load_schema('v1', 'server'))
class ServersController(client.CrudController):
def list(self):
"""
Retrieve a list of servers
:returns: A list of :class:`Server`
"""
response = self.client.get('/servers')
return [Server(i) for i in response.json()['servers']]
def get(self, server_id):
"""
Retrieve a server
:param server_id: Server Identifier
:returns: :class:`Server`
"""
response = self.client.get('/servers/%s' % server_id)
return Server(response.json())
def create(self, server):
"""
Create a server
:param server: A :class:`Server` to create
:returns: :class:`Server`
"""
response = self.client.post('/servers', data=json.dumps(server))
return Server(response.json())
def update(self, server):
"""
Update a server
:param server: A :class:`Server` to update
:returns: :class:`Server`
"""
response = self.client.put('/servers/%s' % server.id,
data=json.dumps(server.changes))
return Server(response.json())
def delete(self, server):
"""
Delete a server
:param server: A :class:`Server`, or Server Identifier to delete
"""
if isinstance(server, Server):
self.client.delete('/servers/%s' % server.id)
else:
self.client.delete('/servers/%s' % server)

View File

@@ -1,37 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 designateclient import client
class SyncController(client.Controller):
def sync_all(self):
"""
Sync Everything
"""
self.client.post('/domains/sync')
def sync_domain(self, domain_id):
"""
Sync Single Domain
"""
self.client.post('/domains/%s/sync' % domain_id)
def sync_record(self, domain_id, record_id):
"""
Sync Single Record
"""
self.client.post('/domains/%s/records/%s/sync' %
(domain_id, record_id))

View File

@@ -1,24 +0,0 @@
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# 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 designateclient import client
class TouchController(client.Controller):
def domain(self, domain_id):
"""
Touch a single Domain
"""
self.client.post('/domains/%s/touch' % domain_id)

View File

@@ -1,43 +0,0 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# Author: Graham Hayes <endre.karlson@hp.com>
#
# 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 designateclient import client
from designateclient.v2.utils import parse_query_from_url
class DesignateList(list):
next_link_criterion = {}
next_page = False
class V2Controller(client.Controller):
def _get(self, url, response_key=None, **kwargs):
resp, body = self.client.session.get(url, **kwargs)
if response_key is not None:
data = DesignateList()
data.extend(body[response_key])
if 'next' in body.get('links', {}):
data.next_page = True
data.next_link_criterion = parse_query_from_url(
body['links']['next'])
return data
return body

View File

@@ -1,48 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.v2.base import V2Controller
class BlacklistController(V2Controller):
def create(self, pattern, description=None):
data = {
'pattern': pattern,
}
if description is not None:
data['description'] = description
return self._post('/blacklists', data=data)
def list(self, criterion=None, marker=None, limit=None):
url = self.build_url('/blacklists', criterion, marker, limit)
return self._get(url, response_key="blacklists")
def get(self, blacklist_id):
url = '/blacklists/%s' % blacklist_id
return self._get(url)
def update(self, blacklist_id, values):
url = '/blacklists/%s' % blacklist_id
return self._patch(url, data=values)
def delete(self, blacklist_id):
url = '/blacklists/%s' % blacklist_id
return self._delete(url)

View File

@@ -1,155 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 logging
from osc_lib.command import command
import six
from designateclient import utils
from designateclient.v2.cli import common
from designateclient.v2.utils import get_all
LOG = logging.getLogger(__name__)
def _format_blacklist(blacklist):
# Remove unneeded fields for display output formatting
blacklist.pop('links', None)
class ListBlacklistsCommand(command.Lister):
"""List blacklists"""
columns = ['id', 'pattern', 'description']
def get_parser(self, prog_name):
parser = super(ListBlacklistsCommand, self).get_parser(prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
cols = self.columns
data = get_all(client.blacklists.list)
return cols, (utils.get_item_properties(s, cols) for s in data)
class ShowBlacklistCommand(command.ShowOne):
"""Show blacklist details"""
def get_parser(self, prog_name):
parser = super(ShowBlacklistCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Blacklist ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.blacklists.get(parsed_args.id)
_format_blacklist(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class CreateBlacklistCommand(command.ShowOne):
"""Create new blacklist"""
def get_parser(self, prog_name):
parser = super(CreateBlacklistCommand, self).get_parser(prog_name)
parser.add_argument('--pattern', help="Blacklist pattern",
required=True)
parser.add_argument('--description', help="Description")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.blacklists.create(
parsed_args.pattern, parsed_args.description)
_format_blacklist(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetBlacklistCommand(command.ShowOne):
"""Set blacklist properties"""
def get_parser(self, prog_name):
parser = super(SetBlacklistCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Blacklist ID")
parser.add_argument('--pattern', help="Blacklist pattern")
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
data = {}
if parsed_args.pattern:
data['pattern'] = parsed_args.pattern
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
updated = client.blacklists.update(parsed_args.id, data)
_format_blacklist(updated)
return six.moves.zip(*sorted(six.iteritems(updated)))
class DeleteBlacklistCommand(command.Command):
"""Delete blacklist"""
def get_parser(self, prog_name):
parser = super(DeleteBlacklistCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Blacklist ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
client.blacklists.delete(parsed_args.id)
LOG.info('Blacklist %s was deleted', parsed_args.id)

View File

@@ -1,74 +0,0 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# Author: Graham Hayes <endre.karlson@hp.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
def add_all_projects_option(parser):
parser.add_argument(
'--all-projects',
default=False,
action='store_true',
help='Show results from all projects. Default: False'
)
def add_edit_managed_option(parser):
parser.add_argument(
'--edit-managed',
default=False,
action='store_true',
help='Edit resources marked as managed. Default: False'
)
def add_sudo_project_id_option(parser):
parser.add_argument(
'--sudo-project-id',
default=None,
help='Project ID to impersonate for this command. Default: None'
)
def add_all_common_options(parser):
add_all_projects_option(parser)
add_edit_managed_option(parser)
add_sudo_project_id_option(parser)
def set_all_projects(client, value):
client.session.all_projects = value
def set_sudo_project_id(client, value):
client.session.sudo_project_id = value
def set_edit_managed(client, value):
client.session.edit_managed = value
def set_all_common_headers(client, parsed_args):
if parsed_args.all_projects is not None and \
isinstance(parsed_args.all_projects, bool):
set_all_projects(client, parsed_args.all_projects)
if parsed_args.edit_managed is not None and \
isinstance(parsed_args.edit_managed, bool):
set_edit_managed(client, parsed_args.edit_managed)
if parsed_args.sudo_project_id is not None and \
isinstance(parsed_args.sudo_project_id, str):
set_sudo_project_id(client, parsed_args.sudo_project_id)

View File

@@ -1,133 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 itertools
import logging
from cliff import command
from cliff import show
import six
from designateclient.v2.cli import common
LOG = logging.getLogger(__name__)
DNS_QUOTAS = {
"api_export_size": "api-export-size",
"recordset_records": "recordset-records",
"zone_records": "zone-records",
"zone_recordsets": "zone-recordsets",
"zones": "zones"
}
class ListQuotasCommand(show.ShowOne):
"""List quotas"""
# columns = ['resource', 'hard_limit']
def get_parser(self, prog_name):
parser = super(ListQuotasCommand, self).get_parser(prog_name)
common.add_all_common_options(parser)
parser.add_argument(
'--project-id',
help="Project ID Default: current project")
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
proj_id = parsed_args.project_id or client.session.get_project_id()
if parsed_args.project_id != client.session.get_project_id():
common.set_all_projects(client, True)
data = client.quotas.list(proj_id)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetQuotasCommand(show.ShowOne):
"""Set blacklist properties"""
def _build_options_list(self):
return itertools.chain(DNS_QUOTAS.items())
def get_parser(self, prog_name):
parser = super(SetQuotasCommand, self).get_parser(prog_name)
common.add_all_common_options(parser)
parser.add_argument('--project-id', help="Project ID")
for k, v in self._build_options_list():
parser.add_argument(
'--%s' % v,
metavar='<%s>' % v,
dest=k,
type=int,
help='New value for the %s quota' % v,
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
quotas = {}
for k, v in DNS_QUOTAS.items():
value = getattr(parsed_args, k, None)
if value is not None:
quotas[k] = value
proj_id = parsed_args.project_id or client.session.get_project_id()
if parsed_args.project_id != client.session.get_project_id():
common.set_all_projects(client, True)
updated = client.quotas.update(proj_id, quotas)
return six.moves.zip(*sorted(six.iteritems(updated)))
class ResetQuotasCommand(command.Command):
"""Delete blacklist"""
def get_parser(self, prog_name):
parser = super(ResetQuotasCommand, self).get_parser(prog_name)
common.add_all_common_options(parser)
parser.add_argument('--project-id', help="Project ID")
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
proj_id = parsed_args.project_id or client.session.get_project_id()
if parsed_args.project_id != client.session.get_project_id():
common.set_all_projects(client, True)
client.quotas.reset(proj_id)
LOG.info('Quota for project %s was reset', parsed_args.project_id)

View File

@@ -1,246 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 logging
from osc_lib.command import command
import six
from designateclient import utils
from designateclient.v2.cli import common
from designateclient.v2.utils import get_all
LOG = logging.getLogger(__name__)
def _format_recordset(recordset):
# Remove unneeded fields for display output formatting
recordset['records'] = "\n".join(recordset['records'])
recordset.pop('links', None)
return recordset
def _has_project_id(data):
if len(data) < 1:
return False
if 'project_id' in data[0]:
return True
return False
class ListRecordSetsCommand(command.Lister):
"""List recordsets"""
columns = ['id', 'name', 'type', 'records', 'status', 'action']
def get_parser(self, prog_name):
parser = super(ListRecordSetsCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="RecordSet Name", required=False)
parser.add_argument('--type', help="RecordSet Type", required=False)
parser.add_argument('--data', help="RecordSet Record Data",
required=False)
parser.add_argument('--ttl', help="Time To Live (Seconds)",
required=False)
parser.add_argument('--description', help="Description",
required=False)
parser.add_argument('--status', help="RecordSet Status",
required=False)
parser.add_argument('--action', help="RecordSet Action",
required=False)
parser.add_argument('zone_id', help="Zone ID. To list all"
" recordsets specify 'all'")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
criterion = {}
if parsed_args.type is not None:
criterion["type"] = parsed_args.type
if parsed_args.name is not None:
criterion["name"] = parsed_args.name
if parsed_args.data is not None:
criterion["data"] = parsed_args.data
if parsed_args.ttl is not None:
criterion["ttl"] = parsed_args.ttl
if parsed_args.description is not None:
criterion["description"] = parsed_args.description
if parsed_args.status is not None:
criterion["status"] = parsed_args.status
if parsed_args.action is not None:
criterion["action"] = parsed_args.action
cols = self.columns
if parsed_args.zone_id == 'all':
data = get_all(client.recordsets.list_all_zones,
criterion=criterion)
cols.insert(2, 'zone_name')
else:
data = get_all(client.recordsets.list, args=[parsed_args.zone_id],
criterion=criterion)
if client.session.all_projects and _has_project_id(data):
cols.insert(1, 'project_id')
for i, rs in enumerate(data):
data[i] = _format_recordset(rs)
return cols, (utils.get_item_properties(s, cols) for s in data)
class ShowRecordSetCommand(command.ShowOne):
"""Show recordset details"""
def get_parser(self, prog_name):
parser = super(ShowRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.get(parsed_args.zone_id, parsed_args.id)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class CreateRecordSetCommand(command.ShowOne):
"""Create new recordset"""
def get_parser(self, prog_name):
parser = super(CreateRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('name', help="RecordSet Name")
parser.add_argument('--records', help="RecordSet Records",
nargs='+', required=True)
parser.add_argument('--type', help="RecordSet Type", required=True)
parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)")
parser.add_argument('--description', help="Description")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.create(
parsed_args.zone_id,
parsed_args.name,
parsed_args.type,
parsed_args.records,
description=parsed_args.description,
ttl=parsed_args.ttl)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetRecordSetCommand(command.ShowOne):
"""Set recordset properties"""
def get_parser(self, prog_name):
parser = super(SetRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
parser.add_argument('--records', help="Records", nargs='+')
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
ttl_group = parser.add_mutually_exclusive_group()
ttl_group.add_argument('--ttl', type=int, help="TTL")
ttl_group.add_argument('--no-ttl', action='store_true')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
data = {}
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
if parsed_args.no_ttl:
data['ttl'] = None
elif parsed_args.ttl:
data['ttl'] = parsed_args.ttl
if parsed_args.records:
data['records'] = parsed_args.records
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
updated = client.recordsets.update(
parsed_args.zone_id,
parsed_args.id,
data)
_format_recordset(updated)
return six.moves.zip(*sorted(six.iteritems(updated)))
class DeleteRecordSetCommand(command.ShowOne):
"""Delete recordset"""
def get_parser(self, prog_name):
parser = super(DeleteRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.delete(parsed_args.zone_id, parsed_args.id)
LOG.info('RecordSet %s was deleted', parsed_args.id)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))

View File

@@ -1,142 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 logging
from osc_lib.command import command
import six
from designateclient import utils
from designateclient.v2.cli import common
from designateclient.v2.utils import get_all
LOG = logging.getLogger(__name__)
def _format_floatingip(fip):
# Remove unneeded fields for display output formatting
fip.pop('links', None)
class ListFloatingIPCommand(command.Lister):
"""List floatingip ptr records"""
columns = ['id', 'ptrdname', 'description', 'ttl']
def get_parser(self, prog_name):
parser = super(ListFloatingIPCommand, self).get_parser(prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
cols = self.columns
data = get_all(client.floatingips.list)
return cols, (utils.get_item_properties(s, cols) for s in data)
class ShowFloatingIPCommand(command.ShowOne):
"""Show floatingip ptr record details"""
def get_parser(self, prog_name):
parser = super(ShowFloatingIPCommand, self).get_parser(prog_name)
parser.add_argument('floatingip_id', help="Floating IP ID in format "
"region:floatingip_id")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.floatingips.get(parsed_args.floatingip_id)
_format_floatingip(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetFloatingIPCommand(command.ShowOne):
"""Set floatingip ptr record"""
def get_parser(self, prog_name):
parser = super(SetFloatingIPCommand, self).get_parser(prog_name)
parser.add_argument('floatingip_id', help="Floating IP ID in format "
"region:floatingip_id")
parser.add_argument('ptrdname', help="PTRD Name")
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
ttl_group = parser.add_mutually_exclusive_group()
ttl_group.add_argument('--ttl', type=int, help="TTL")
ttl_group.add_argument('--no-ttl', action='store_true')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
data = {}
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
if parsed_args.no_ttl:
data['ttl'] = None
elif parsed_args.ttl:
data['ttl'] = parsed_args.ttl
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
fip = client.floatingips.set(
parsed_args.floatingip_id,
parsed_args.ptrdname,
parsed_args.description,
parsed_args.ttl)
_format_floatingip(fip)
return six.moves.zip(*sorted(six.iteritems(fip)))
class UnsetFloatingIPCommand(command.Command):
"""Unset floatingip ptr record"""
def get_parser(self, prog_name):
parser = super(UnsetFloatingIPCommand, self).get_parser(prog_name)
parser.add_argument('floatingip_id', help="Floating IP ID in format "
"region:floatingip_id")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
client.floatingips.unset(parsed_args.floatingip_id)
LOG.info('FloatingIP PTR %s was unset', parsed_args.floatingip_id)

View File

@@ -1,94 +0,0 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 logging
from osc_lib.command import command
import six
from designateclient import utils
from designateclient.v2.cli import common
from designateclient.v2 import utils as v2_utils
LOG = logging.getLogger(__name__)
def _format_status(status):
status.pop("links", None)
# Remove unneeded fields for display output formatting
for k in ("capabilities", "stats"):
status[k] = "\n".join(status[k]) if status[k] else "-"
return status
class ListServiceStatusesCommand(command.Lister):
"""List service statuses"""
columns = ['id', 'hostname', 'service_name', 'status', 'stats',
'capabilities']
def get_parser(self, prog_name):
parser = super(ListServiceStatusesCommand, self).get_parser(prog_name)
parser.add_argument("--hostname", help="Hostname", required=False)
parser.add_argument("--service_name", help="Service Name",
required=False)
parser.add_argument("--status", help="Status", required=False)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
cols = self.columns
criterion = {}
for i in ["hostname", "service_name", "status"]:
v = getattr(parsed_args, i)
if v is not None:
criterion[i] = v
data = v2_utils.get_all(client.service_statuses.list,
criterion=criterion)
for i, s in enumerate(data):
data[i] = _format_status(s)
return cols, (utils.get_item_properties(s, cols) for s in data)
class ShowServiceStatusCommand(command.ShowOne):
"""Show service status details"""
def get_parser(self, prog_name):
parser = super(ShowServiceStatusCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Service Status ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.service_statuses.get(parsed_args.id)
_format_status(data)
return six.moves.zip(*sorted(six.iteritems(data)))

View File

@@ -1,154 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 logging
from osc_lib.command import command
import six
from designateclient import utils
from designateclient.v2.cli import common
from designateclient.v2.utils import get_all
LOG = logging.getLogger(__name__)
def _format_tld(tld):
# Remove unneeded fields for display output formatting
tld.pop('links', None)
class ListTLDsCommand(command.Lister):
"""List tlds"""
columns = ['id', 'name', 'description']
def get_parser(self, prog_name):
parser = super(ListTLDsCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="TLD NAME")
parser.add_argument('--description', help="TLD Description")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = get_all(client.tlds.list)
cols = self.columns
return cols, (utils.get_item_properties(s, cols) for s in data)
class ShowTLDCommand(command.ShowOne):
"""Show tld details"""
def get_parser(self, prog_name):
parser = super(ShowTLDCommand, self).get_parser(prog_name)
parser.add_argument('id', help="TLD ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.tlds.get(parsed_args.id)
_format_tld(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class CreateTLDCommand(command.ShowOne):
"""Create new tld"""
def get_parser(self, prog_name):
parser = super(CreateTLDCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="TLD Name", required=True)
parser.add_argument('--description', help="Description")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.tlds.create(parsed_args.name, parsed_args.description)
_format_tld(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetTLDCommand(command.ShowOne):
"""Set tld properties"""
def get_parser(self, prog_name):
parser = super(SetTLDCommand, self).get_parser(prog_name)
parser.add_argument('id', help="TLD ID")
parser.add_argument('--name', help="TLD Name")
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
data = {}
if parsed_args.name:
data['name'] = parsed_args.name
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.tlds.update(parsed_args.id, data)
_format_tld(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class DeleteTLDCommand(command.Command):
"""Delete tld"""
def get_parser(self, prog_name):
parser = super(DeleteTLDCommand, self).get_parser(prog_name)
parser.add_argument('id', help="TLD ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
client.tlds.delete(parsed_args.id)
LOG.info('TLD %s was deleted', parsed_args.id)

View File

@@ -1,716 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 logging
from osc_lib.command import command
from osc_lib import exceptions as osc_exc
import six
from designateclient import utils
from designateclient.v2.cli import common
from designateclient.v2.utils import get_all
LOG = logging.getLogger(__name__)
def _format_zone(zone):
zone.pop('links', None)
zone['masters'] = ", ".join(zone['masters'])
attrib = ''
for attr in zone['attributes']:
attrib += "%s:%s\n" % (attr, zone['attributes'][attr])
zone['attributes'] = attrib
def _format_zone_export_record(zone_export_record):
zone_export_record.pop('links', None)
def _format_zone_import_record(zone_import_record):
zone_import_record.pop('links', None)
class ListZonesCommand(command.Lister):
"""List zones"""
columns = ['id', 'name', 'type', 'serial', 'status', 'action']
def get_parser(self, prog_name):
parser = super(ListZonesCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="Zone Name", required=False)
parser.add_argument('--email', help="Zone Email", required=False)
parser.add_argument('--type', help="Zone Type", required=False)
parser.add_argument('--ttl', help="Time To Live (Seconds)",
required=False)
parser.add_argument('--description', help="Description",
required=False)
parser.add_argument('--status', help="Zone Status", required=False)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
common.set_all_common_headers(client, parsed_args)
criterion = {}
if parsed_args.type is not None:
criterion["type"] = parsed_args.type
if parsed_args.name is not None:
criterion["name"] = parsed_args.name
if parsed_args.ttl is not None:
criterion["ttl"] = parsed_args.ttl
if parsed_args.description is not None:
criterion["description"] = parsed_args.description
if parsed_args.email is not None:
criterion["email"] = parsed_args.email
if parsed_args.status is not None:
criterion["status"] = parsed_args.status
data = get_all(client.zones.list, criterion)
cols = self.columns
if client.session.all_projects:
cols.insert(1, 'project_id')
return cols, (utils.get_item_properties(s, cols) for s in data)
class ShowZoneCommand(command.ShowOne):
"""Show zone details"""
def get_parser(self, prog_name):
parser = super(ShowZoneCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Zone ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zones.get(parsed_args.id)
_format_zone(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class CreateZoneCommand(command.ShowOne):
"""Create new zone"""
def get_parser(self, prog_name):
parser = super(CreateZoneCommand, self).get_parser(prog_name)
parser.add_argument('name', help="Zone Name")
parser.add_argument('--email', help="Zone Email")
parser.add_argument('--type', help="Zone Type", default='PRIMARY')
parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)")
parser.add_argument('--description', help="Description")
parser.add_argument('--masters', help="Zone Masters", nargs='+')
parser.add_argument('--attributes', help="Zone Attributes", nargs='+')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
payload = {}
if parsed_args.description:
payload["description"] = parsed_args.description
if parsed_args.attributes:
payload["attributes"] = {}
for attr in parsed_args.attributes:
try:
k, v = attr.split(':')
payload["attributes"][k] = v
except ValueError:
msg = "Attribute '%s' is in an incorrect format. "\
"Attributes are <key>:<value> formated"
raise osc_exc.CommandError(msg % attr)
if parsed_args.type == 'PRIMARY':
# email is just for PRIMARY.
if not parsed_args.email:
msg = "Zone type PRIMARY requires --email."
raise osc_exc.CommandError(msg)
payload["email"] = parsed_args.email
# TTL is just valid for PRIMARY
if parsed_args.ttl is not None:
payload["ttl"] = parsed_args.ttl
elif parsed_args.type == 'SECONDARY':
payload["masters"] = parsed_args.masters
else:
msg = "Type %s is not supported. Please choose between " \
"PRIMARY or SECONDARY"
raise osc_exc.CommandError(msg % parsed_args.type)
data = client.zones.create(
parsed_args.name, parsed_args.type, **payload)
_format_zone(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetZoneCommand(command.ShowOne):
"""Set zone properties"""
def get_parser(self, prog_name):
parser = super(SetZoneCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Zone ID")
parser.add_argument('--email', help="Zone Email")
parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)")
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
parser.add_argument('--masters', help="Zone Masters", nargs='+')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = {}
# TODO(kiall): API needs updating.. this get is silly
if parsed_args.email:
data['email'] = parsed_args.email
if parsed_args.ttl:
data['ttl'] = parsed_args.ttl
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
if parsed_args.masters:
data['masters'] = parsed_args.masters
updated = client.zones.update(parsed_args.id, data)
_format_zone(updated)
return six.moves.zip(*sorted(six.iteritems(updated)))
class DeleteZoneCommand(command.ShowOne):
"""Delete zone"""
def get_parser(self, prog_name):
parser = super(DeleteZoneCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Zone ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zones.delete(parsed_args.id)
LOG.info('Zone %s was deleted', parsed_args.id)
_format_zone(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class AbandonZoneCommand(command.Command):
"""Abandon a zone"""
def get_parser(self, prog_name):
parser = super(AbandonZoneCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Zone ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
client.zones.abandon(parsed_args.id)
LOG.info("Z %(zone_id)s abandoned",
{"zone_id": parsed_args.id})
class AXFRZoneCommand(command.Command):
"""AXFR a zone"""
def get_parser(self, prog_name):
parser = super(AXFRZoneCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Zone ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
client.zones.axfr(parsed_args.id)
LOG.info("Scheduled AXFR for zone %(zone_id)s",
{"zone_id": parsed_args.id})
class CreateTransferRequestCommand(command.ShowOne):
"""Create new zone transfer request"""
def get_parser(self, prog_name):
parser = super(CreateTransferRequestCommand, self).get_parser(
prog_name)
parser.add_argument('zone_id', help="Zone ID to transfer.",)
parser.add_argument(
'--target-project-id',
help="Target Project ID to transfer to.")
parser.add_argument('--description', help="Description")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_transfers.create_request(
parsed_args.zone_id, parsed_args.target_project_id,
parsed_args.description)
return six.moves.zip(*sorted(six.iteritems(data)))
class ListTransferRequestsCommand(command.Lister):
"""List Zone Transfer Requests"""
columns = ['id', 'zone_id', 'zone_name', 'project_id',
'target_project_id', 'status', 'key']
def get_parser(self, prog_name):
parser = super(ListTransferRequestsCommand, self).get_parser(
prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_transfers.list_requests()
cols = self.columns
return cols, (utils.get_item_properties(s, cols) for s in data)
class ShowTransferRequestCommand(command.ShowOne):
"""Show Zone Transfer Request Details"""
def get_parser(self, prog_name):
parser = super(ShowTransferRequestCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Zone Tranfer Request ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_transfers.get_request(parsed_args.id)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetTransferRequestCommand(command.ShowOne):
"""Set a Zone Transfer Request"""
def get_parser(self, prog_name):
parser = super(SetTransferRequestCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Zone Transfer Request ID")
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = {}
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
updated = client.zone_transfers.update_request(parsed_args.id, data)
return six.moves.zip(*sorted(six.iteritems(updated)))
class DeleteTransferRequestCommand(command.Command):
"""Delete a Zone Transfer Request"""
def get_parser(self, prog_name):
parser = super(DeleteTransferRequestCommand, self).get_parser(
prog_name)
parser.add_argument('id', help="Zone Transfer Request ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
client.zone_transfers.delete_request(parsed_args.id)
LOG.info('Zone Transfer %s was deleted', parsed_args.id)
class AcceptTransferRequestCommand(command.ShowOne):
"""Accept a Zone Transfer Request"""
def get_parser(self, prog_name):
parser = super(AcceptTransferRequestCommand, self).get_parser(
prog_name)
parser.add_argument('--transfer-id', help="Transfer ID", type=str,
required=True)
parser.add_argument('--key', help="Transfer Key", type=str,
required=True)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_transfers.accept_request(
parsed_args.transfer_id, parsed_args.key)
return six.moves.zip(*sorted(six.iteritems(data)))
class ListTransferAcceptsCommand(command.Lister):
"""List Zone Transfer Accepts"""
columns = ['id', 'zone_id', 'project_id',
'zone_transfer_request_id', 'status', 'key']
def get_parser(self, prog_name):
parser = super(ListTransferAcceptsCommand, self).get_parser(
prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_transfers.list_requests()
cols = self.columns
return cols, (utils.get_item_properties(s, cols) for s in data)
class ShowTransferAcceptCommand(command.ShowOne):
"""Show Zone Transfer Accept"""
def get_parser(self, prog_name):
parser = super(ShowTransferAcceptCommand, self).get_parser(prog_name)
parser.add_argument('id', help="Zone Tranfer Accept ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_transfers.get_accept(parsed_args.id)
return six.moves.zip(*sorted(six.iteritems(data)))
class ExportZoneCommand(command.ShowOne):
"""Export a Zone"""
def get_parser(self, prog_name):
parser = super(ExportZoneCommand, self).get_parser(
prog_name)
common.add_all_common_options(parser)
parser.add_argument('zone_id', help="Zone ID", type=str)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_exports.create(parsed_args.zone_id)
_format_zone_export_record(data)
LOG.info('Zone Export %s was created', data['id'])
return six.moves.zip(*sorted(six.iteritems(data)))
class ListZoneExportsCommand(command.Lister):
"""List Zone Exports"""
columns = [
'id',
'zone_id',
'created_at',
'status',
]
def get_parser(self, prog_name):
parser = super(ListZoneExportsCommand, self).get_parser(
prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_exports.list()
cols = self.columns
return cols, (utils.get_item_properties(s, cols)
for s in data['exports'])
class ShowZoneExportCommand(command.ShowOne):
"""Show a Zone Export"""
def get_parser(self, prog_name):
parser = super(ShowZoneExportCommand, self).get_parser(
prog_name)
parser.add_argument('zone_export_id', help="Zone Export ID", type=str)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_exports.get_export_record(
parsed_args.zone_export_id)
_format_zone_export_record(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class DeleteZoneExportCommand(command.Command):
"""Delete a Zone Export"""
def get_parser(self, prog_name):
parser = super(DeleteZoneExportCommand, self).get_parser(
prog_name)
parser.add_argument('zone_export_id', help="Zone Export ID", type=str)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
client.zone_exports.delete(parsed_args.zone_export_id)
LOG.info('Zone Export %s was deleted', parsed_args.zone_export_id)
class ShowZoneExportFileCommand(command.ShowOne):
"""Show the zone file for the Zone Export"""
def get_parser(self, prog_name):
parser = super(ShowZoneExportFileCommand, self).get_parser(
prog_name)
parser.add_argument('zone_export_id', help="Zone Export ID", type=str)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_exports.get_export(parsed_args.zone_export_id)
return ['data'], [data]
class ImportZoneCommand(command.ShowOne):
"""Import a Zone from a file on the filesystem"""
def get_parser(self, prog_name):
parser = super(ImportZoneCommand, self).get_parser(
prog_name)
parser.add_argument('zone_file_path',
help="Path to a zone file", type=str)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
with open(parsed_args.zone_file_path, 'r') as f:
zone_file_contents = f.read()
data = client.zone_imports.create(zone_file_contents)
_format_zone_import_record(data)
LOG.info('Zone Import %s was created', data['id'])
return six.moves.zip(*sorted(six.iteritems(data)))
class ListZoneImportsCommand(command.Lister):
"""List Zone Imports"""
columns = [
'id',
'zone_id',
'created_at',
'status',
'message',
]
def get_parser(self, prog_name):
parser = super(ListZoneImportsCommand, self).get_parser(
prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_imports.list()
cols = self.columns
return cols, (utils.get_item_properties(s, cols)
for s in data['imports'])
class ShowZoneImportCommand(command.ShowOne):
"""Show a Zone Import"""
def get_parser(self, prog_name):
parser = super(ShowZoneImportCommand, self).get_parser(
prog_name)
parser.add_argument('zone_import_id', help="Zone Import ID", type=str)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
data = client.zone_imports.get_import_record(
parsed_args.zone_import_id)
_format_zone_import_record(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class DeleteZoneImportCommand(command.Command):
"""Delete a Zone Import"""
def get_parser(self, prog_name):
parser = super(DeleteZoneImportCommand, self).get_parser(
prog_name)
parser.add_argument('zone_import_id', help="Zone Import ID", type=str)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
common.set_all_common_headers(client, parsed_args)
client.zone_imports.delete(parsed_args.zone_import_id)
LOG.info('Zone Import %s was deleted', parsed_args.zone_import_id)

View File

@@ -1,140 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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
from designateclient import exceptions
from designateclient.v2.blacklists import BlacklistController
from designateclient.v2.limits import LimitController
from designateclient.v2.nameservers import NameServerController
from designateclient.v2.pools import PoolController
from designateclient.v2.quotas import QuotasController
from designateclient.v2.recordsets import RecordSetController
from designateclient.v2.reverse import FloatingIPController
from designateclient.v2.service_statuses import ServiceStatusesController
from designateclient.v2.tlds import TLDController
from designateclient.v2.zones import ZoneController
from designateclient.v2.zones import ZoneExportsController
from designateclient.v2.zones import ZoneImportsController
from designateclient.v2.zones import ZoneTransfersController
from designateclient import version
class DesignateAdapter(adapter.LegacyJsonAdapter):
"""Adapter around LegacyJsonAdapter.
The user can pass a timeout keyword that will apply only to
the Designate Client, in order:
- timeout keyword passed to ``request()``
- timeout attribute on keystone session
"""
def __init__(self, *args, **kwargs):
self.timeout = kwargs.pop('timeout', None)
self.all_projects = kwargs.pop('all_projects', False)
self.edit_managed = kwargs.pop('edit_managed', False)
self.sudo_project_id = kwargs.pop('sudo_project_id', None)
super(self.__class__, self).__init__(*args, **kwargs)
def request(self, *args, **kwargs):
kwargs.setdefault('raise_exc', False)
if self.timeout is not None:
kwargs.setdefault('timeout', self.timeout)
kwargs.setdefault('headers', {})
if self.all_projects:
kwargs['headers'].setdefault(
'X-Auth-All-Projects',
str(self.all_projects)
)
if self.edit_managed:
kwargs['headers'].setdefault(
'X-Designate-Edit-Managed-Records',
str(self.edit_managed)
)
if self.sudo_project_id is not None:
kwargs['headers'].setdefault(
'X-Auth-Sudo-Project-ID',
self.sudo_project_id
)
kwargs['headers'].setdefault(
'Content-Type', 'application/json')
response, body = super(self.__class__, self).request(*args, **kwargs)
# Decode is response, if possible
try:
response_payload = response.json()
except ValueError:
response_payload = {}
body = response.text
if response.status_code == 400:
raise exceptions.BadRequest(**response_payload)
elif response.status_code in (401, 403):
raise exceptions.Forbidden(**response_payload)
elif response.status_code == 404:
raise exceptions.NotFound(**response_payload)
elif response.status_code == 409:
raise exceptions.Conflict(**response_payload)
elif response.status_code == 413:
raise exceptions.OverQuota(**response_payload)
elif response.status_code >= 500:
raise exceptions.Unknown(**response_payload)
return response, body
class Client(object):
def __init__(self, region_name=None, endpoint_type='publicURL',
extensions=None, service_type='dns', service_name=None,
http_log_debug=False, session=None, auth=None, timeout=None,
endpoint_override=None, all_projects=False,
edit_managed=False, sudo_project_id=None):
if session is None:
raise ValueError("A session instance is required")
self.session = DesignateAdapter(
session,
auth=auth,
region_name=region_name,
service_type=service_type,
interface=endpoint_type.rstrip('URL'),
user_agent='python-designateclient-%s' % version.version_info,
version=('2'),
endpoint_override=endpoint_override,
timeout=timeout,
all_projects=all_projects,
edit_managed=edit_managed,
sudo_project_id=sudo_project_id
)
self.blacklists = BlacklistController(self)
self.floatingips = FloatingIPController(self)
self.limits = LimitController(self)
self.nameservers = NameServerController(self)
self.recordsets = RecordSetController(self)
self.service_statuses = ServiceStatusesController(self)
self.tlds = TLDController(self)
self.zones = ZoneController(self)
self.zone_transfers = ZoneTransfersController(self)
self.zone_exports = ZoneExportsController(self)
self.zone_imports = ZoneImportsController(self)
self.pools = PoolController(self)
self.quotas = QuotasController(self)

View File

@@ -1,21 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.v2.base import V2Controller
class LimitController(V2Controller):
def get(self):
return self._get('/limits')

View File

@@ -1,26 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.v2.base import V2Controller
from designateclient.v2 import utils as v2_utils
class NameServerController(V2Controller):
def list(self, zone):
zone = v2_utils.resolve_by_name(self.client.zones.list, zone)
url = '/zones/%s/nameservers' % zone
return self._get(url, response_key='nameservers')

View File

@@ -1,22 +0,0 @@
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from designateclient.v2.base import V2Controller
class PoolController(V2Controller):
def list(self):
url = '/pools'
return self._get(url, response_key='pools')

View File

@@ -1,27 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.v2.base import V2Controller
class QuotasController(V2Controller):
def list(self, project_id):
return self._get('/quotas/%s' % project_id)
def update(self, project_id, values):
return self._patch('/quotas/%s' % project_id, data=values)
def reset(self, project_id):
return self._delete('/quotas/%s' % project_id)

View File

@@ -1,106 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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_utils import uuidutils
import six
from designateclient.v2.base import V2Controller
from designateclient.v2 import utils as v2_utils
class RecordSetController(V2Controller):
def _canonicalize_record_name(self, zone, name):
zone_info = None
# If we get a zone name we'll need to get the ID of it before POST.
if isinstance(zone, six.string_types) and not \
uuidutils.is_uuid_like(zone):
zone_info = self.client.zones.get(zone)
elif isinstance(zone, dict):
zone_info = zone
# We where given a name like "www" vs www.i.io., attempt to fix it on
# the behalf of the actor.
if not name.endswith("."):
if not isinstance(zone_info, dict):
zone_info = self.client.zones.get(zone)
name = "%s.%s" % (name, zone_info["name"])
return name, zone_info
def create(self, zone, name, type_, records, description=None,
ttl=None):
name, zone_info = self._canonicalize_record_name(zone, name)
data = {
'name': name,
'type': type_,
'records': records
}
if ttl is not None:
data['ttl'] = ttl
if description is not None:
data['description'] = description
if zone_info is not None:
zone_id = zone_info["id"]
else:
zone_id = zone
url = '/zones/%s/recordsets' % zone_id
return self._post(url, data=data)
def list(self, zone, criterion=None, marker=None, limit=None):
zone = v2_utils.resolve_by_name(self.client.zones.list, zone)
url = self.build_url(
'/zones/%s/recordsets' % zone,
criterion, marker, limit)
return self._get(url, response_key='recordsets')
def list_all_zones(self, criterion=None, marker=None, limit=None):
url = self.build_url('/recordsets', criterion, marker, limit)
return self._get(url, response_key='recordsets')
def get(self, zone, recordset):
zone = v2_utils.resolve_by_name(self.client.zones.list, zone)
recordset = v2_utils.resolve_by_name(self.list, recordset, zone)
url = self.build_url('/zones/%s/recordsets/%s' % (
zone, recordset))
return self._get(url)
def update(self, zone, recordset, values):
zone = v2_utils.resolve_by_name(self.client.zones.list, zone)
recordset = v2_utils.resolve_by_name(self.list, recordset, zone)
url = '/zones/%s/recordsets/%s' % (zone, recordset)
return self._put(url, data=values)
def delete(self, zone, recordset):
zone = v2_utils.resolve_by_name(self.client.zones.list, zone)
recordset = v2_utils.resolve_by_name(self.list, recordset, zone)
url = '/zones/%s/recordsets/%s' % (zone, recordset)
return self._delete(url)

View File

@@ -1,49 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.v2.base import V2Controller
class FloatingIPController(V2Controller):
def set(self, floatingip_id, ptrdname, description=None, ttl=None):
data = {
'ptrdname': ptrdname
}
if description is not None:
data["description"] = description
if ttl is not None:
data["ttl"] = ttl
url = '/reverse/floatingips/%s' % floatingip_id
return self._patch(url, data=data)
def list(self, criterion=None):
url = self.build_url('/reverse/floatingips', criterion)
return self._get(url, response_key='floatingips')
def get(self, floatingip_id):
url = '/reverse/floatingips/%s' % floatingip_id
return self._get(url)
def unset(self, floatingip_id):
data = {"ptrdname": None}
url = '/reverse/floatingips/%s' % floatingip_id
return self._patch(url, data=data)

View File

@@ -1,28 +0,0 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.v2 import base
class ServiceStatusesController(base.V2Controller):
def list(self, criterion=None, marker=None, limit=None):
url = self.build_url('/service_statuses', criterion, marker, limit)
return self._get(url, response_key="service_statuses")
def get(self, service_status_id):
url = '/service_statuses/%s' % service_status_id
return self._get(url)

View File

@@ -1,49 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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 designateclient.v2.base import V2Controller
from designateclient.v2 import utils as v2_utils
class TLDController(V2Controller):
def create(self, name, description=None):
data = {
'name': name,
}
if description is not None:
data["description"] = description
return self._post('/tlds', data=data)
def list(self, criterion=None, marker=None, limit=None):
url = self.build_url('/tlds', criterion, marker, limit)
return self._get(url, response_key='tlds')
def get(self, tld):
tld = v2_utils.resolve_by_name(self.list, tld)
return self._get('/tlds/%s' % tld)
def update(self, tld, values):
tld = v2_utils.resolve_by_name(self.list, tld)
return self._patch('/tlds/%s' % tld, data=values)
def delete(self, tld):
tld = v2_utils.resolve_by_name(self.list, tld)
return self._delete('/tlds/%s' % tld)

View File

@@ -1,80 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Endre Karlson <endre.karlson@hp.com>
#
# 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_utils import uuidutils
from six import iteritems
from six import iterkeys
from six.moves.urllib.parse import parse_qs
from six.moves.urllib.parse import urlparse
from designateclient import exceptions
def resolve_by_name(func, name, *args):
"""
Helper to resolve a "name" a'la foo.com to it's ID by using REST api's
query support and filtering on name.
"""
if uuidutils.is_uuid_like(name):
return name
results = func(criterion={"name": "%s" % name}, *args)
length = len(results)
if length == 1:
return results[0]["id"]
elif length == 0:
raise exceptions.NotFound("Name %s didn't resolve" % name)
else:
msg = "Multiple matches found for %s, please use ID instead." % name
raise exceptions.NoUniqueMatch(msg)
def parse_query_from_url(url):
"""
Helper to get key bits of data from the "next" url returned
from the API on collections
:param url:
:return: dict
"""
values = parse_qs(urlparse(url)[4])
return {k: values[k][0] for k in iterkeys(values)}
def get_all(function, criterion=None, args=None):
"""
:param function: Function to be called to get data
:param criterion: dict of filters to be applied
:param args: arguments to be given to the function
:return: DesignateList()
"""
criterion = criterion or {}
args = args or []
data = function(*args, criterion=criterion)
returned_data = data
while True:
if data.next_page:
for k, v in iteritems(data.next_link_criterion):
criterion[k] = v
data = function(*args, criterion=criterion)
returned_data.extend(data)
else:
break
return returned_data

Some files were not shown because too many files have changed in this diff Show More