From d873f7b90e8fbeae39040225502af879de7a8e26 Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Mon, 16 Dec 2019 18:02:42 +0100 Subject: [PATCH] Supporting DNS search domains and options by terraform VM definition. --- lib/cr_tf/terraform/vm.py | 78 ++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/lib/cr_tf/terraform/vm.py b/lib/cr_tf/terraform/vm.py index 083bb83..9b050f0 100644 --- a/lib/cr_tf/terraform/vm.py +++ b/lib/cr_tf/terraform/vm.py @@ -37,7 +37,7 @@ from .disk import TerraformDisk, TerraformDiskDict from .interface import TerraformInterface -__version__ = '1.4.5' +__version__ = '1.5.1' LOG = logging.getLogger(__name__) @@ -82,6 +82,8 @@ class TerraformVm(HandlingObject): ipaddress.ip_address('217.66.52.10'), ipaddress.ip_address('212.91.225.75') ) + default_searchdomains = ('pixelpark.net', 'pixelpark.com') + default_dns_options = 'timeout:1 attempts:2' default_num_cpus = 1 default_puppet_contact = '8x5@pixelpark.com' default_puppet_customer = 'pixelpark' @@ -98,6 +100,9 @@ class TerraformVm(HandlingObject): min_rootdisk_size = CrTfConfiguration.default_root_min_size max_rootdisk_size = CrTfConfiguration.default_root_max_size + max_nameservers = 4 + max_searchdomains = 5 + re_key_fqdn = re.compile(r'^\s*fqdn|name\s*$', re.IGNORECASE) re_key_vm_folder = re.compile(r'^\s*(?:vm[_-]?)folder\s*$', re.IGNORECASE) re_key_boot_delay = re.compile(r'^\s*boot[_-]?delay\s*$', re.IGNORECASE) @@ -111,6 +116,8 @@ class TerraformVm(HandlingObject): re_key_puppet_role = re.compile(r'^\s*puppet[_-]?role\s*$', re.IGNORECASE) re_key_env = re.compile(r'^\s*env(?:ironment)?\s*$', re.IGNORECASE) re_key_ns = re.compile(r'^\s*nameservers?\s*$', re.IGNORECASE) + re_key_searchdomain = re.compile(r'^\s*search[_-]*domains?\s*$', re.IGNORECASE) + re_key_dnsoptions = re.compile(r'^\s*(dns|resolv)[_-]*options?*$', re.IGNORECASE) re_key_root_disk = re.compile(r'^\s*root[_-]?disk\s*$', re.IGNORECASE) re_key_root_disk_size = re.compile(r'^\s*root[_-]?disk[_-]?size\s*$', re.IGNORECASE) re_key_data_disk = re.compile(r'^\s*data[_-]?disk\s*$', re.IGNORECASE) @@ -139,8 +146,8 @@ class TerraformVm(HandlingObject): cluster=None, boot_delay=None, ds_cluster=None, datastore=None, ds_type=None, customer=None, rootdisk_size=None, purpose=None, puppet_contact=None, puppet_role=None, puppet_customer=None, puppet_project=None, puppet_tier=None, puppet_env=None, - vm_template=None, nameservers=None, has_backup=True, has_puppet=True, - already_existing=None, vsphere=None): + vm_template=None, nameservers=None, searchdomains=None, dns_options=None, + has_backup=True, has_puppet=True, already_existing=None, vsphere=None): self._vsphere = self.default_vsphere self._is_template = bool(is_template) @@ -172,6 +179,8 @@ class TerraformVm(HandlingObject): self.interfaces = [] self.nameservers = copy.copy(self.default_nameservers) + self.searchdomains = copy.copy(self.default_searchdomains) + self.dns_options = copy.copy(self.default_dns_options) super(TerraformVm, self).__init__( appname=appname, verbose=verbose, version=version, base_dir=base_dir, @@ -183,13 +192,16 @@ class TerraformVm(HandlingObject): name=name, fqdn=fqdn, num_cpus=num_cpus, memory=memory, folder=folder, boot_delay=boot_delay, vm_template=vm_template, puppet_contact=puppet_contact, puppet_customer=puppet_customer, puppet_tier=puppet_tier, puppet_env=puppet_env, - cluster=cluster, rootdisk_size=rootdisk_size, nameservers=nameservers, purpose=purpose, + cluster=cluster, rootdisk_size=rootdisk_size, nameservers=nameservers, + searchdomains=searchdomains, dns_options=dns_options, purpose=purpose, customer=customer, ds_cluster=ds_cluster, datastore=datastore, ds_type=ds_type, already_existing=already_existing, initialized=initialized, puppet_role=puppet_role, puppet_project=puppet_project, vsphere=vsphere) # ------------------------------------------------------------------------- - def _post_init(self, name=None, fqdn=None, nameservers=None, initialized=False, **kwargs): + def _post_init( + self, name=None, fqdn=None, nameservers=None, searchdomains=None, + initialized=False, **kwargs): self.disks = TerraformDiskDict( appname=self.appname, verbose=self.verbose, base_dir=self.base_dir) @@ -208,6 +220,8 @@ class TerraformVm(HandlingObject): if nameservers is not None: self.nameservers = self._get_ns_list(nameservers) + if searchdomains is not None: + self.searchdomains = self._get_searchdomain_list(searchdomains) if self.is_template: if self.fqdn: @@ -315,6 +329,27 @@ class TerraformVm(HandlingObject): LOG.error(_("Could not evaluate nameservers from {!r}.").format(value)) return + if cls.re_key_searchdomain.search(key): + if isinstance(value, Iterable): + domains = cls._get_searchdomain_list(value) + if domains: + vm.searchdomains = domains + elif value is None: + vm.searchdomains = [] + else: + LOG.error(_("Could not evaluate search domains from {!r}.").format(value)) + return + + if cls.re_key_dnsoptions.search(key): + if value is None: + vm.dns_options = None + else: + val = value.strip().lower() + if val: + vm.dns_options = val + else: + vm.dns_options = None + if cls.re_key_interface.search(key): if vm.is_template: LOG.error(_("Template definitions may not have interface definitions.")) @@ -571,6 +606,7 @@ class TerraformVm(HandlingObject): vm_template=self.vm_template, puppet_contact=self.puppet_contact, puppet_customer=self.puppet_customer, puppet_tier=self.puppet_tier, puppet_env=self.puppet_env, puppet_role=self.puppet_role, nameservers=self.nameservers, + searchdomains=self.searchdomains, dns_options=self.dns_options, rootdisk_size=self.rootdisk_size, has_backup=self.has_backup, has_puppet=self.has_puppet, puppet_project=self.puppet_project, vsphere=self.vsphere, @@ -589,17 +625,19 @@ class TerraformVm(HandlingObject): def _get_ns_list(cls, nameservers): if not isinstance(nameservers, Iterable): - raise ValueError(_("Parameter nameservers {!r} is not iterable.").format(nameservers)) + raise ValueError(_("Parameter {p} {ns!r} is not iterable.").format( + p='nameservers', ns=nameservers)) ns = [] i = 1 for val in nameservers: try: address = ipaddress.ip_address(val) - if i > 3: + if i > cls.max_nameservers: LOG.warn(_( - "There are at most three nameservers accepted, {} " - "will not be considered.").format(address)) + "There are at most {mx} nameservers accepted, {addr} " + "will not be considered.").format( + mx=cls.max_nameservers, addr=address)) elif address not in ns: ns.append(address) i += 1 @@ -609,6 +647,28 @@ class TerraformVm(HandlingObject): return ns + # ------------------------------------------------------------------------- + @classmethod + def _get_searchdomain_list(cls, searchdomains): + + if not isinstance(searchdomains, Iterable): + raise ValueError(_("Parameter {p} {ns!r} is not iterable.").format( + p='searchdomains', ns=searchdomains)) + + domains = [] + i = 1 + for dom in searchdomains: + if i > cls.max_searchdomains: + LOG.warn(_( + "There are at most {mx} search domains accepted, {srv} " + "will not be considered.").format( + mx=cls.max_searchdomains, srv=dom)) + elif dom not in domains: + domains.append(dom) + i += 1 + + return domains + # ----------------------------------------------------------- @property def is_template(self): -- 2.39.5