summaryrefslogtreecommitdiff
path: root/designateclient
diff options
context:
space:
mode:
authorRudolf Vriend <rudolf.vriend@sap.com>2017-07-07 14:00:17 +0200
committerRudolf Vriend <rudolf.vriend@sap.com>2017-07-07 14:16:30 +0200
commitb741282eaff277977507379bbd0de3454eb66232 (patch)
treefdfbebda4ec64f19c390689c517b47ee06f63446 /designateclient
parent3bb401758c00a9d66383484c60933421d9a21d63 (diff)
downloadpython-designateclient-b741282eaff277977507379bbd0de3454eb66232.tar.gz
Add tsig key support to python-designateclient
This fix adds support for the designate tsig keys api to python-designateclient. It will add tsigkey related crud commands to the openstackclient. Change-Id: I84336c3aca85ca62771fd2115481eda32ee980d2 Closes-Bug: #1702506
Diffstat (limited to 'designateclient')
-rw-r--r--designateclient/functionaltests/client.py38
-rw-r--r--designateclient/functionaltests/datagen.py8
-rw-r--r--designateclient/functionaltests/v2/fixtures.py19
-rw-r--r--designateclient/functionaltests/v2/test_tsigkeys.py90
-rw-r--r--designateclient/tests/v2/test_tsigkeys.py96
-rw-r--r--designateclient/v2/cli/tsigkeys.py170
-rw-r--r--designateclient/v2/client.py2
-rw-r--r--designateclient/v2/tsigkeys.py50
8 files changed, 472 insertions, 1 deletions
diff --git a/designateclient/functionaltests/client.py b/designateclient/functionaltests/client.py
index c439edb..1f0fc03 100644
--- a/designateclient/functionaltests/client.py
+++ b/designateclient/functionaltests/client.py
@@ -273,8 +273,44 @@ class TLDCommands(object):
return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
-class BlacklistCommands(object):
+class TSIGKeyCommands(object):
+ def tsigkey_list(self, *args, **kwargs):
+ return self.parsed_cmd('tsigkey list', ListModel, *args, **kwargs)
+
+ def tsigkey_show(self, id, *args, **kwargs):
+ return self.parsed_cmd('tsigkey show {0}'.format(id), FieldValueModel,
+ *args, **kwargs)
+
+ def tsigkey_delete(self, id, *args, **kwargs):
+ return self.parsed_cmd('tsigkey delete {0}'.format(id), *args,
+ **kwargs)
+ def tsigkey_create(self, name, algorithm, secret, scope, resource_id,
+ *args, **kwargs):
+ options_str = build_option_string({
+ '--name': name,
+ '--algorithm': algorithm,
+ '--secret': secret,
+ '--scope': scope,
+ '--resource-id': resource_id,
+ })
+ cmd = 'tsigkey create {0}'.format(options_str)
+ return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs)
+
+ def tsigkey_set(self, id, name=None, algorithm=None, secret=None,
+ scope=None,
+ *args, **kwargs):
+ options_str = build_option_string({
+ '--name': name,
+ '--algorithm': algorithm,
+ '--secret': secret,
+ '--scope': scope,
+ })
+ cmd = 'tsigkey set {0} {1}'.format(id, options_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)
diff --git a/designateclient/functionaltests/datagen.py b/designateclient/functionaltests/datagen.py
index 91f72ba..aaa555f 100644
--- a/designateclient/functionaltests/datagen.py
+++ b/designateclient/functionaltests/datagen.py
@@ -25,6 +25,14 @@ def random_tld(name='testtld'):
return "{0}{1}".format(name, random_digits())
+def random_tsigkey_name(name='testtsig'):
+ return "{0}{1}".format(name, random_digits())
+
+
+def random_tsigkey_secret(name='test-secret'):
+ return "{0}-{1}".format(name, random_digits(254 - len(name)))
+
+
def random_zone_name(name='testdomain', tld='com'):
return "{0}{1}.{2}.".format(name, random_digits(), tld)
diff --git a/designateclient/functionaltests/v2/fixtures.py b/designateclient/functionaltests/v2/fixtures.py
index 67ca404..8e2ff95 100644
--- a/designateclient/functionaltests/v2/fixtures.py
+++ b/designateclient/functionaltests/v2/fixtures.py
@@ -193,6 +193,25 @@ class TLDFixture(BaseFixture):
pass
+class TSIGKeyFixture(BaseFixture):
+ """See DesignateCLI.tsigkey_create for __init__ args"""
+
+ def __init__(self, user='admin', *args, **kwargs):
+ super(TSIGKeyFixture, self).__init__(user=user, *args, **kwargs)
+
+ def _setUp(self):
+ super(TSIGKeyFixture, self)._setUp()
+ self.tsigkey = self.client.tsigkey_create(*self.args, **self.kwargs)
+ self.addCleanup(self.cleanup_tsigkey(self.client, self.tsigkey.id))
+
+ @classmethod
+ def cleanup_tsigkey(cls, client, tsigkey_id):
+ try:
+ client.tsigkey_delete(tsigkey_id)
+ except CommandFailed:
+ pass
+
+
class BlacklistFixture(BaseFixture):
"""See DesignateCLI.zone_blacklist_create for __init__ args"""
diff --git a/designateclient/functionaltests/v2/test_tsigkeys.py b/designateclient/functionaltests/v2/test_tsigkeys.py
new file mode 100644
index 0000000..7ed4d75
--- /dev/null
+++ b/designateclient/functionaltests/v2/test_tsigkeys.py
@@ -0,0 +1,90 @@
+"""
+Copyright 2017 SAP SE
+
+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_tsigkey_name
+from designateclient.functionaltests.datagen import random_tsigkey_secret
+from designateclient.functionaltests.datagen import random_zone_name
+from designateclient.functionaltests.v2.fixtures import TSIGKeyFixture
+from designateclient.functionaltests.v2.fixtures import ZoneFixture
+
+
+class TestTSIGKey(BaseDesignateTest):
+ def setUp(self):
+ super(TestTSIGKey, self).setUp()
+ self.ensure_tsigkey_exists('com')
+ self.zone = self.useFixture(ZoneFixture(
+ name=random_zone_name(),
+ email='test@example.com',
+ )).zone
+ tsig_name = random_tsigkey_name()
+ tsig_algorithm = "hmac-sha256"
+ tsig_secret = random_tsigkey_secret()
+ tsig_scope = 'ZONE'
+ self.tsig = self.useFixture(TSIGKeyFixture(
+ name=tsig_name,
+ algorithm=tsig_algorithm,
+ secret=tsig_secret,
+ scope=tsig_scope,
+ resource_id=self.zone.id
+ )).tsig
+
+ self.assertEqual(self.tsig.name, tsig_name)
+ self.assertEqual(self.tsig.algorithm, tsig_algorithm)
+ self.assertEqual(self.tsig.secret, tsig_secret)
+ self.assertEqual(self.tsig.scope, tsig_scope)
+ self.assertEqual(self.tsig.resource_id, self.zone.id)
+
+ def test_tsigkey_list(self):
+ tsigkeys = self.clients.as_user('admin').tsigkey_list()
+ self.assertGreater(len(tsigkeys), 0)
+
+ def test_tsigkey_create_and_show(self):
+ tsigkey = self.clients.as_user('admin').tsigkey_show(self.tsigkey.id)
+ self.assertEqual(tsigkey.name, self.tsigkey.name)
+ self.assertEqual(tsigkey.created_at, self.tsigkey.created_at)
+ self.assertEqual(tsigkey.id, self.tsigkey.id)
+ self.assertEqual(self.tsig.algorithm, self.tsig_algorithm)
+ self.assertEqual(self.tsig.secret, self.tsig_secret)
+ self.assertEqual(self.tsig.scope, self.tsig_scope)
+ self.assertEqual(self.tsig.resource_id, self.zone.id)
+ self.assertEqual(tsigkey.updated_at, self.tsigkey.updated_at)
+
+ def test_tsigkey_delete(self):
+ client = self.clients.as_user('admin')
+ client.tsigkey_delete(self.tsigkey.id)
+ self.assertRaises(CommandFailed, client.tsigkey_show, self.tsigkey.id)
+
+ def test_tsigkey_set(self):
+ client = self.clients.as_user('admin')
+ updated_name = random_tsigkey_name('updated')
+ tsigkey = client.tsigkey_set(self.tsigkey.id, name=updated_name,
+ secret='An updated tsigsecret')
+ self.assertEqual(tsigkey.secret, 'An updated tsigsecret')
+ self.assertEqual(tsigkey.name, updated_name)
+
+
+class TestTSIGKeyNegative(BaseDesignateTest):
+ def test_tsigkey_invalid_commmand(self):
+ client = self.clients.as_user('admin')
+ self.assertRaises(CommandFailed, client.openstack,
+ 'tsigkey notacommand')
+
+ def test_tsigkey_create_invalid_flag(self):
+ client = self.clients.as_user('admin')
+ self.assertRaises(CommandFailed, client.openstack,
+ 'tsigkey create --notanoption "junk"')
diff --git a/designateclient/tests/v2/test_tsigkeys.py b/designateclient/tests/v2/test_tsigkeys.py
new file mode 100644
index 0000000..6290ffa
--- /dev/null
+++ b/designateclient/tests/v2/test_tsigkeys.py
@@ -0,0 +1,96 @@
+# Copyright 2017 SAP SE
+#
+# Author: Rudolf Vriend <rudolf.vriend@sap.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 TestTSIGKeys(v2.APIV2TestCase, v2.CrudMixin):
+ RESOURCE = 'tsigkeys'
+
+ def new_ref(self, **kwargs):
+ ref = super(TestTSIGKeys, self).new_ref(**kwargs)
+ ref.setdefault("name", uuid.uuid4().hex)
+ ref.setdefault("algorithm", "hmac-sha256")
+ ref.setdefault("secret", uuid.uuid4().hex)
+ ref.setdefault("scope", "POOL")
+ ref.setdefault("resource_id", 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.tsigkeys.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.tsigkeys.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={"tsigkeys": [ref]})
+
+ response = self.client.tsigkeys.get(ref['name'])
+
+ self.assertEqual("GET", self.requests.request_history[0].method)
+ self.assertEqual(
+ "http://127.0.0.1:9001/v2/tsigkeys?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={"tsigkeys": items})
+
+ listed = self.client.tsigkeys.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.tsigkeys.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.tsigkeys.delete(ref["id"])
+ self.assertRequestBodyIs(None)
diff --git a/designateclient/v2/cli/tsigkeys.py b/designateclient/v2/cli/tsigkeys.py
new file mode 100644
index 0000000..b1d42ad
--- /dev/null
+++ b/designateclient/v2/cli/tsigkeys.py
@@ -0,0 +1,170 @@
+# Copyright 2017 SAP SE
+#
+# Author: Rudolf Vriend <rudolf.vriend@sap.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_tsigkey(tsigkey):
+ # Remove unneeded fields for display output formatting
+ tsigkey.pop('links', None)
+
+
+class ListTSIGKeysCommand(command.Lister):
+ """List tsigkeys"""
+
+ columns = ['id', 'name', 'algorithm', 'secret', 'scope', 'resource_id']
+
+ def get_parser(self, prog_name):
+ parser = super(ListTSIGKeysCommand, self).get_parser(prog_name)
+
+ parser.add_argument('--name', help="TSIGKey NAME", required=False)
+ parser.add_argument('--algorithm', help="TSIGKey algorithm",
+ required=False)
+ parser.add_argument('--scope', help="TSIGKey scope", 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)
+
+ criterion = {}
+ if parsed_args.name is not None:
+ criterion["name"] = parsed_args.name
+ if parsed_args.algorithm is not None:
+ criterion["algorithm"] = parsed_args.algorithm
+ if parsed_args.scope is not None:
+ criterion["scope"] = parsed_args.scope
+
+ data = get_all(client.tsigkeys.list, criterion)
+
+ cols = self.columns
+ return cols, (utils.get_item_properties(s, cols) for s in data)
+
+
+class ShowTSIGKeyCommand(command.ShowOne):
+ """Show tsigkey details"""
+
+ def get_parser(self, prog_name):
+ parser = super(ShowTSIGKeyCommand, self).get_parser(prog_name)
+
+ parser.add_argument('id', help="TSIGKey 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.tsigkeys.get(parsed_args.id)
+ _format_tsigkey(data)
+ return six.moves.zip(*sorted(six.iteritems(data)))
+
+
+class CreateTSIGKeyCommand(command.ShowOne):
+ """Create new tsigkey"""
+
+ def get_parser(self, prog_name):
+ parser = super(CreateTSIGKeyCommand, self).get_parser(prog_name)
+
+ parser.add_argument('--name', help="TSIGKey Name", required=True)
+ parser.add_argument('--algorithm', help="TSIGKey algorithm",
+ required=True)
+ parser.add_argument('--secret', help="TSIGKey secret", required=True)
+ parser.add_argument('--scope', help="TSIGKey scope", required=True)
+ parser.add_argument('--resource-id', help="TSIGKey resource_id",
+ 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.tsigkeys.create(parsed_args.name, parsed_args.algorithm,
+ parsed_args.secret, parsed_args.scope,
+ parsed_args.resource_id)
+ _format_tsigkey(data)
+ return six.moves.zip(*sorted(six.iteritems(data)))
+
+
+class SetTSIGKeyCommand(command.ShowOne):
+ """Set tsigkey properties"""
+
+ def get_parser(self, prog_name):
+ parser = super(SetTSIGKeyCommand, self).get_parser(prog_name)
+
+ parser.add_argument('id', help="TSIGKey ID")
+ parser.add_argument('--name', help="TSIGKey Name")
+ parser.add_argument('--algorithm', help="TSIGKey algorithm")
+ parser.add_argument('--secret', help="TSIGKey secret")
+ parser.add_argument('--scope', help="TSIGKey scope")
+
+ 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.algorithm:
+ data['algorithm'] = parsed_args.algorithm
+ if parsed_args.secret:
+ data['secret'] = parsed_args.secret
+ if parsed_args.scope:
+ data['scope'] = parsed_args.scope
+
+ client = self.app.client_manager.dns
+ common.set_all_common_headers(client, parsed_args)
+
+ data = client.tsigkeys.update(parsed_args.id, data)
+ _format_tsigkey(data)
+ return six.moves.zip(*sorted(six.iteritems(data)))
+
+
+class DeleteTSIGKeyCommand(command.Command):
+ """Delete tsigkey"""
+
+ def get_parser(self, prog_name):
+ parser = super(DeleteTSIGKeyCommand, self).get_parser(prog_name)
+
+ parser.add_argument('id', help="TSIGKey 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.tsigkeys.delete(parsed_args.id)
+
+ LOG.info('TSIGKey %s was deleted', parsed_args.id)
diff --git a/designateclient/v2/client.py b/designateclient/v2/client.py
index d5dda03..b9a42af 100644
--- a/designateclient/v2/client.py
+++ b/designateclient/v2/client.py
@@ -25,6 +25,7 @@ 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.tsigkeys import TSIGKeysController
from designateclient.v2.zones import ZoneController
from designateclient.v2.zones import ZoneExportsController
from designateclient.v2.zones import ZoneImportsController
@@ -138,3 +139,4 @@ class Client(object):
self.zone_imports = ZoneImportsController(self)
self.pools = PoolController(self)
self.quotas = QuotasController(self)
+ self.tsigkeys = TSIGKeysController(self)
diff --git a/designateclient/v2/tsigkeys.py b/designateclient/v2/tsigkeys.py
new file mode 100644
index 0000000..988700f
--- /dev/null
+++ b/designateclient/v2/tsigkeys.py
@@ -0,0 +1,50 @@
+# Copyright 2017 SAP SE
+#
+# Author: Rudolf Vriend <rudolf.vriend@sap.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 TSIGKeysController(V2Controller):
+ def create(self, name, algorithm, secret, scope, resource_id):
+ data = {
+ 'name': name,
+ 'algorithm': algorithm,
+ 'secret': secret,
+ 'scope': scope,
+ 'resource_id': resource_id
+ }
+
+ return self._post('/tsigkeys', data=data)
+
+ def list(self, criterion=None, marker=None, limit=None):
+ url = self.build_url('/tsigkeys', criterion, marker, limit)
+
+ return self._get(url, response_key='tsigkeys')
+
+ def get(self, tsigkey):
+ tsigkey = v2_utils.resolve_by_name(self.list, tsigkey)
+
+ return self._get('/tsigkeys/%s' % tsigkey)
+
+ def update(self, tsigkey, values):
+ tsigkey = v2_utils.resolve_by_name(self.list, tsigkey)
+
+ return self._patch('/tsigkeys/%s' % tsigkey, data=values)
+
+ def delete(self, tsigkey):
+ tsigkey = v2_utils.resolve_by_name(self.list, tsigkey)
+
+ return self._delete('/tsigkeys/%s' % tsigkey)