Support multi DNS server

Using comma delimited ipv4 address list to specify multi dns server
"8.8.8.8,114.114.114.114".

Task: 29465
Story: 2004994

Change-Id: I031247b0cc2ae417f18b2a5b9b3832e78ed9dafd
This commit is contained in:
huang.xiangdong 2019-02-19 11:10:55 +08:00 committed by Feilong Wang
parent fb82777983
commit 3cb6226ff0
16 changed files with 98 additions and 13 deletions

View File

@ -67,7 +67,7 @@ parameters:
default: 10.0.0.0/24 default: 10.0.0.0/24
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a dns nameserver reachable in your environment description: address of a dns nameserver reachable in your environment
http_proxy: http_proxy:

View File

@ -31,7 +31,7 @@ parameters:
description: flavor to use when booting the server for minions description: flavor to use when booting the server for minions
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a DNS nameserver reachable in your environment description: address of a DNS nameserver reachable in your environment
default: 8.8.8.8 default: 8.8.8.8

View File

@ -61,7 +61,7 @@ class ClusterTemplate(base.APIBase):
master_flavor_id = wtypes.StringType(min_length=1, max_length=255) master_flavor_id = wtypes.StringType(min_length=1, max_length=255)
"""The flavor of the master node for this ClusterTemplate""" """The flavor of the master node for this ClusterTemplate"""
dns_nameserver = wtypes.IPv4AddressType() dns_nameserver = types.dns_list
"""The DNS nameserver address""" """The DNS nameserver address"""
keypair_id = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255), keypair_id = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255),

View File

@ -14,6 +14,7 @@
# under the License. # under the License.
import inspect import inspect
import six
from oslo_utils import strutils from oslo_utils import strutils
from oslo_utils import uuidutils from oslo_utils import uuidutils
@ -25,6 +26,17 @@ from magnum.common import utils
from magnum.i18n import _ from magnum.i18n import _
class DNSListType(wtypes.UserType):
"""A comman delimited dns nameserver list"""
basetype = six.string_types
name = "dnslist"
@staticmethod
def validate(value):
return utils.validate_dns(value)
class MacAddressType(wtypes.UserType): class MacAddressType(wtypes.UserType):
"""A simple MAC address type.""" """A simple MAC address type."""
@ -129,6 +141,7 @@ class MultiType(wtypes.UserType):
% {'type': self.types, 'value': type(value)}) % {'type': self.types, 'value': type(value)})
dns_list = DNSListType()
macaddress = MacAddressType() macaddress = MacAddressType()
uuid = UuidType() uuid = UuidType()
name = NameType() name = NameType()

View File

@ -220,6 +220,12 @@ class InvalidMAC(Invalid):
message = _("Expected a MAC address but received %(mac)s.") message = _("Expected a MAC address but received %(mac)s.")
class InvalidDNS(Invalid):
message = _(
"Expected a single dns address or comma separated dns list, "
"but received %(dns)s.")
class ConfigInvalid(Invalid): class ConfigInvalid(Invalid):
message = _("Invalid configuration file. %(error_msg)s") message = _("Invalid configuration file. %(error_msg)s")

View File

@ -25,6 +25,7 @@ import re
import shutil import shutil
import tempfile import tempfile
import netaddr
from oslo_concurrency import processutils from oslo_concurrency import processutils
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import netutils from oslo_utils import netutils
@ -115,6 +116,24 @@ def validate_and_normalize_mac(address):
return address.lower() return address.lower()
def validate_dns(dns_list):
"""Validate a string is a single dns address or comma separated dns list
:param dns_list: dns_list to be validated
:returns: original dns_list.
:raise: InvalidDNS if dns format is invalid
"""
dns_nameservers = dns_list.split(',')
try:
for dns in dns_nameservers:
netaddr.IPAddress(dns, version=4, flags=netaddr.INET_PTON)
except netaddr.AddrFormatError:
raise exception.InvalidDNS(dns=dns_list)
else:
return dns_list
@contextlib.contextmanager @contextlib.contextmanager
def tempdir(**kwargs): def tempdir(**kwargs):
tempfile.tempdir = CONF.tempdir tempfile.tempdir = CONF.tempdir

View File

@ -23,7 +23,7 @@ parameters:
default: "" default: ""
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a dns nameserver reachable in your environment description: address of a dns nameserver reachable in your environment
external_network: external_network:
@ -41,8 +41,7 @@ resources:
properties: properties:
cidr: {get_param: private_network_cidr} cidr: {get_param: private_network_cidr}
network: {get_resource: private_network} network: {get_resource: private_network}
dns_nameservers: dns_nameservers: {get_param: dns_nameserver}
- {get_param: dns_nameserver}
extrouter: extrouter:
type: Magnum::Optional::Neutron::Router type: Magnum::Optional::Neutron::Router

View File

@ -59,7 +59,7 @@ parameters:
admin user password for the Grafana monitoring interface admin user password for the Grafana monitoring interface
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a DNS nameserver reachable in your environment description: address of a DNS nameserver reachable in your environment
default: 8.8.8.8 default: 8.8.8.8

View File

@ -54,7 +54,7 @@ parameters:
admin user password for the Grafana monitoring interface admin user password for the Grafana monitoring interface
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a DNS nameserver reachable in your environment description: address of a DNS nameserver reachable in your environment
default: 8.8.8.8 default: 8.8.8.8

View File

@ -58,7 +58,7 @@ parameters:
admin user password for the Grafana monitoring interface admin user password for the Grafana monitoring interface
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a dns nameserver reachable in your environment description: address of a dns nameserver reachable in your environment
default: 8.8.8.8 default: 8.8.8.8

View File

@ -44,7 +44,7 @@ parameters:
description: flavor to use when booting the slave server description: flavor to use when booting the slave server
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a dns nameserver reachable in your environment description: address of a dns nameserver reachable in your environment
default: 8.8.8.8 default: 8.8.8.8

View File

@ -62,7 +62,7 @@ parameters:
description: flavor to use when booting the swarm node description: flavor to use when booting the swarm node
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a dns nameserver reachable in your environment description: address of a dns nameserver reachable in your environment
default: 8.8.8.8 default: 8.8.8.8

View File

@ -57,7 +57,7 @@ parameters:
description: flavor to use when booting the swarm node description: flavor to use when booting the swarm node
dns_nameserver: dns_nameserver:
type: string type: comma_delimited_list
description: address of a dns nameserver reachable in your environment description: address of a dns nameserver reachable in your environment
default: 8.8.8.8 default: 8.8.8.8

View File

@ -775,7 +775,7 @@ class TestPost(api_base.FunctionalTest):
mock_image_data.return_value = {'name': 'mock_name', mock_image_data.return_value = {'name': 'mock_name',
'os_distro': 'fedora-atomic'} 'os_distro': 'fedora-atomic'}
for k, v in cluster_template_config_dict.items(): for k, v in cluster_template_config_dict.items():
cfg.CONF.set_override(k, v, 'cluster_template') cfg.CONF.set_override(k, v, 'cluster_template')
with mock.patch.object( with mock.patch.object(
self.dbapi, 'create_cluster_template', self.dbapi, 'create_cluster_template',
wraps=self.dbapi.create_cluster_template) as cc_mock: wraps=self.dbapi.create_cluster_template) as cc_mock:
@ -1115,6 +1115,30 @@ class TestPost(api_base.FunctionalTest):
self.assertRaises(AppError, self.post_json, '/clustertemplates', self.assertRaises(AppError, self.post_json, '/clustertemplates',
bdict) bdict)
@mock.patch('magnum.api.attr_validator.validate_image')
@mock.patch('oslo_utils.timeutils.utcnow')
def test_create_cluster_template_with_multi_dns(self, mock_utcnow,
mock_image_data):
bdict = apiutils.cluster_template_post_data(
dns_nameserver="8.8.8.8,114.114.114.114")
test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time
mock_image_data.return_value = {'name': 'mock_name',
'os_distro': 'fedora-atomic'}
response = self.post_json('/clustertemplates', bdict)
self.assertEqual(201, response.status_int)
# Check location header
self.assertIsNotNone(response.location)
expected_location = '/v1/clustertemplates/%s' % bdict['uuid']
self.assertEqual(expected_location,
urlparse.urlparse(response.location).path)
self.assertEqual(bdict['uuid'], response.json['uuid'])
self.assertNotIn('updated_at', response.json.keys)
return_created_at = timeutils.parse_isotime(
response.json['created_at']).replace(tzinfo=None)
self.assertEqual(test_time, return_created_at)
class TestDelete(api_base.FunctionalTest): class TestDelete(api_base.FunctionalTest):

View File

@ -26,6 +26,24 @@ from magnum.common import utils
from magnum.tests.unit.api import base from magnum.tests.unit.api import base
class TestDNSListType(base.FunctionalTest):
def test_valid_single_dns(self):
test_dns = "8.8.8.8"
with mock.patch.object(utils, 'validate_dns') as m_mock:
types.DNSListType.validate(test_dns)
m_mock.assert_called_once_with(test_dns)
def test_valid_multi_dns(self):
test_dns = "8.8.8.8,114.114.114.114"
with mock.patch.object(utils, 'validate_dns') as m_mock:
types.DNSListType.validate(test_dns)
m_mock.assert_called_once_with(test_dns)
def test_invalid_single_dns(self):
self.assertRaises(exception.InvalidDNS,
types.DNSListType.validate, 'invalid-dns')
class TestMacAddressType(base.FunctionalTest): class TestMacAddressType(base.FunctionalTest):
def test_valid_mac_addr(self): def test_valid_mac_addr(self):

View File

@ -0,0 +1,6 @@
---
features:
- Support multi DNS server when creating template.
User can use a comma delimited ipv4 address list
to specify multi dns server, for example
"8.8.8.8,114.114.114.114"