import os
import logging
import re
-import socket
-import ipaddress
import shutil
import stat
import textwrap
import pytz
import six
-from fb_tools.common import pp, to_bool, to_str, RE_DOT_AT_END
+from fb_tools.common import pp, to_bool, to_str
from fb_tools.errors import HandlerError, ExpectedHandlerError
from fb_tools.handling_obj import HandlingObject, CalledProcessError
from fb_tools.handler import BaseHandler
from fb_vmware.connect import VsphereConnection
# Own modules
+from .dns import CrTfHandlerDnsMixin
from .first import CrTfHandlerFirstMixin
from .read import CrTfHandlerReadMixin
from ..xlate import XLATOR
-__version__ = '3.9.3'
+__version__ = '3.9.4'
LOG = logging.getLogger(__name__)
_ = XLATOR.gettext
# =============================================================================
-class CreateTerraformHandler(BaseHandler, CrTfHandlerFirstMixin, CrTfHandlerReadMixin):
+class CreateTerraformHandler(
+ BaseHandler, CrTfHandlerFirstMixin, CrTfHandlerReadMixin, CrTfHandlerDnsMixin):
"""
A handler class for creating the terraform environment
"""
if self.stop_at_step == 'collect-folders':
raise AbortExecution('collect-folders')
- # -------------------------------------------------------------------------·
- def exec_pdns_zones(self):
-
- if self.config.no_pdns:
- return
-
- if self.stop_at_step == 'pdns-zones':
- self.incr_verbosity()
-
- print()
- LOG.info(_("Retrieving informations from PowerDNS ..."))
-
- self.pdns.get_api_zones()
- if self.eval_errors:
- msg = ngettext(
- "Found one error in exploring PowerDNS zones.",
- "Found {n} errors in exploring PowerDNS zones.",
- self.eval_errors).format(n=self.eval_errors)
- raise ExpectedHandlerError(msg)
-
- LOG.info(_("Finished step {!r}.").format('pdns-zones'))
- if self.stop_at_step == 'pdns-zones':
- raise AbortExecution('pdns-zones')
-
# -------------------------------------------------------------------------·
def init_vspheres(self, yaml_file):
if self.stop_at_step == 'validate-iface':
raise AbortExecution('validate-iface')
- # -------------------------------------------------------------------------·
- def exec_validate_dns(self):
-
- if self.stop_at_step == 'validate-dns':
- self.incr_verbosity()
-
- self.validate_dns_mappings()
- if self.eval_errors:
- msg = ngettext(
- "Found one error in validating DNS mappings.",
- "Found {n} errors in validating DNS mappings.",
- self.eval_errors).format(n=self.eval_errors)
- raise ExpectedHandlerError(msg)
-
- LOG.info(_("Finished step {!r}.").format('validate-dns'))
- if self.stop_at_step == 'validate-dns':
- raise AbortExecution('validate-dns')
-
- # -------------------------------------------------------------------------·
- def exec_perform_dns(self):
-
- if self.stop_at_step == 'perform-dns':
- self.incr_verbosity()
-
- self.perform_dns()
-
- LOG.info(_("Finished step {!r}.").format('perform-dns'))
- if self.stop_at_step == 'perform-dns':
- raise AbortExecution('perform-dns')
-
# -------------------------------------------------------------------------·
def exec_project_dir(self):
if network not in self.used_networks[vs_name]:
self.used_networks[vs_name].append(network)
- # -------------------------------------------------------------------------·
- def validate_dns_mappings(self):
-
- LOG.info(_("Validating DNS mappings ..."))
- self._validate_forward_dns_mappings()
- self._validate_reverse_dns_mappings()
-
- lines = []
- if self.dns_mappings2create['forward']:
- for pair in self.dns_mappings2create['forward']:
- line = ' * {n!r} => {a!r}'.format(n=pair[0], a=str(pair[1]))
- lines.append(line)
- else:
- lines.append(self.colored('>>> ' + _('None') + ' <<<', 'AQUA'))
- LOG.info(_("Forward DNS entries to create:") + "\n" + '\n'.join(lines))
-
- lines = []
- if self.dns_mappings2create['reverse']:
- for pair in self.dns_mappings2create['reverse']:
- line = ' * {r} ({a!r}) => {n!r}'.format(
- r=pair[0].reverse_pointer, n=pair[1], a=str(pair[0]))
- lines.append(line)
- else:
- lines.append(self.colored('>>> ' + _('None') + ' <<<', 'AQUA'))
- LOG.info(_("Reverse DNS entries to create:") + "\n" + '\n'.join(lines))
-
- # -------------------------------------------------------------------------·
- def _validate_forward_dns_mappings(self):
-
- if not self.dns_mapping['forward']:
- return
-
- LOG.debug(_("Validating forward DNS mappings ..."))
-
- for (fqdn, address) in self.dns_mapping['forward']:
-
- if self.verbose > 1:
- LOG.debug(_("Validating {f!r} => {a!r}.").format(f=fqdn, a=str(address)))
-
- results_v4 = []
- results_v6 = []
-
- try:
- addr_infos = socket.getaddrinfo(fqdn, 80)
- except socket.gaierror:
- addr_infos = []
-
- for addr_info in addr_infos:
- if addr_info[0] not in (socket.AF_INET, socket.AF_INET6):
- continue
- addr = ipaddress.ip_address(addr_info[4][0])
- if addr.version == 4:
- if addr not in results_v4:
- results_v4.append(addr)
- else:
- if addr not in results_v6:
- results_v6.append(addr)
- if self.verbose > 2:
- if results_v4 or results_v6:
- lines = []
- for addr in results_v4 + results_v6:
- lines.append(' * {}'.format(str(addr)))
- out = '\n'.join(lines)
- LOG.debug(_("Found existing addresses for {f!r}:").format(f=fqdn) + '\n' + out)
- else:
- LOG.debug(_("Did not found existing addresses for {!r}.").format(fqdn))
-
- if address.version == 4:
- if not results_v4:
- self.dns_mappings2create['forward'].append((fqdn, address))
- continue
- if address in results_v4:
- LOG.debug(_("FQDN {f!r} already points to {a!r}.").format(
- f=fqdn, a=str(address)))
- continue
- else:
- if not results_v6:
- self.dns_mappings2create['forward'].append((fqdn, address))
- continue
- if address in results_v6:
- LOG.debug(_("FQDN {f!r} already points to {a!r}.").format(
- f=fqdn, a=str(address)))
- continue
-
- alist = '\n'.join(map(lambda x: ' * {}'.format(str(x)), results_v4 + results_v6))
- msg = (_(
- "FQDN {f!r} has already existing addresses, "
- "but none of them are {a!r}:").format(f=fqdn, a=str(address)) + "\n" + alist)
- if self.ignore_existing_dns:
- LOG.warn(msg)
- self.dns_mappings2create['forward'].append((fqdn, address))
- else:
- LOG.error(msg)
- self.eval_errors += 1
-
- # -------------------------------------------------------------------------·
- def _validate_reverse_dns_mappings(self):
-
- if not self.dns_mapping['reverse']:
- return
-
- LOG.debug(_("Validating reverse DNS mappings ..."))
-
- for (address, fqdn) in self.dns_mapping['reverse']:
-
- if self.verbose > 1:
- LOG.debug(_("Validating {a!r} => {f!r}.").format(f=fqdn, a=str(address)))
-
- try:
- info = socket.gethostbyaddr(str(address))
- except socket.herror:
- info = []
- if self.verbose > 2:
- LOG.debug(_("Got reverse info:") + "\n" + str(info))
- ptr = None
- if info:
- ptr = info[0]
-
- if not ptr:
- if self.verbose > 1:
- LOG.debug(_("Did not found reverse pointer for {!r}.").format(str(address)))
- self.dns_mappings2create['reverse'].append((address, fqdn))
- continue
-
- ptr = RE_DOT_AT_END.sub('', ptr).lower()
- fqdn_canon = RE_DOT_AT_END.sub('', fqdn).lower()
-
- if self.verbose > 1:
- LOG.debug(_("Found reverse pointer {a!r} => {f!r}.").format(f=ptr, a=str(address)))
- if fqdn_canon == ptr:
- if self.verbose > 1:
- LOG.debug(_("Reverse pointer for {!r} was already existing.").format(
- str(address)))
- continue
-
- LOG.error(_("Address {a!r} has already an existing reverse pointer to {p!r}.").format(
- a=str(address), p=ptr))
- self.eval_errors += 1
-
# -------------------------------------------------------------------------·
def get_tf_name_network(self, net_name, *args):
return default
raise KeyError(_("Did not found datastore {!r}.").format(ds_name))
- # --------------------------------------------------------------------------
- def perform_dns(self):
-
- if self.config.no_pdns:
- LOG.debug(_("Power DNS actions are not eceuted."))
- return
-
- print()
- LOG.info(_("Performing DNS actions ..."))
- print()
-
- # TODO: Check for simulate and mappings to create
-
- errors = 0
-
- for (fqdn, address) in self.dns_mappings2create['forward']:
- if not self._perform_dns_forward(fqdn, address):
- errors += 1
-
- for (address, fqdn) in self.dns_mappings2create['reverse']:
- if not self._perform_dns_reverse(address, fqdn):
- errors += 1
-
- if errors:
- msg = ngettext(
- "There was one error in creating DNS mappings.",
- "There were {n} errors in creating DNS mappings.", errors).format(n=errors)
- raise ExpectedHandlerError(msg)
- else:
- if self.verbose > 1:
- LOG.debug(_("No errors in creating DNS mappings."))
-
- print()
-
- for zone_name in self.updated_zones:
- self._increase_zone_serial(zone_name)
-
- # --------------------------------------------------------------------------
- def _increase_zone_serial(self, zone_name):
-
- LOG.info(_("Increasing serial of zone {!r}.").format(zone_name))
-
- zone = self.pdns.zones[zone_name]
- zone.increase_serial()
- zone.notify()
-
- # --------------------------------------------------------------------------
- def _perform_dns_forward(self, fqdn, address):
-
- record_type = 'A'
- addr_obj = ipaddress.ip_address(address)
- if addr_obj.version == 6:
- record_type = 'AAAA'
-
- canon_fqdn = self.pdns.canon_name(fqdn)
-
- zone_name = self.pdns.get_zone_for_item(canon_fqdn, is_fqdn=True)
- if zone_name:
- if self.verbose > 1:
- LOG.debug(_("Got zone {z!r} for FQDN {f!r}.").format(
- z=zone_name, f=canon_fqdn))
- else:
- LOG.error(_("Did not found zone to insert {t}-record for {f!r}.").format(
- t=record_type, f=fqdn))
- return False
-
- zone = self.pdns.zones[zone_name]
- if addr_obj.is_private:
- zone.add_address_record(
- fqdn, address, set_ptr=False, comment='local',
- account=self.config.pdns_comment_account, append_comments=True)
- else:
- zone.add_address_record(fqdn, address, set_ptr=False)
- if zone_name not in self.updated_zones:
- self.updated_zones.append(zone_name)
- return True
-
- # --------------------------------------------------------------------------
- def _perform_dns_reverse(self, address, fqdn):
-
- LOG.debug(_("Trying to create PTR-record {a!r} => {f!r}.").format(
- f=fqdn, a=str(address)))
-
- pointer = self.pdns.canon_name(address.reverse_pointer)
- if self.verbose > 1:
- LOG.debug(_("PTR of {a!r}: {p!r}.").format(a=str(address), p=pointer))
-
- zone_name = self.pdns.get_zone_for_item(pointer, is_fqdn=True)
- if zone_name:
- if self.verbose > 1:
- LOG.debug(_("Got reverse zone {z!r} for address {a!r}.").format(
- z=zone_name, a=str(address)))
- else:
- LOG.warn(_("Did not found zone to insert PTR-record {p!r} ({a}).").format(
- p=pointer, a=str(address)))
- return True
-
- zone = self.pdns.zones[zone_name]
- zone.add_ptr_record(pointer, fqdn)
- if zone_name not in self.updated_zones:
- self.updated_zones.append(zone_name)
- return True
-
# --------------------------------------------------------------------------
def ensure_project_dir(self):
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@author: Frank Brehm
+@contact: frank.brehm@pixelpark.com
+@copyright: © 2023 by Frank Brehm, Berlin
+@summary: A mixin module for the handler module for dns related methods.
+"""
+from __future__ import absolute_import, print_function
+
+# Standard module
+import ipaddress
+import logging
+import socket
+
+# Third party modules
+from fb_tools.common import RE_DOT_AT_END
+from fb_tools.errors import ExpectedHandlerError
+
+# Own modules
+
+from ..errors import AbortExecution
+
+from ..xlate import XLATOR
+
+__version__ = '0.1.0'
+LOG = logging.getLogger(__name__)
+
+_ = XLATOR.gettext
+ngettext = XLATOR.ngettext
+
+
+# =============================================================================
+class CrTfHandlerDnsMixin():
+ """A mixin module for the handler module for dns related methods."""
+
+ # -------------------------------------------------------------------------·
+ def exec_pdns_zones(self):
+
+ if self.config.no_pdns:
+ return
+
+ if self.stop_at_step == 'pdns-zones':
+ self.incr_verbosity()
+
+ print()
+ LOG.info(_("Retrieving informations from PowerDNS ..."))
+
+ self.pdns.get_api_zones()
+ if self.eval_errors:
+ msg = ngettext(
+ "Found one error in exploring PowerDNS zones.",
+ "Found {n} errors in exploring PowerDNS zones.",
+ self.eval_errors).format(n=self.eval_errors)
+ raise ExpectedHandlerError(msg)
+
+ LOG.info(_("Finished step {!r}.").format('pdns-zones'))
+ if self.stop_at_step == 'pdns-zones':
+ raise AbortExecution('pdns-zones')
+
+ # -------------------------------------------------------------------------·
+ def exec_validate_dns(self):
+
+ if self.stop_at_step == 'validate-dns':
+ self.incr_verbosity()
+
+ self.validate_dns_mappings()
+ if self.eval_errors:
+ msg = ngettext(
+ "Found one error in validating DNS mappings.",
+ "Found {n} errors in validating DNS mappings.",
+ self.eval_errors).format(n=self.eval_errors)
+ raise ExpectedHandlerError(msg)
+
+ LOG.info(_("Finished step {!r}.").format('validate-dns'))
+ if self.stop_at_step == 'validate-dns':
+ raise AbortExecution('validate-dns')
+
+ # -------------------------------------------------------------------------·
+ def exec_perform_dns(self):
+
+ if self.stop_at_step == 'perform-dns':
+ self.incr_verbosity()
+
+ self.perform_dns()
+
+ LOG.info(_("Finished step {!r}.").format('perform-dns'))
+ if self.stop_at_step == 'perform-dns':
+ raise AbortExecution('perform-dns')
+
+ # --------------------------------------------------------------------------
+ def perform_dns(self):
+
+ if self.config.no_pdns:
+ LOG.debug(_("Power DNS actions are not eceuted."))
+ return
+
+ print()
+ LOG.info(_("Performing DNS actions ..."))
+ print()
+
+ # TODO: Check for simulate and mappings to create
+
+ errors = 0
+
+ for (fqdn, address) in self.dns_mappings2create['forward']:
+ if not self._perform_dns_forward(fqdn, address):
+ errors += 1
+
+ for (address, fqdn) in self.dns_mappings2create['reverse']:
+ if not self._perform_dns_reverse(address, fqdn):
+ errors += 1
+
+ if errors:
+ msg = ngettext(
+ "There was one error in creating DNS mappings.",
+ "There were {n} errors in creating DNS mappings.", errors).format(n=errors)
+ raise ExpectedHandlerError(msg)
+ else:
+ if self.verbose > 1:
+ LOG.debug(_("No errors in creating DNS mappings."))
+
+ print()
+
+ for zone_name in self.updated_zones:
+ self._increase_zone_serial(zone_name)
+
+ # --------------------------------------------------------------------------
+ def _increase_zone_serial(self, zone_name):
+
+ LOG.info(_("Increasing serial of zone {!r}.").format(zone_name))
+
+ zone = self.pdns.zones[zone_name]
+ zone.increase_serial()
+ zone.notify()
+
+ # --------------------------------------------------------------------------
+ def _perform_dns_forward(self, fqdn, address):
+
+ record_type = 'A'
+ addr_obj = ipaddress.ip_address(address)
+ if addr_obj.version == 6:
+ record_type = 'AAAA'
+
+ canon_fqdn = self.pdns.canon_name(fqdn)
+
+ zone_name = self.pdns.get_zone_for_item(canon_fqdn, is_fqdn=True)
+ if zone_name:
+ if self.verbose > 1:
+ LOG.debug(_("Got zone {z!r} for FQDN {f!r}.").format(
+ z=zone_name, f=canon_fqdn))
+ else:
+ LOG.error(_("Did not found zone to insert {t}-record for {f!r}.").format(
+ t=record_type, f=fqdn))
+ return False
+
+ zone = self.pdns.zones[zone_name]
+ if addr_obj.is_private:
+ zone.add_address_record(
+ fqdn, address, set_ptr=False, comment='local',
+ account=self.config.pdns_comment_account, append_comments=True)
+ else:
+ zone.add_address_record(fqdn, address, set_ptr=False)
+ if zone_name not in self.updated_zones:
+ self.updated_zones.append(zone_name)
+ return True
+
+ # --------------------------------------------------------------------------
+ def _perform_dns_reverse(self, address, fqdn):
+
+ LOG.debug(_("Trying to create PTR-record {a!r} => {f!r}.").format(
+ f=fqdn, a=str(address)))
+
+ pointer = self.pdns.canon_name(address.reverse_pointer)
+ if self.verbose > 1:
+ LOG.debug(_("PTR of {a!r}: {p!r}.").format(a=str(address), p=pointer))
+
+ zone_name = self.pdns.get_zone_for_item(pointer, is_fqdn=True)
+ if zone_name:
+ if self.verbose > 1:
+ LOG.debug(_("Got reverse zone {z!r} for address {a!r}.").format(
+ z=zone_name, a=str(address)))
+ else:
+ LOG.warn(_("Did not found zone to insert PTR-record {p!r} ({a}).").format(
+ p=pointer, a=str(address)))
+ return True
+
+ zone = self.pdns.zones[zone_name]
+ zone.add_ptr_record(pointer, fqdn)
+ if zone_name not in self.updated_zones:
+ self.updated_zones.append(zone_name)
+ return True
+
+ # -------------------------------------------------------------------------·
+ def validate_dns_mappings(self):
+
+ LOG.info(_("Validating DNS mappings ..."))
+ self._validate_forward_dns_mappings()
+ self._validate_reverse_dns_mappings()
+
+ lines = []
+ if self.dns_mappings2create['forward']:
+ for pair in self.dns_mappings2create['forward']:
+ line = ' * {n!r} => {a!r}'.format(n=pair[0], a=str(pair[1]))
+ lines.append(line)
+ else:
+ lines.append(self.colored('>>> ' + _('None') + ' <<<', 'AQUA'))
+ LOG.info(_("Forward DNS entries to create:") + "\n" + '\n'.join(lines))
+
+ lines = []
+ if self.dns_mappings2create['reverse']:
+ for pair in self.dns_mappings2create['reverse']:
+ line = ' * {r} ({a!r}) => {n!r}'.format(
+ r=pair[0].reverse_pointer, n=pair[1], a=str(pair[0]))
+ lines.append(line)
+ else:
+ lines.append(self.colored('>>> ' + _('None') + ' <<<', 'AQUA'))
+ LOG.info(_("Reverse DNS entries to create:") + "\n" + '\n'.join(lines))
+
+ # -------------------------------------------------------------------------·
+ def _validate_forward_dns_mappings(self):
+
+ if not self.dns_mapping['forward']:
+ return
+
+ LOG.debug(_("Validating forward DNS mappings ..."))
+
+ for (fqdn, address) in self.dns_mapping['forward']:
+
+ if self.verbose > 1:
+ LOG.debug(_("Validating {f!r} => {a!r}.").format(f=fqdn, a=str(address)))
+
+ results_v4 = []
+ results_v6 = []
+
+ try:
+ addr_infos = socket.getaddrinfo(fqdn, 80)
+ except socket.gaierror:
+ addr_infos = []
+
+ for addr_info in addr_infos:
+ if addr_info[0] not in (socket.AF_INET, socket.AF_INET6):
+ continue
+ addr = ipaddress.ip_address(addr_info[4][0])
+ if addr.version == 4:
+ if addr not in results_v4:
+ results_v4.append(addr)
+ else:
+ if addr not in results_v6:
+ results_v6.append(addr)
+ if self.verbose > 2:
+ if results_v4 or results_v6:
+ lines = []
+ for addr in results_v4 + results_v6:
+ lines.append(' * {}'.format(str(addr)))
+ out = '\n'.join(lines)
+ LOG.debug(_("Found existing addresses for {f!r}:").format(f=fqdn) + '\n' + out)
+ else:
+ LOG.debug(_("Did not found existing addresses for {!r}.").format(fqdn))
+
+ if address.version == 4:
+ if not results_v4:
+ self.dns_mappings2create['forward'].append((fqdn, address))
+ continue
+ if address in results_v4:
+ LOG.debug(_("FQDN {f!r} already points to {a!r}.").format(
+ f=fqdn, a=str(address)))
+ continue
+ else:
+ if not results_v6:
+ self.dns_mappings2create['forward'].append((fqdn, address))
+ continue
+ if address in results_v6:
+ LOG.debug(_("FQDN {f!r} already points to {a!r}.").format(
+ f=fqdn, a=str(address)))
+ continue
+
+ alist = '\n'.join(map(lambda x: ' * {}'.format(str(x)), results_v4 + results_v6))
+ msg = (_(
+ "FQDN {f!r} has already existing addresses, "
+ "but none of them are {a!r}:").format(f=fqdn, a=str(address)) + "\n" + alist)
+ if self.ignore_existing_dns:
+ LOG.warn(msg)
+ self.dns_mappings2create['forward'].append((fqdn, address))
+ else:
+ LOG.error(msg)
+ self.eval_errors += 1
+
+ # -------------------------------------------------------------------------·
+ def _validate_reverse_dns_mappings(self):
+
+ if not self.dns_mapping['reverse']:
+ return
+
+ LOG.debug(_("Validating reverse DNS mappings ..."))
+
+ for (address, fqdn) in self.dns_mapping['reverse']:
+
+ if self.verbose > 1:
+ LOG.debug(_("Validating {a!r} => {f!r}.").format(f=fqdn, a=str(address)))
+
+ try:
+ info = socket.gethostbyaddr(str(address))
+ except socket.herror:
+ info = []
+ if self.verbose > 2:
+ LOG.debug(_("Got reverse info:") + "\n" + str(info))
+ ptr = None
+ if info:
+ ptr = info[0]
+
+ if not ptr:
+ if self.verbose > 1:
+ LOG.debug(_("Did not found reverse pointer for {!r}.").format(str(address)))
+ self.dns_mappings2create['reverse'].append((address, fqdn))
+ continue
+
+ ptr = RE_DOT_AT_END.sub('', ptr).lower()
+ fqdn_canon = RE_DOT_AT_END.sub('', fqdn).lower()
+
+ if self.verbose > 1:
+ LOG.debug(_("Found reverse pointer {a!r} => {f!r}.").format(f=ptr, a=str(address)))
+ if fqdn_canon == ptr:
+ if self.verbose > 1:
+ LOG.debug(_("Reverse pointer for {!r} was already existing.").format(
+ str(address)))
+ continue
+
+ LOG.error(_("Address {a!r} has already an existing reverse pointer to {p!r}.").format(
+ a=str(address), p=ptr))
+ self.eval_errors += 1
+
+
+# =============================================================================
+
+if __name__ == "__main__":
+
+ pass
+
+# =============================================================================
+
+# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list