summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Gauld <ag1282@att.com>2018-01-19 13:53:49 -0500
committerAndrew Gauld <ag1282@att.com>2018-01-19 14:24:16 -0500
commit89978d130541937c9b5cdc8a0cfe57bc2a430bfc (patch)
treef15089c8e1d1368589579a1a3c49b72f55b1552c
parent1565be2e406cac067eebc9604f27f762124622cf (diff)
dnsdesig plugin support for Identity v3 api
Change-Id: Ic00bf6e18abc680bd99fd02b752b9da065107eb7 Issue-ID: CCSDK-181 Signed-off-by: Andrew Gauld <ag1282@att.com>
-rw-r--r--LICENSE.txt2
-rw-r--r--dnsdesig/LICENSE.txt2
-rw-r--r--dnsdesig/dns_types.yaml4
-rw-r--r--dnsdesig/dnsdesig/dns_plugin.py89
-rw-r--r--dnsdesig/setup.py4
-rw-r--r--dnsdesig/tests/test_plugin.py168
6 files changed, 218 insertions, 51 deletions
diff --git a/LICENSE.txt b/LICENSE.txt
index c233514..e19c6c0 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,6 +1,6 @@
===========LICENSE_START==========================================
===================================================================
-Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+Copyright © 2018 AT&T Intellectual Property. 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.
diff --git a/dnsdesig/LICENSE.txt b/dnsdesig/LICENSE.txt
index f90f8f1..1fedf86 100644
--- a/dnsdesig/LICENSE.txt
+++ b/dnsdesig/LICENSE.txt
@@ -1,7 +1,7 @@
============LICENSE_START=======================================================
org.onap.ccsdk
================================================================================
-Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+Copyright (c) 2018 AT&T Intellectual Property. 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.
diff --git a/dnsdesig/dns_types.yaml b/dnsdesig/dns_types.yaml
index 9af2422..3161213 100644
--- a/dnsdesig/dns_types.yaml
+++ b/dnsdesig/dns_types.yaml
@@ -1,7 +1,7 @@
# ============LICENSE_START====================================================
# org.onap.ccsdk
# =============================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2018 AT&T Intellectual Property. 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.
@@ -24,7 +24,7 @@ plugins:
dns_designate:
executor: central_deployment_agent
package_name: dnsdesig
- package_version: 1.0.0
+ package_version: 1.0.1
node_types:
ccsdk.nodes.dns.arecord:
diff --git a/dnsdesig/dnsdesig/dns_plugin.py b/dnsdesig/dnsdesig/dns_plugin.py
index ee755aa..d46468d 100644
--- a/dnsdesig/dnsdesig/dns_plugin.py
+++ b/dnsdesig/dnsdesig/dns_plugin.py
@@ -1,7 +1,7 @@
# ============LICENSE_START====================================================
# org.onap.ccsdk
# =============================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2018 AT&T Intellectual Property. 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.
@@ -30,23 +30,82 @@ def _check_status(resp, msg):
raise NonRecoverableError(msg)
def _get_auth_info(openstack):
+ if openstack['auth_url'].endswith('/v2.0'):
+ (tok, gbls, urls) = _get_auth_info_v2(openstack)
+ else:
+ (tok, gbls, urls) = _get_auth_info_v3(openstack)
+ if len(urls.keys()) == 1:
+ reg = urls.keys()[0]
+ else:
+ reg = openstack['region']
+ if reg in urls and 'dns' in urls[reg]:
+ url = urls[reg]['dns']
+ elif 'dns' in gbls:
+ url = gbls['dns']
+ else:
+ raise NonRecoverableError('DNS service not found')
+ return { 'osauth': { 'X-Auth-Token': tok }, 'dns': url }
+
+def _get_auth_info_v3(openstack):
+ domain = openstack['domain'] if 'domain' in openstack else 'default'
+ resp = requests.post('{0}/auth/tokens'.format(openstack['auth_url']), json={
+ 'auth': {
+ 'identity': {
+ 'methods': [
+ 'password'
+ ],
+ 'password': {
+ 'user': {
+ 'name': openstack['username'],
+ 'domain': {
+ 'id': domain
+ },
+ 'password': openstack['password']
+ }
+ }
+ },
+ 'scope': {
+ 'project': {
+ 'name': openstack['tenant_name'],
+ 'domain': {
+ 'id': domain
+ }
+ }
+ }
+ }
+ })
+ _check_status(resp, 'Failed to get authorization token from OpenStack identity service v3')
+ gbls = {}
+ urls = {}
+ for sc in resp.json()['token']['catalog']:
+ type = sc['type']
+ for ep in sc['endpoints']:
+ if 'region' in ep and ep['region'] not in urls:
+ urls[ep['region']] = {}
+ if ep['interface'] == 'public' and ep['url'] != '':
+ if 'region' not in ep:
+ gbls[type] = ep['url']
+ else:
+ urls[ep['region']][type] = ep['url']
+ return (resp.headers['X-Subject-Token'], gbls, urls)
+
+def _get_auth_info_v2(openstack):
resp = requests.post('{0}/tokens'.format(openstack['auth_url']), json={'auth':{'tenantName':openstack['tenant_name'],'passwordCredentials':{'username':openstack['username'], 'password':openstack['password']}}})
- _check_status(resp, 'Failed to get authorization token from OpenStack identity service')
+ _check_status(resp, 'Failed to get authorization token from OpenStack identity service v2')
respj = resp.json()['access']
- osauth={'X-Auth-Token': respj['token']['id'] }
+ gbls = {}
urls = {}
for se in respj['serviceCatalog']:
type = se['type']
for ep in se['endpoints']:
- url = ep['publicURL']
- reg = ep['region']
- if not urls.has_key(reg):
- urls[reg] = { }
- if type not in urls[reg] or urls[reg][type] == '':
- urls[reg][type] = url
- if len(urls.keys()) == 1:
- openstack['region'] = urls.keys()[0]
- return { 'osauth': osauth, 'dns': urls[openstack['region']]['dns'] }
+ if 'region' in ep and ep['region'] not in urls:
+ urls[ep['region']] = {}
+ if 'publicURL' in ep and ep['publicURL'] != '':
+ if 'region' not in ep:
+ gbls[type] = ep['publicURL']
+ else:
+ urls[ep['region']][type] = ep['publicURL']
+ return (respj['token']['id'], gbls, urls)
def _dot(fqdn):
"""
@@ -86,7 +145,7 @@ def aneeded(**kwargs):
"""
try:
_doneed('A', kwargs['args']['ip_addresses'])
- except NonRecoverableError as nre:
+ except (NonRecoverableError, RecoverableError) as nre:
raise nre
except Exception as e:
raise NonRecoverableError(e)
@@ -105,7 +164,7 @@ def cnameneeded(**kwargs):
"""
try:
_doneed('CNAME', [ _dot(kwargs['args']['cname']) ] )
- except NonRecoverableError as nre:
+ except (NonRecoverableError, RecoverableError) as nre:
raise nre
except Exception as e:
raise NonRecoverableError(e)
@@ -145,7 +204,7 @@ def _noneed(type):
if rs:
resp = requests.delete('{0}/v2/zones/{1}/recordsets/{2}'.format(access['dns'], zid, rs['id']), headers=access['osauth'])
_check_status(resp, 'Failed to delete DNS record set for {0}'.format(fqdn))
- except NonRecoverableError as nre:
+ except (NonRecoverableError, RecoverableError) as nre:
raise nre
except Exception as e:
raise NonRecoverableError(e)
diff --git a/dnsdesig/setup.py b/dnsdesig/setup.py
index 9450390..35578ce 100644
--- a/dnsdesig/setup.py
+++ b/dnsdesig/setup.py
@@ -1,7 +1,7 @@
# ============LICENSE_START====================================================
# org.onap.ccsdk
# =============================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2018 AT&T Intellectual Property. 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.
@@ -21,7 +21,7 @@ from setuptools import setup, find_packages
setup(
name='dnsdesig',
- version='1.0.0',
+ version='1.0.1',
packages=find_packages(),
author='AT&T',
description=('Cloudify plugin for creating DNS entries using Designate.'),
diff --git a/dnsdesig/tests/test_plugin.py b/dnsdesig/tests/test_plugin.py
index 730897a..d2b9174 100644
--- a/dnsdesig/tests/test_plugin.py
+++ b/dnsdesig/tests/test_plugin.py
@@ -1,7 +1,7 @@
# ============LICENSE_START====================================================
# org.onap.ccsdk
# =============================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2018 AT&T Intellectual Property. 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.
@@ -22,17 +22,23 @@ import dnsdesig.dns_plugin
from cloudify.mocks import MockCloudifyContext
from cloudify.state import current_ctx
from cloudify.exceptions import NonRecoverableError
+from cloudify.exceptions import RecoverableError
from cloudify import ctx
class _resp(object):
- def __init__(self, code, body = None):
+ def __init__(self, code, body = None, rhdrs = None):
self.status_code = code
+ if rhdrs is not None:
+ self.headers = rhdrs
if body is not None:
self._json = body
def json(self):
return self._json
+ def rhdrs(self):
+ return self.headers
+
def _same(a, b):
t1 = type(a)
t2 = type(b)
@@ -74,6 +80,7 @@ class _req(object):
_nf = _resp(404)
_ar = _resp(401)
_np = _resp(403)
+_svcunavail = _resp(503)
_ok = _resp(200, { 'something': 'or-other' })
_tok = 'at'
@@ -81,7 +88,7 @@ _tok = 'at'
_hdrs = { 'X-Auth-Token': _tok }
_goodos = {
- 'auth_url': 'https://example.com/identity',
+ 'auth_url': 'https://example.com/identity/v3',
'password': 'pw',
'region': 'r',
'tenant_name': 'tn',
@@ -89,7 +96,23 @@ _goodos = {
}
_bados = {
- 'auth_url': 'https://example.com/identity',
+ 'auth_url': 'https://example.com/identity/v3',
+ 'password': 'xx',
+ 'region': 'r',
+ 'tenant_name': 'tn',
+ 'username': 'un'
+}
+
+_goodosv2 = {
+ 'auth_url': 'https://example.com/identity/v2.0',
+ 'password': 'pw',
+ 'region': 'r',
+ 'tenant_name': 'tn',
+ 'username': 'un'
+}
+
+_badosv2 = {
+ 'auth_url': 'https://example.com/identity/v2.0',
'password': 'xx',
'region': 'r',
'tenant_name': 'tn',
@@ -98,21 +121,79 @@ _bados = {
_answers = [
- # Authenticate
- _req('POST', 'https://example.com/identity/tokens', headers=None, resp=_resp(200, {
+ # Authenticate v3
+ _req('POST', 'https://example.com/identity/v3/auth/tokens', headers=None, resp=_resp(200, {
+ 'token': {
+ 'catalog': [
+ {
+ 'type': 'dns',
+ 'endpoints': [
+ {
+ 'interface': 'public',
+ 'region': 'r2',
+ 'url': 'https://example.com/invalid2'
+ },
+ {
+ 'interface': 'public',
+ 'region': 'r3',
+ 'url': 'https://example.com/invalid3'
+ },
+ {
+ 'interface': 'public',
+ 'url': 'https://example.com/dns'
+ }
+ ]
+ }
+ ]
+ }
+ }, rhdrs = {
+ 'X-Subject-Token': _tok
+ }), json={
+ 'auth': {
+ 'identity': {
+ 'methods': [
+ 'password'
+ ],
+ 'password': {
+ 'user': {
+ 'name': 'un',
+ 'domain': {
+ 'id': 'default'
+ },
+ 'password': 'pw'
+ }
+ }
+ },
+ 'scope': {
+ 'project': {
+ 'name': 'tn',
+ 'domain': {
+ 'id': 'default'
+ }
+ }
+ }
+ }
+ }),
+ # Invalid authentication v3
+ _req('POST', 'https://example.com/identity/v3/auth/tokens', headers=None, resp=_np),
+ # Authenticate v2.0
+ _req('POST', 'https://example.com/identity/v2.0/tokens', headers=None, resp=_resp(200, {
'access': {
'token': {
'id': _tok
}, 'serviceCatalog': [
{
- 'type': 'dns',
- 'endpoints': [
+ 'type': 'dns',
+ 'endpoints': [
+ {
+ 'publicURL': 'https://example.com/dns',
+ 'region': 'r'
+ },
{
- 'publicURL': 'https://example.com/dns',
- 'region': 'r'
+ 'publicURL': 'https://example.com/otherregions'
}
- ]
- }
+ ]
+ }
]
}
}), json={
@@ -120,18 +201,18 @@ _answers = [
'tenantName': 'tn',
'passwordCredentials': {
'username': 'un',
- 'password': 'pw'
+ 'password': 'pw'
}
}
}),
- # Invalid authentication
- _req('POST', 'https://example.com/identity/tokens', headers=None, resp=_np),
+ # Invalid authentication v2.0
+ _req('POST', 'https://example.com/identity/v2.0/tokens', headers=None, resp=_np),
# Get zones
_req('GET', 'https://example.com/dns/v2/zones', headers=_hdrs, resp=_resp(200, {
'zones': [
{
'name': 'x.example.com.',
- 'id': 'z1'
+ 'id': 'z1'
}
]
})),
@@ -139,22 +220,30 @@ _answers = [
_req('GET', 'https://example.com/dns/v2/zones/z1/recordsets?limit=1000', headers=_hdrs, resp=_resp(200, {
'recordsets': [
{
- 'id': 'ar1',
+ 'id': 'ar1',
'type': 'A',
- 'name': 'a.x.example.com.',
- 'ttl': 300,
- 'records': [
- '87.65.43.21',
- '98.76,54.32'
- ]
+ 'name': 'a.x.example.com.',
+ 'ttl': 300,
+ 'records': [
+ '87.65.43.21',
+ '98.76,54.32'
+ ]
+ }, {
+ 'id': 'cname1',
+ 'type': 'CNAME',
+ 'name': 'c.x.example.com.',
+ 'ttl': 300,
+ 'records': [
+ 'a.x.example.com.'
+ ]
}, {
- 'id': 'cname1',
+ 'id': 'noservice',
'type': 'CNAME',
- 'name': 'c.x.example.com.',
- 'ttl': 300,
- 'records': [
- 'a.x.example.com.'
- ]
+ 'name': 'noservice.x.example.com.',
+ 'ttl': 300,
+ 'records': [
+ 'a.x.example.com.'
+ ]
}
]
})),
@@ -196,7 +285,9 @@ _answers = [
# Delete A recordset
_req('DELETE', 'https://example.com/dns/v2/zones/z1/recordsets/ar1', headers=_hdrs, resp=_ok),
# Delete CNAME recordset
- _req('DELETE', 'https://example.com/dns/v2/zones/z1/recordsets/cname1', headers=_hdrs, resp=_ok)
+ _req('DELETE', 'https://example.com/dns/v2/zones/z1/recordsets/cname1', headers=_hdrs, resp=_ok),
+ # service unavailable
+ _req('DELETE', 'https://example.com/dns/v2/zones/z1/recordsets/noservice', headers=_hdrs, resp=_svcunavail)
]
def _match(op, url, headers, json = None):
@@ -237,6 +328,15 @@ def _setup(os, fqdn, ttl=None):
return newfcn
return fcnbuilder
+@_setup(_badosv2, 'a.x.example.com')
+def test_dns_badauthv2():
+ with pytest.raises(NonRecoverableError):
+ dnsdesig.dns_plugin.anotneeded()
+
+@_setup(_goodosv2, 'a.x.example.com')
+def test_dns_goodauthv2():
+ dnsdesig.dns_plugin.anotneeded()
+
@_setup(_bados, 'a.x.example.com')
def test_dns_badauth():
with pytest.raises(NonRecoverableError):
@@ -270,3 +370,11 @@ def test_dns_modcnamerecord():
@_setup(_goodos, 'c.x.example.com')
def test_dns_delcname():
dnsdesig.dns_plugin.cnamenotneeded()
+
+@_setup(_goodos, 'noservice.x.example.com')
+def test_dns_delcname():
+ with pytest.raises(RecoverableError):
+ dnsdesig.dns_plugin.cnamenotneeded()
+
+def test_module_logger():
+ dnsdesig.get_module_logger('dnsdesig')