Esempio n. 1
0
    def process_notification(self, context, event_type, payload):
        # Do something with the notification.. e.g:
        zone_id = cfg.CONF[self.name].zone_id
        zone_name = cfg.CONF[self.name].zone_name

        record_name = '%s.%s' % (payload['instance_id'], zone_name)

        context = DesignateContext().elevated()
        context.all_tenants = True
        # context.edit_managed_records = True

        for fixed_ip in payload['fixed_ips']:
            recordset_values = {
                'zone_id': zone_id,
                'name': record_name,
                'type': 'A' if fixed_ip['version'] == 4 else 'AAAA'
            }

            record_values = {
                'data': fixed_ip['address'],
            }

            recordset = self._find_or_create_recordset(context,
                                                       **recordset_values)

            self.central_api.create_record(context, zone_id, recordset['id'],
                                           Record(**record_values))
Esempio n. 2
0
    def _delete(self, zone_id, resource_id=None, resource_type='instance',
                criterion=None):
        """
        Handle a generic delete of a fixed ip within a zone

        :param zone_id: The ID of the designate zone.
        :param resource_id: The managed resource ID
        :param resource_type: The managed resource type
        :param criterion: Criterion to search and destroy records
        """
        criterion = criterion or {}

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        criterion.update({
            'zone_id': zone_id,
            'managed': True,
            'managed_plugin_name': self.get_plugin_name(),
            'managed_plugin_type': self.get_plugin_type(),
            'managed_resource_id': resource_id,
            'managed_resource_type': resource_type
        })

        records = self.central_api.find_records(context, criterion)

        for record in records:
            LOG.debug('Deleting record %s', record['id'])

            self.central_api.delete_record(context,
                                           zone_id,
                                           record['recordset_id'],
                                           record['id'])
Esempio n. 3
0
    def process_request(self, request):
        headers = request.headers

        try:
            if headers['X-Identity-Status'] is 'Invalid':
                #TODO(graham) fix the return to use non-flask resources
                return flask.Response(status=401)
        except KeyError:
            #If the key is valid, Keystone does not include this header at all
            pass

        roles = headers.get('X-Roles').split(',')

        context = DesignateContext(auth_token=headers.get('X-Auth-Token'),
                                   user=headers.get('X-User-ID'),
                                   tenant=headers.get('X-Tenant-ID'),
                                   roles=roles)

        # Store the context where oslo-log exepcts to find it.
        local.store.context = context

        # Attempt to sudo, if requested.
        sudo_tenant_id = headers.get('X-Designate-Sudo-Tenant-ID', None)

        if sudo_tenant_id and (uuidutils.is_uuid_like(sudo_tenant_id)
                               or sudo_tenant_id.isdigit()):
            context.sudo(sudo_tenant_id)

        # Attach the context to the request environment
        request.environ['context'] = context
Esempio n. 4
0
    def _create(self, addresses, extra, zone_id, managed=True, resource_type=None, resource_id=None):
        """
        Create a a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param managed: Is it a managed resource
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        if not managed:
            LOG.warning(
                _LW(
                    "Deprecation notice: Unmanaged designate-sink records are "
                    "being deprecated please update the call "
                    "to remove managed=False"
                )
            )
        LOG.debug("Using Zone ID: %s", zone_id)
        zone = self.get_zone(zone_id)
        LOG.debug("Domain: %r", zone)

        data = extra.copy()
        LOG.debug("Event data: %s", data)
        data["zone"] = zone["name"]

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        for addr in addresses:
            event_data = data.copy()
            event_data.update(self._get_ip_data(addr))

            for fmt in cfg.CONF[self.name].get("format"):
                recordset_values = {
                    "zone_id": zone["id"],
                    "name": fmt % event_data,
                    "type": "A" if addr["version"] == 4 else "AAAA",
                }

                recordset = self._find_or_create_recordset(context, **recordset_values)

                record_values = {"data": addr["address"]}

                if managed:
                    record_values.update(
                        {
                            "managed": managed,
                            "managed_plugin_name": self.get_plugin_name(),
                            "managed_plugin_type": self.get_plugin_type(),
                            "managed_resource_type": resource_type,
                            "managed_resource_id": resource_id,
                        }
                    )

                LOG.debug("Creating record in %s / %s with values %r", zone["id"], recordset["id"], record_values)
                self.central_api.create_record(context, zone["id"], recordset["id"], Record(**record_values))
Esempio n. 5
0
    def _create(self, addresses, extra, zone_id, managed=True,
                resource_type=None, resource_id=None):
        """
        Create a a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param managed: Is it a managed resource
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        if not managed:
            LOG.warning(_LW(
                'Deprecation notice: Unmanaged designate-sink records are '
                'being deprecated please update the call '
                'to remove managed=False'))
        LOG.debug('Using Zone ID: %s' % zone_id)
        zone = self.get_zone(zone_id)
        LOG.debug('Zone: %r' % zone)

        data = extra.copy()
        LOG.debug('Event data: %s' % data)
        data['zone'] = zone['name']

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        for addr in addresses:
            event_data = data.copy()
            event_data.update(self._get_ip_data(addr))

            for fmt in cfg.CONF[self.name].get('format'):
                recordset_values = {
                    'zone_id': zone['id'],
                    'name': fmt % event_data,
                    'type': 'A' if addr['version'] == 4 else 'AAAA'}

                recordset = self._find_or_create_recordset(
                    context, **recordset_values)

                record_values = {
                    'data': addr['address']}

                if managed:
                    record_values.update({
                        'managed': managed,
                        'managed_plugin_name': self.get_plugin_name(),
                        'managed_plugin_type': self.get_plugin_type(),
                        'managed_resource_type': resource_type,
                        'managed_resource_id': resource_id})

                LOG.debug('Creating record in %s / %s with values %r' %
                          (zone['id'], recordset['id'], record_values))
                self.central_api.create_record(context,
                                               zone['id'],
                                               recordset['id'],
                                               Record(**record_values))
Esempio n. 6
0
    def _create(self, addresses, extra, zone_id, resource_type=None,
                resource_id=None):
        """
        Create a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param zone_id: The ID of the designate zone.
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        LOG.debug('Using Zone ID: %s', zone_id)
        zone = self.get_zone(zone_id)
        LOG.debug('Domain: %r', zone)

        data = extra.copy()
        LOG.debug('Event data: %s', data)
        data['zone'] = zone['name']

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        for addr in addresses:
            event_data = data.copy()
            event_data.update(self._get_ip_data(addr))

            if addr['version'] == 4:
                format = self._get_formatv4()
            else:
                format = self._get_formatv6()

            for fmt in format:
                recordset_values = {
                    'zone_id': zone['id'],
                    'name': fmt % event_data,
                    'type': 'A' if addr['version'] == 4 else 'AAAA'}

                recordset = self._find_or_create_recordset(
                    context, **recordset_values)

                record_values = {
                    'data': addr['address'],
                    'managed': True,
                    'managed_plugin_name': self.get_plugin_name(),
                    'managed_plugin_type': self.get_plugin_type(),
                    'managed_resource_type': resource_type,
                    'managed_resource_id': resource_id
                }

                LOG.debug('Creating record in %s / %s with values %r',
                          zone['id'], recordset['id'], record_values)
                self.central_api.create_record(context,
                                               zone['id'],
                                               recordset['id'],
                                               Record(**record_values))
Esempio n. 7
0
    def periodic_sync(self):
        """
        :return: None
        """
        # NOTE(kiall): Only run this periodic task on the pool leader
        if self._pool_election.is_leader:
            context = DesignateContext.get_admin_context(all_tenants=True)

            LOG.debug("Starting Periodic Synchronization")

            criterion = {
                'pool_id': CONF['service:pool_manager'].pool_id,
                'status': '!%s' % ERROR_STATUS
            }

            periodic_sync_seconds = \
                CONF['service:pool_manager'].periodic_sync_seconds

            if periodic_sync_seconds is not None:
                # Generate the current serial, will provide a UTC Unix TS.
                current = utils.increment_serial()
                criterion['serial'] = ">%s" % (current - periodic_sync_seconds)

            zones = self.central_api.find_zones(context, criterion)

            try:
                for zone in zones:
                    # TODO(kiall): If the zone was created within the last
                    #              periodic_sync_seconds, attempt to recreate
                    #              to fill in targets which may have failed.
                    self.update_zone(context, zone)

            except Exception:
                LOG.exception(_LE('An unhandled exception in periodic '
                                  'synchronization occurred.'))
Esempio n. 8
0
    def _delete(self, managed=True, resource_id=None, resource_type='instance',
                criterion={}):
        """
        Handle a generic delete of a fixed ip within a domain

        :param criterion: Criterion to search and destroy records
        """
        context = DesignateContext.get_admin_context()

        if managed:
            criterion.update({
                'managed': managed,
                'managed_plugin_name': self.get_plugin_name(),
                'managed_plugin_type': self.get_plugin_type(),
                'managed_resource_id': resource_id,
                'managed_resource_type': resource_type
            })

        records = central_api.find_records(context,
                                           cfg.CONF[self.name].domain_id,
                                           criterion)

        for record in records:
            LOG.debug('Deleting record %s' % record['id'])

            central_api.delete_record(context, cfg.CONF[self.name].domain_id,
                                      record['id'])
Esempio n. 9
0
    def periodic_recovery(self):
        """
        :return: None
        """
        # TODO(kiall): Replace this inter-process-lock with a distributed
        #              lock, likely using the tooz library - see bug 1445127.
        with lockutils.lock('periodic_recovery', external=True, delay=30):
            context = DesignateContext.get_admin_context(all_tenants=True)

            LOG.debug("Starting Periodic Recovery")

            try:
                # Handle Deletion Failures
                domains = self._get_failed_domains(context, DELETE_ACTION)

                for domain in domains:
                    self.delete_domain(context, domain)

                # Handle Creation Failures
                domains = self._get_failed_domains(context, CREATE_ACTION)

                for domain in domains:
                    self.create_domain(context, domain)

                # Handle Update Failures
                domains = self._get_failed_domains(context, UPDATE_ACTION)

                for domain in domains:
                    self.update_domain(context, domain)

            except Exception:
                LOG.exception(_LE('An unhandled exception in periodic '
                                  'recovery occurred'))
Esempio n. 10
0
    def load_pool(self, pool_id):
        # Build the Pool (and related) Object from Config
        context = DesignateContext.get_admin_context()

        pool = None
        has_targets = False

        while not has_targets:
            try:
                pool = self.central_api.get_pool(context, pool_id)

                if len(pool.targets) > 0:
                    has_targets = True
                else:
                    LOG.error("No targets for %s found.", pool)
                    time.sleep(5)

            # Pool data may not have migrated to the DB yet
            except exceptions.PoolNotFound:
                LOG.error("Pool ID %s not found.", pool_id)
                time.sleep(5)
            # designate-central service may not have started yet
            except messaging.exceptions.MessagingTimeout:
                time.sleep(0.2)

        return self._setup_target_backends(pool)
Esempio n. 11
0
    def start(self):

        # Build the Pool (and related) Object from Config
        context = DesignateContext.get_admin_context()
        pool_id = CONF['service:pool_manager'].pool_id

        has_targets = False

        # TODO(kiall): This block of code should be replaced with a cleaner,
        #              limited version. e.g. should retry for X minutes, and
        #              backoff rather than fixed retry intervals.
        while not has_targets:
            try:
                self.pool = self.central_api.get_pool(context, pool_id)

                if len(self.pool.targets) > 0:
                    has_targets = True
                else:
                    LOG.error(_LE("No targets for %s found."), self.pool)
                    time.sleep(5)

            # Pool data may not have migrated to the DB yet
            except exceptions.PoolNotFound:
                LOG.error(_LE("Pool ID %s not found."), pool_id)
                time.sleep(5)
            # designate-central service may not have started yet
            except messaging.exceptions.MessagingTimeout:
                time.sleep(0.2)
            # designate-central failed in an unknown way, don't allow another
            # failing / not started service to cause pool-manager to crash.
            except Exception:
                LOG.exception(_LE("An unknown exception occurred while "
                                  "fetching pool details"))
                time.sleep(5)

        # Create the necessary Backend instances for each target
        self._setup_target_backends()

        for target in self.pool.targets:
            self.target_backends[target.id].start()

        super(Service, self).start()

        # Setup a Leader Election, use for ensuring certain tasks are executed
        # on exactly one pool-manager instance at a time]
        self._pool_election = coordination.LeaderElection(
            self._coordinator, '%s:%s' % (self.service_name, self.pool.id))
        self._pool_election.start()

        if CONF['service:pool_manager'].enable_recovery_timer:
            interval = CONF['service:pool_manager'].periodic_recovery_interval
            LOG.info(_LI('Starting periodic recovery timer every'
                         ' %(interval)s s') % {'interval': interval})
            self.tg.add_timer(interval, self.periodic_recovery, interval)

        if CONF['service:pool_manager'].enable_sync_timer:
            interval = CONF['service:pool_manager'].periodic_sync_interval
            LOG.info(_LI('Starting periodic synchronization timer every'
                         ' %(interval)s s') % {'interval': interval})
            self.tg.add_timer(interval, self.periodic_sync, interval)
Esempio n. 12
0
    def periodic_recovery(self):
        """
        :return: None
        """
        # NOTE(kiall): Only run this periodic task on the pool leader
        if self._pool_election.is_leader:
            context = DesignateContext.get_admin_context(all_tenants=True)

            LOG.debug("Starting Periodic Recovery")

            try:
                # Handle Deletion Failures
                zones = self._get_failed_zones(context, DELETE_ACTION)

                for zone in zones:
                    self.delete_zone(context, zone)

                # Handle Creation Failures
                zones = self._get_failed_zones(context, CREATE_ACTION)

                for zone in zones:
                    self.create_zone(context, zone)

                # Handle Update Failures
                zones = self._get_failed_zones(context, UPDATE_ACTION)

                for zone in zones:
                    self.update_zone(context, zone)

            except Exception:
                LOG.exception(_LE('An unhandled exception in periodic '
                                  'recovery occurred'))
Esempio n. 13
0
    def __init__(self, target):
        super(Backend, self).__init__()

        self.target = target
        self.options = target.options
        self.masters = target.masters

        # TODO(kiall): Context's should never be shared accross requests.
        self.admin_context = DesignateContext.get_admin_context()
        self.admin_context.all_tenants = True
Esempio n. 14
0
    def test_invalid_event_type(self):
        context = DesignateContext.get_admin_context(all_tenants=True)
        if not hasattr(self, 'plugin'):
            raise NotImplementedError
        event_type = 'invalid'

        self.assertNotIn(event_type, self.plugin.get_event_types())

        with testtools.ExpectedException(ValueError):
            self.plugin.process_notification(context, event_type, 'payload')
Esempio n. 15
0
    def __init__(self):
        # Get a storage connection
        storage_driver = cfg.CONF['service:mdns'].storage_driver
        self.storage = storage.get_storage(storage_driver)
        self.admin_context = DesignateContext.get_admin_context(
            all_tenants=True)

        # Fake request is used to send a response when we cannot decipher the
        # request.
        self._fake_request = dns.message.make_query('unknown', dns.rdatatype.A)
Esempio n. 16
0
    def _delete(self, zone_id, managed=True, resource_id=None,
                resource_type='instance', criterion=None):
        """
        Handle a generic delete of a fixed ip within a zone

        :param zone_id: The ID of the designate zone.
        :param managed: Is it a managed resource
        :param resource_id: The managed resource ID
        :param resource_type: The managed resource type
        :param criterion: Criterion to search and destroy records
        """
        if not managed:
            LOG.warning(
                'Deprecation notice: Unmanaged designate-sink records are '
                'being deprecated please update the call '
                'to remove managed=False')
        criterion = criterion or {}

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        criterion.update({'zone_id': zone_id})

        if managed:
            criterion.update({
                'managed': managed,
                'managed_plugin_name': self.get_plugin_name(),
                'managed_plugin_type': self.get_plugin_type(),
                'managed_resource_id': resource_id,
                'managed_resource_type': resource_type
            })

        records = self.central_api.find_records(context, criterion)

        for record in records:
            LOG.debug('Deleting record %s', record['id'])

            self.central_api.delete_record(context,
                                           zone_id,
                                           record['recordset_id'],
                                           record['id'])
Esempio n. 17
0
    def _delete(self, zone_id, managed=True, resource_id=None, resource_type="instance", criterion=None):
        """
        Handle a generic delete of a fixed ip within a zone

        :param criterion: Criterion to search and destroy records
        """
        if not managed:
            LOG.warning(
                _LW(
                    "Deprecation notice: Unmanaged designate-sink records are "
                    "being deprecated please update the call "
                    "to remove managed=False"
                )
            )
        criterion = criterion or {}

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        criterion.update({"zone_id": zone_id})

        if managed:
            criterion.update(
                {
                    "managed": managed,
                    "managed_plugin_name": self.get_plugin_name(),
                    "managed_plugin_type": self.get_plugin_type(),
                    "managed_resource_id": resource_id,
                    "managed_resource_type": resource_type,
                }
            )

        records = self.central_api.find_records(context, criterion)

        for record in records:
            LOG.debug("Deleting record %s", record["id"])

            self.central_api.delete_record(context, zone_id, record["recordset_id"], record["id"])
Esempio n. 18
0
    def process_request(self, request):
        headers = request.headers

        roles = headers.get('X-Roles').split(',')

        context = DesignateContext(auth_token=headers.get('X-Auth-Token'),
                                   user=headers.get('X-User-ID'),
                                   tenant=headers.get('X-Tenant-ID'),
                                   roles=roles)

        # Store the context where oslo-log exepcts to find it.
        local.store.context = context

        # Attempt to sudo, if requested.
        sudo_tenant_id = headers.get('X-Designate-Sudo-Tenant-ID', None)

        if sudo_tenant_id and (uuidutils.is_uuid_like(sudo_tenant_id)
                               or sudo_tenant_id.isdigit()):
            context.sudo(sudo_tenant_id)

        # Attach the context to the request environment
        request.environ['context'] = context
Esempio n. 19
0
    def start(self):

        # Build the Pool (and related) Object from Config
        context = DesignateContext.get_admin_context()
        pool_id = CONF['service:pool_manager'].pool_id

        has_targets = False

        while not has_targets:
            try:
                self.pool = self.central_api.get_pool(context, pool_id)

                if len(self.pool.targets) > 0:
                    has_targets = True
                else:
                    LOG.error(_LE("No targets for %s found."), self.pool)
                    time.sleep(5)

            # Pool data may not have migrated to the DB yet
            except exceptions.PoolNotFound:
                LOG.error(_LE("Pool ID %s not found."), pool_id)
                time.sleep(5)
            # designate-central service may not have started yet
            except messaging.exceptions.MessagingTimeout:
                time.sleep(0.2)

        # Create the necessary Backend instances for each target
        self._setup_target_backends()

        for target in self.pool.targets:
            self.target_backends[target.id].start()

        super(Service, self).start()

        # Setup a Leader Election, use for ensuring certain tasks are executed
        # on exactly one pool-manager instance at a time]
        self._pool_election = coordination.LeaderElection(
            self._coordinator, '%s:%s' % (self.service_name, self.pool.id))
        self._pool_election.start()

        if CONF['service:pool_manager'].enable_recovery_timer:
            interval = CONF['service:pool_manager'].periodic_recovery_interval
            LOG.info(_LI('Starting periodic recovery timer every'
                         ' %(interval)s s') % {'interval': interval})
            self.tg.add_timer(interval, self.periodic_recovery, interval)

        if CONF['service:pool_manager'].enable_sync_timer:
            interval = CONF['service:pool_manager'].periodic_sync_interval
            LOG.info(_LI('Starting periodic synchronization timer every'
                         ' %(interval)s s') % {'interval': interval})
            self.tg.add_timer(interval, self.periodic_sync, interval)
Esempio n. 20
0
    def _create(self, addresses, extra, managed=True,
                resource_type=None, resource_id=None):
        """
        Create a a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param managed: Is it a managed resource
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        LOG.debug('Using DomainID: %s' % cfg.CONF[self.name].domain_id)
        domain = self.get_domain(cfg.CONF[self.name].domain_id)
        LOG.debug('Domain: %r' % domain)

        data = extra.copy()
        LOG.debug('Event data: %s' % data)
        data['domain'] = domain['name']

        context = DesignateContext.get_admin_context(all_tenants=True)

        for addr in addresses:
            event_data = data.copy()
            event_data.update(get_ip_data(addr))

            recordset_values = {
                'domain_id': domain['id'],
                'name': self._get_format() % event_data,
                'type': 'A' if addr['version'] == 4 else 'AAAA'}

            recordset = self._find_or_create_recordset(
                context, **recordset_values)

            record_values = {
                'data': addr['address']}

            if managed:
                record_values.update({
                    'managed': managed,
                    'managed_plugin_name': self.get_plugin_name(),
                    'managed_plugin_type': self.get_plugin_type(),
                    'managed_resource_type': resource_type,
                    'managed_resource_id': resource_id})

            LOG.debug('Creating record in %s / %s with values %r' %
                      (domain['id'], recordset['id'], record_values))
            self.central_api.create_record(context,
                                           domain['id'],
                                           recordset['id'],
                                           Record(**record_values))
Esempio n. 21
0
    def process_request(self, request):
        headers = request.headers

        try:
            if headers["X-Identity-Status"] is "Invalid":
                # TODO(graham) fix the return to use non-flask resources
                return flask.Response(status=401)
        except KeyError:
            # If the key is valid, Keystone does not include this header at all
            pass

        if headers.get("X-Service-Catalog"):
            catalog = json.loads(headers.get("X-Service-Catalog"))
        else:
            catalog = None

        roles = headers.get("X-Roles").split(",")

        context = DesignateContext(
            auth_token=headers.get("X-Auth-Token"),
            user=headers.get("X-User-ID"),
            tenant=headers.get("X-Tenant-ID"),
            roles=roles,
            service_catalog=catalog,
        )

        # Store the context where oslo-log exepcts to find it.
        local.store.context = context

        # Attempt to sudo, if requested.
        sudo_tenant_id = headers.get("X-Designate-Sudo-Tenant-ID", None)

        if sudo_tenant_id and (uuidutils.is_uuid_like(sudo_tenant_id) or sudo_tenant_id.isdigit()):
            context.sudo(sudo_tenant_id)

        # Attach the context to the request environment
        request.environ["context"] = context
Esempio n. 22
0
    def __init__(self, target):
        super(Backend, self).__init__()

        self.target = target
        self.options = target.options
        self.masters = target.masters
        self.host = self.options.get('host', '127.0.0.1')
        self.port = int(self.options.get('port', 53))

        # TODO(kiall): Context's should never be shared across requests.
        self.admin_context = DesignateContext.get_admin_context()
        self.admin_context.all_tenants = True

        # Options for sending NOTIFYs
        self.timeout = CONF['service:pool_manager'].poll_timeout
        self.retry_interval = CONF['service:pool_manager'].poll_retry_interval
        self.max_retries = CONF['service:pool_manager'].poll_max_retries
        self.delay = CONF['service:pool_manager'].poll_delay
def main():
    args = parse_args()
    logging.setup('cirrus_floatingip')
    LOG.logger.setLevel('DEBUG')
    load_config(args.config_file)

    kc = keystone_c.Client(
        username=args.username,
        password=args.password,
        tenant_name=args.tenantname,
        auth_url=args.authurl,
        endpoint_type=args.endpoint_type,
        region_name=args.regionname)

    policy.init()
    rpc.init(cfg.CONF)
    context = DesignateContext.get_admin_context(tenant=kc.auth_tenant_id)

    handler = cirrus.CirrusFloatingIPHandler()

    args.func(kc, handler, context, args)
Esempio n. 24
0
 def _create_reverse_record(self, context, managed, host_fqdn, interface):
     LOG.info('Create reverse record for interface: %s and address: %s', interface['label'], interface['address'])
     host_reverse_fqdn = self._get_reverse_fqdn(interface['address'], interface['version'])
     LOG.info('Create reverse record: %s', host_reverse_fqdn)
     reverse_domains = self._get_reverse_domains(host_reverse_fqdn)
     admin_context = DesignateContext.get_admin_context(all_tenants=True)
     for reverse_domain in reverse_domains:
         LOG.info('Create reverse record for domain: %s', reverse_domain.name)
         try:
             recordset = self.central_api.create_recordset(admin_context,
                                                           reverse_domain.id,
                                                           RecordSet(name=host_reverse_fqdn, type='PTR'))
         except exceptions.DuplicateRecordSet:
             LOG.warn('The reverse record: %s was already registered', host_reverse_fqdn)
         else:
             record_values = dict(managed, data=host_fqdn)
             LOG.debug('Creating reverse record in %s / %s with values %r',
                       reverse_domain.id, recordset['id'], record_values)
             self.central_api.create_record(admin_context,
                                            reverse_domain.id,
                                            recordset['id'],
                                            Record(**record_values))
Esempio n. 25
0
    def _create(self, addresses, extra, managed=True,
                resource_type=None, resource_id=None):
        """
        Create a a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param managed: Is it a managed resource
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        LOG.debug('Using DomainID: %s' % cfg.CONF[self.name].domain_id)
        domain = self.get_domain(cfg.CONF[self.name].domain_id)
        LOG.debug('Domain: %r' % domain)

        data = extra.copy()
        data['domain'] = domain['name']

        context = DesignateContext.get_admin_context()

        for addr in addresses:
            record_data = data.copy()
            record_data.update(get_ip_data(addr))

            record_name = self._get_format() % record_data
            record_values = {
                'type': 'A' if addr['version'] == 4 else 'AAAA',
                'name': record_name,
                'data': addr['address']}
            if managed:
                record_values.update({
                    'managed': managed,
                    'managed_plugin_name': self.get_plugin_name(),
                    'managed_plugin_type': self.get_plugin_type(),
                    'managed_resource_type': resource_type,
                    'managed_resource_id': resource_id})
            central_api.create_record(context, domain['id'], record_values)
Esempio n. 26
0
    def periodic_sync(self):
        """
        :return: None
        """
        # TODO(kiall): Replace this inter-process-lock with a distributed
        #              lock, likely using the tooz library - see bug 1445127.
        with lockutils.lock('periodic_sync', external=True, delay=30):
            context = DesignateContext.get_admin_context(all_tenants=True)

            LOG.debug("Starting Periodic Synchronization")

            criterion = {
                'pool_id': CONF['service:pool_manager'].pool_id,
                'status': '!%s' % ERROR_STATUS
            }

            periodic_sync_seconds = \
                CONF['service:pool_manager'].periodic_sync_seconds

            if periodic_sync_seconds is not None:
                # Generate the current serial, will provide a UTC Unix TS.
                current = utils.increment_serial()
                criterion['serial'] = ">%s" % (current - periodic_sync_seconds)

            domains = self.central_api.find_domains(context, criterion)

            try:
                for domain in domains:
                    # TODO(kiall): If the domain was created within the last
                    #              periodic_sync_seconds, attempt to recreate
                    #              to fill in targets which may have failed.
                    self.update_domain(context, domain)

            except Exception:
                LOG.exception(_LE('An unhandled exception in periodic '
                                  'synchronization occurred.'))
Esempio n. 27
0
    def _delete(self, extra, managed=True, resource_id=None,
                resource_type='instance', criterion={}):
        """
        Handle a generic delete of a fixed ip within a zone

        :param criterion: Criterion to search and destroy records
        """

        zone = self.get_zone(cfg.CONF[self.name].domain_id)

        data = extra.copy()
        LOG.debug('Event data: %s' % data)
        data['zone'] = zone['name']

        data['project_name'] = data['tenant_id']

        event_data = data.copy()

        fqdn = cfg.CONF[self.name].fqdn_format % event_data
        fqdn = fqdn.rstrip('.')

        keystone = keystone_client.Client(
            session=self._get_keystone_session(), interface='public', connect_retries=5)
        region_recs = keystone.regions.list()
        regions = [region.id for region in region_recs]
        if len(regions) > 1:
            # We need to make sure this VM doesn't exist in another region.  If it does
            #  then we don't want to purge anything because we'll break that one.
            for region in regions:
                if region == cfg.CONF[self.name].region:
                    continue
                nova = novaclient.Client('2', session=self._get_keystone_session(data['tenant_id']),
                                         region_name=region)
                servers = nova.servers.list()
                servernames = [server.name for server in servers]
                if event_data['hostname'] in servernames:
                    LOG.warning("Skipping cleanup of %s because it is also present in region %s" %
                                (fqdn, region))
                    return

        # Clean puppet keys for deleted instance
        if cfg.CONF[self.name].puppet_master_host:
            LOG.debug('Cleaning puppet key %s' % fqdn)
            self._run_remote_command(cfg.CONF[self.name].puppet_master_host,
                                     cfg.CONF[self.name].certmanager_user,
                                     'sudo puppet cert clean %s' %
                                     pipes.quote(fqdn))

        # Clean up the puppet config for this instance, if there is one
        self._delete_puppet_config(data['tenant_id'], fqdn)
        self._delete_puppet_git_config(data['tenant_id'], fqdn)

        # For good measure, look around for things associated with the old domain as well
        if cfg.CONF[self.name].legacy_domain_id:
            legacy_zone = self.get_zone(cfg.CONF[self.name].legacy_domain_id)
            legacy_data = data.copy()
            legacy_data['zone'] = legacy_zone['name']
            legacy_fqdn = cfg.CONF[self.name].fqdn_format % legacy_data
            legacy_fqdn = legacy_fqdn.rstrip('.')
            if cfg.CONF[self.name].puppet_master_host:
                LOG.debug('Cleaning puppet key %s' % legacy_fqdn)
                self._run_remote_command(cfg.CONF[self.name].puppet_master_host,
                                         cfg.CONF[self.name].certmanager_user,
                                         'sudo puppet cert clean %s' %
                                         pipes.quote(legacy_fqdn))

            # Clean up the puppet config for this instance, if there is one
            self._delete_puppet_config(legacy_data['tenant_id'], legacy_fqdn)
            self._delete_puppet_git_config(legacy_data['tenant_id'], legacy_fqdn)

        # Finally, delete any proxy records pointing to this instance.
        #
        # For that, we need the IP which we can dig out of the old DNS record.
        crit = criterion.copy()

        # Make sure we only look at forward records
        crit['zone_id'] = cfg.CONF[self.name].domain_id

        if managed:
            crit.update({
                'managed': managed,
                'managed_resource_id': resource_id,
                'managed_resource_type': resource_type
            })

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        records = central_api.find_records(context, crit)

        # We only care about the IP, and that's the same in both records.
        ip = records[0].data
        LOG.debug("Cleaning up proxy records for IP %s" % ip)
        try:
            self._delete_proxies_for_ip(data['project_name'], ip)
        except requests.exceptions.ConnectionError:
            LOG.warning("Caught exception when deleting proxy records", exc_info=True)
    def process_notification(self, context, event_type, payload):
        LOG.debug('NeutronFloatingHandler: Event type received: %s',
                  event_type)
        LOG.debug('NeutronFloatingHandler: Event body received: %s', payload)
        zone_id = cfg.CONF[self.name].zone_id
        zone = self.get_zone(zone_id)

        # Get a list all all zones owned by the zone tenant owner.
        # This is so we can find the reverse DNS zone.
        elevated_context = DesignateContext.get_admin_context(
            all_tenants=True, edit_managed_records=True)

        criterion = {
            "tenant_id": cfg.CONF[self.name].zone_owner_tenant_id,
        }

        zones = self.central_api.find_zones(elevated_context, criterion)

        if event_type.startswith('floatingip.delete'):
            self._delete(zone_id=zone_id,
                         resource_id=payload['floatingip_id'],
                         resource_type='instance')
        elif event_type.startswith('floatingip.update'):
            floatingip = payload['floatingip']['floating_ip_address']

            # Calculate Reverse Address
            v4address = ipaddress.ip_address(floatingip)
            reverse_address = v4address.reverse_pointer + '.'
            reverse_network = '.'.join(reverse_address.split('.')[1:])
            reverse_id = None

            # Loop through all zones and see if one matches the reverse zone
            reverse_id = None
            for i in zones:
                if i.name == reverse_network:
                    reverse_id = i.id

            if payload['floatingip']['fixed_ip_address']:
                # Create a nova client
                username = cfg.CONF[self.name].admin_user
                password = cfg.CONF[self.name].admin_password
                tenant_name = cfg.CONF[self.name].admin_tenant_name
                auth_url = cfg.CONF[self.name].auth_url
                auth = v3.Password(username=username,
                                   password=password,
                                   project_name=tenant_name,
                                   project_domain_name='default',
                                   user_domain_name='default',
                                   auth_url=auth_url)
                sess = session.Session(auth=auth)
                nvc = nova_c.Client(2.1, session=sess)

                # Search for an instance with the matching fixed ip
                search_opts = {
                    'ip': payload['floatingip']['fixed_ip_address'],
                    'status': 'ACTIVE',
                    'all_tenants': True,
                    'tenant_id': payload['floatingip']['tenant_id'],
                }
                instances = nvc.servers.list(detailed=True,
                                             search_opts=search_opts)

                if len(instances) == 1:
                    instance = instances[0]
                    # Get the ec2 id of the instance and build the hostname from it
                    ec2id = getattr(instance, 'OS-EXT-SRV-ATTR:instance_name')
                    ec2id = ec2id.split('-', 1)[1].lstrip('0')
                    hostname = '%s.%s' % (ec2id, zone['name'])

                    # create a recordset
                    record_type = 'A'
                    recordset_values = {
                        'zone_id': zone_id,
                        'name': hostname,
                        'type': record_type
                    }
                    recordset = self._find_or_create_recordset(
                        elevated_context, **recordset_values)
                    record_values = {
                        'data': floatingip,
                        'managed': True,
                        'managed_plugin_name': self.get_plugin_name(),
                        'managed_plugin_type': self.get_plugin_type(),
                        'managed_resource_type': 'instance',
                        'managed_resource_id': payload['floatingip']['id'],
                        'managed_extra':
                        'instance:%s' % (getattr(instance, 'id')),
                    }

                    LOG.debug('Creating record in %s / %s with values %r' %
                              (zone_id, recordset['id'], record_values))
                    self.central_api.create_record(elevated_context, zone_id,
                                                   recordset['id'],
                                                   Record(**record_values))

                    # create a reverse recordset
                    record_type = 'PTR'

                    if reverse_id == None:
                        LOG.debug('UNABLE TO DETERMINE REVERSE ZONE: %s',
                                  payload['floatingip'])

                    else:
                        recordset_values = {
                            'zone_id': reverse_id,
                            'name': reverse_address,
                            'type': record_type
                        }

                        recordset = self._find_or_create_recordset(
                            elevated_context, **recordset_values)
                        record_values = {
                            'data':
                            hostname,
                            'managed':
                            True,
                            'managed_plugin_name':
                            self.get_plugin_name(),
                            'managed_plugin_type':
                            self.get_plugin_type(),
                            'managed_resource_type':
                            'instance',
                            'managed_resource_id':
                            payload['floatingip']['id'],
                            'managed_extra':
                            'instance:%s' % (getattr(instance, 'id')),
                        }

                        LOG.debug('Creating record in %s / %s with values %r' %
                                  (reverse_id, recordset['id'], record_values))
                        self.central_api.create_record(elevated_context,
                                                       reverse_id,
                                                       recordset['id'],
                                                       Record(**record_values))
            else:
                LOG.debug('Deleting records for %s / %s' %
                          (zone_id, payload['floatingip']['id']))
                self._delete(zone_id=zone_id,
                             resource_id=payload['floatingip']['id'],
                             resource_type='instance')

                if reverse_id == None:
                    LOG.debug('UNABLE TO DETERMINE REVERSE ZONE: %s',
                              payload['floatingip'])
                else:
                    LOG.debug('Deleting records for %s / %s' %
                              (reverse_id, payload['floatingip']['id']))
                    self._delete(zone_id=reverse_id,
                                 resource_id=payload['floatingip']['id'],
                                 resource_type='instance')
Esempio n. 29
0
 def _get_admin_context_all_tenants(self):
     return DesignateContext.get_admin_context(all_tenants=True)
Esempio n. 30
0
    def _create(self,
                addresses,
                extra,
                managed=True,
                resource_type=None,
                resource_id=None):
        """
        Create a a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param managed: Is it a managed resource
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        if not managed:
            LOG.warning(
                _LW('Deprecation notice: Unmanaged designate-sink records are '
                    'being deprecated please update the call '
                    'to remove managed=False'))
        LOG.debug('Using DomainID: %s' % cfg.CONF[self.name].domain_id)
        domain = self.get_domain(cfg.CONF[self.name].domain_id)
        LOG.debug('Domain: %r' % domain)

        data = extra.copy()
        LOG.debug('Event data: %s' % data)
        data['domain'] = domain['name']

        context = DesignateContext.get_admin_context(all_tenants=True)

        for addr in addresses:
            event_data = data.copy()
            event_data.update(get_ip_data(addr))

            recordset_values = {
                'domain_id': domain['id'],
                'name': self._get_format() % event_data,
                'type': 'A' if addr['version'] == 4 else 'AAAA'
            }

            recordset = self._find_or_create_recordset(context,
                                                       **recordset_values)

            record_values = {'data': addr['address']}

            if managed:
                record_values.update({
                    'managed':
                    managed,
                    'managed_plugin_name':
                    self.get_plugin_name(),
                    'managed_plugin_type':
                    self.get_plugin_type(),
                    'managed_resource_type':
                    resource_type,
                    'managed_resource_id':
                    resource_id
                })

            LOG.debug('Creating record in %s / %s with values %r' %
                      (domain['id'], recordset['id'], record_values))
            self.central_api.create_record(context, domain['id'],
                                           recordset['id'],
                                           Record(**record_values))
Esempio n. 31
0
    def process_notification(self, context, event_type, payload):
        # Take notification and create a record
        LOG.debug('FloatingV4Handler: Event type received: %s', event_type)
        zone = self.get_zone(cfg.CONF[self.name].zone_id)

        domain_id = zone['id']

        # Gather extra information (need to compare payload['floating_ip'] and figure out which zone it fits in.
        # The domains are owned by admin so we need admin context?

        elevated_context = DesignateContext.get_admin_context(all_tenants=True, edit_managed_records=True)

        criterion = {
            "tenant_id": cfg.CONF[self.name].admin_tenant_id,
        }

        zones = self.central_api.find_zones(elevated_context, criterion)

        # Calculate Reverse Address
        v4address = ipaddress.ip_address(payload['floating_ip'])
        reverse_address = v4address.reverse_pointer + '.'
        reverse_network = '.'.join(reverse_address.split('.')[1:])
        reverse_id = None

        for i in zones:
            if i.name == reverse_network:
                reverse_id = i.id

        if event_type == 'network.floating_ip.associate':
            LOG.debug('FloatingV4Handler: Creating A record for %s on %s', payload['floating_ip'], payload['instance_id'])

            # Get ec2id for hostname (must be admin
            kc = keystone_c.Client(username=cfg.CONF['keystone_authtoken'].admin_user,
                    password=cfg.CONF['keystone_authtoken'].admin_password,
                    tenant_name=cfg.CONF['keystone_authtoken'].admin_tenant_name,
                    auth_url = cfg.CONF['handler:nova_fixed_v6'].auth_uri)

            nova_endpoint = kc.service_catalog.url_for(service_type='compute',
                        endpoint_type='internalURL')

            nvc = nova_c.Client(auth_token=kc.auth_token,
                        tenant_id=kc.auth_tenant_id,
                        bypass_url=nova_endpoint)

            server_info = nvc.servers.get(payload['instance_id'])

            # Determine the hostname
            ec2id = getattr(server_info, 'OS-EXT-SRV-ATTR:instance_name')
            ec2id = ec2id.split('-', 1)[1].lstrip('0')
            hostname = '%s.%s' % (ec2id, zone['name'])

            record_type = 'A'

            recordset_values = {
                'zone_id': domain_id,
                'name': hostname,
                'type': record_type
            }

            recordset = self._find_or_create_recordset(elevated_context, **recordset_values)

            record_values = {
                'data': payload['floating_ip'],
                'managed': True,
                'managed_plugin_name': self.get_plugin_name(),
                'managed_plugin_type': self.get_plugin_type(),
                'managed_resource_type': 'instance',
                'managed_resource_id': payload['instance_id']
            }

            LOG.debug('Creating record in %s / %s with values %r' %
                      (domain_id, recordset['id'], record_values))
            self.central_api.create_record(elevated_context,
                                       domain_id,
                                       recordset['id'],
                                       Record(**record_values))

            # Reverse Record

            record_type = 'PTR'

            if reverse_id == None:
                LOG.debug('UNABLE TO DETERMINE REVERSE ZONE: %s', payload['floating_ip'])

            else:
                recordset_values = {
                    'zone_id': reverse_id,
                    'name': reverse_address,
                    'type': record_type
                }

                recordset = self._find_or_create_recordset(elevated_context, **recordset_values)
                record_values = {
                    'data': hostname,
                    'managed': True,
                    'managed_plugin_name': self.get_plugin_name(),
                    'managed_plugin_type': self.get_plugin_type(),
                    'managed_resource_type': 'instance',
                    'managed_resource_id': payload['instance_id']
                }

                LOG.debug('Creating record in %s / %s with values %r' %
                          (reverse_id, recordset['id'], record_values))
                self.central_api.create_record(elevated_context,
                                           reverse_id,
                                           recordset['id'],
                                           Record(**record_values))

        elif event_type == 'network.floating_ip.disassociate':
            LOG.debug('FloatingV4Handler: Deleting A record for %s on %s', payload['floating_ip'], payload['instance_id'])

            self._delete(zone_id=domain_id,
                    resource_id=payload['instance_id'],
                    resource_type='instance')

            if reverse_id == None:
                LOG.debug('UNABLE TO DETERMINE REVERSE ZONE: %s', payload['floating_ip'])

            else:
                self._delete(zone_id=reverse_id,
                    resource_id=payload['instance_id'],
                    resource_type='instance')
Esempio n. 32
0
 def get_admin_context(self):
     return DesignateContext.get_admin_context()
Esempio n. 33
0
    def start(self):
        # Build the Pool (and related) Object from Config
        context = DesignateContext.get_admin_context()
        pool_id = CONF['service:pool_manager'].pool_id

        has_targets = False

        # TODO(kiall): This block of code should be replaced with a cleaner,
        #              limited version. e.g. should retry for X minutes, and
        #              backoff rather than fixed retry intervals.
        while not has_targets:
            try:
                self.pool = self.central_api.get_pool(context, pool_id)

                if len(self.pool.targets) > 0:
                    has_targets = True
                else:
                    LOG.error(_LE("No targets for %s found."), self.pool)
                    time.sleep(5)

            # Pool data may not have migrated to the DB yet
            except exceptions.PoolNotFound:
                LOG.error(_LE("Pool ID %s not found."), pool_id)
                time.sleep(5)
            # designate-central service may not have started yet
            except messaging.exceptions.MessagingTimeout:
                time.sleep(0.2)
            # designate-central failed in an unknown way, don't allow another
            # failing / not started service to cause pool-manager to crash.
            except Exception:
                LOG.exception(
                    _LE("An unknown exception occurred while "
                        "fetching pool details"))
                time.sleep(5)

        # Create the necessary Backend instances for each target
        self._setup_target_backends()

        for target in self.pool.targets:
            self.target_backends[target.id].start()

        super(Service, self).start()

        # Setup a Leader Election, use for ensuring certain tasks are executed
        # on exactly one pool-manager instance at a time]
        self._pool_election = coordination.LeaderElection(
            self._coordinator, '%s:%s' % (self.service_name, self.pool.id))
        self._pool_election.start()

        if CONF['service:pool_manager'].enable_recovery_timer:
            interval = CONF['service:pool_manager'].periodic_recovery_interval
            LOG.info(
                _LI('Starting periodic recovery timer every'
                    ' %(interval)s s') % {'interval': interval})
            self.tg.add_timer(interval, self.periodic_recovery, interval)

        if CONF['service:pool_manager'].enable_sync_timer:
            interval = CONF['service:pool_manager'].periodic_sync_interval
            LOG.info(
                _LI('Starting periodic synchronization timer every'
                    ' %(interval)s s') % {'interval': interval})
            self.tg.add_timer(interval, self.periodic_sync, interval)
Esempio n. 34
0
    def _create(self,
                addresses,
                extra,
                zone_id,
                managed=True,
                resource_type=None,
                resource_id=None):
        """
        Create a a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param zone_id: The ID of the designate zone.
        :param managed: Is it a managed resource
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        if not managed:
            LOG.warning(
                _LW('Deprecation notice: Unmanaged designate-sink records are '
                    'being deprecated please update the call '
                    'to remove managed=False'))
        LOG.debug('Using Zone ID: %s', zone_id)
        zone = self.get_zone(zone_id)
        LOG.debug('Domain: %r', zone)

        data = extra.copy()
        LOG.debug('Event data: %s', data)
        data['zone'] = zone['name']

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        for addr in addresses:
            event_data = data.copy()
            event_data.update(self._get_ip_data(addr))

            if addr['version'] == 4:
                format = self._get_formatv4()
            else:
                format = self._get_formatv6()

            for fmt in format:
                recordset_values = {
                    'zone_id': zone['id'],
                    'name': fmt % event_data,
                    'type': 'A' if addr['version'] == 4 else 'AAAA'
                }

                recordset = self._find_or_create_recordset(
                    context, **recordset_values)

                record_values = {'data': addr['address']}

                if managed:
                    record_values.update({
                        'managed':
                        managed,
                        'managed_plugin_name':
                        self.get_plugin_name(),
                        'managed_plugin_type':
                        self.get_plugin_type(),
                        'managed_resource_type':
                        resource_type,
                        'managed_resource_id':
                        resource_id
                    })

                LOG.debug('Creating record in %s / %s with values %r',
                          zone['id'], recordset['id'], record_values)
                self.central_api.create_record(context, zone['id'],
                                               recordset['id'],
                                               Record(**record_values))
Esempio n. 35
0
 def get_zone(self, zone_id):
     """
     Return the zone for this context
     """
     context = DesignateContext.get_admin_context(all_tenants=True)
     return self.central_api.get_zone(context, zone_id)
Esempio n. 36
0
 def get_domain(self, domain_id):
     """
     Return the domain for this context
     """
     context = DesignateContext.get_admin_context(all_tenants=True)
     return self.central_api.get_domain(context, domain_id)
Esempio n. 37
0
 def __init__(self):
     self.context = DesignateContext.get_admin_context(
         request_id='designate-manage')
     policy.init()
Esempio n. 38
0
 def get_admin_context(self):
     return DesignateContext.get_admin_context(
         project_id=utils.generate_uuid(), user_id=utils.generate_uuid())
Esempio n. 39
0
    def process_notification(self, context, event_type, payload):
        LOG.debug('NovaFixedV6Handler: Event type received %s', event_type)
        LOG.debug('NovaFixedV6Handler: Event body received %s', payload)
        zone = self.get_zone(cfg.CONF[self.name].zone_id)
        reverse_zone = self.get_zone(cfg.CONF[self.name].reverse_zone_id)

        domain_id = zone['id']
        reverse_domain_id = reverse_zone['id']

        if event_type == 'compute.instance.create.end':
            # Need admin context to get the ec2id. Otherwise using the normal context would have worked.
            username = cfg.CONF[self.name].admin_user
            password = cfg.CONF[self.name].admin_password
            tenant_name = cfg.CONF[self.name].admin_tenant_name
            auth_url = cfg.CONF[self.name].auth_url
            auth = v3.Password(username=username,
                               password=password,
                               project_name=tenant_name,
                               project_domain_name='default',
                               user_domain_name='default',
                               auth_url=auth_url)
            sess = session.Session(auth=auth)
            nvc = nova_c.Client(2.1, session=sess)

            instance = nvc.servers.get(payload['instance_id'])

            # Determine the hostname
            ec2id = getattr(instance, 'OS-EXT-SRV-ATTR:instance_name')
            ec2id = ec2id.split('-', 1)[1].lstrip('0')
            hostname = '%s.%s' % (ec2id, zone['name'])

            LOG.debug('NovaFixedV6Handler creating AAAA record (%s) for - %s',
                      hostname, payload['instance_id'])
            # Become Designate Admin to manage records
            context = DesignateContext.get_admin_context(all_tenants=True)

            # 1 recordset of an A and AAAA record

            for fixed_ip in payload['fixed_ips']:
                # Don't create an A record for the private address.
                if fixed_ip['version'] == 4:
                    continue

                record_type = 'AAAA'

                recordset_values = {
                    'zone_id': domain_id,
                    'name': hostname,
                    'type': record_type
                }

                recordset = self._find_or_create_recordset(
                    context, **recordset_values)

                record_values = {
                    'data': fixed_ip['address'],
                    'managed': True,
                    'managed_plugin_name': self.get_plugin_name(),
                    'managed_plugin_type': self.get_plugin_type(),
                    'managed_resource_type': 'instance',
                    'managed_resource_id': payload['instance_id']
                }

                LOG.debug('Creating record in %s / %s with values %r' %
                          (domain_id, recordset['id'], record_values))
                self.central_api.create_record(context, domain_id,
                                               recordset['id'],
                                               Record(**record_values))

                # Create PTR
                record_type = 'PTR'

                # Calculate reverse address
                v6address = ipaddress.ip_address(fixed_ip['address'])
                reverse_address = v6address.reverse_pointer + '.'

                recordset_values = {
                    'zone_id': reverse_domain_id,
                    'name': reverse_address,
                    'type': record_type
                }

                reverse_recordset = self._find_or_create_recordset(
                    context, **recordset_values)

                record_values = {
                    'data': hostname,
                    'managed': True,
                    'managed_plugin_name': self.get_plugin_name(),
                    'managed_plugin_type': self.get_plugin_type(),
                    'managed_resource_type': 'instance',
                    'managed_resource_id': payload['instance_id']
                }

                LOG.debug(
                    'NovaFixedV6Handler Creating record in %s / %s with values %r'
                    % (reverse_domain_id, reverse_recordset['id'],
                       record_values))
                self.central_api.create_record(context, reverse_domain_id,
                                               reverse_recordset['id'],
                                               Record(**record_values))

                nvc.servers.set_meta_item(instance, 'dns', hostname[:-1])

        elif event_type == 'compute.instance.delete.start':
            # Nova Delete Event does not include fixed_ips. Hence why we had the instance ID in the records.
            LOG.debug('NovaFixedV6Handler delete A and AAAA record for - %s',
                      payload['instance_id'])

            self._delete(zone_id=domain_id,
                         resource_id=payload['instance_id'],
                         resource_type='instance')
            self._delete(zone_id=reverse_domain_id,
                         resource_id=payload['instance_id'],
                         resource_type='instance')

            # search for and delete floating IPs
            elevated_context = DesignateContext.get_admin_context(
                all_tenants=True, edit_managed_records=True)

            criterion = {
                'managed': True,
                'managed_plugin_name': 'neutron_floating',
                'managed_resource_type': 'instance',
                'managed_extra': 'instance:%s' % (payload['instance_id']),
            }
            records = self.central_api.find_records(elevated_context,
                                                    criterion)
            LOG.debug('Found %d floating ip records to delete for %s' %
                      (len(records), payload['instance_id']))
            for record in records:
                zones = self.central_api.find_zones(elevated_context)
                for zone in zones:
                    try:
                        recordset = self.central_api.get_recordset(
                            elevated_context, zone['id'],
                            record['recordset_id'])
                        LOG.debug(
                            'Deleting record %s from %s / %s' %
                            (record['id'], zone['id'], record['recordset_id']))
                        #self.central_api.delete_record(elevated_context, zone['id'], record['recordset_id'], record['id'])
                        self.central_api.delete_recordset(
                            elevated_context, zone['id'],
                            record['recordset_id'])
                    except:
                        pass
Esempio n. 40
0
    def _create(self,
                addresses,
                extra,
                managed=True,
                resource_type=None,
                resource_id=None):
        """
        Create a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param managed: Is it a managed resource
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        LOG.debug('Using DomainID: %s' % cfg.CONF[self.name].domain_id)
        zone = self.get_zone(cfg.CONF[self.name].domain_id)
        legacy_zone = self.get_zone(cfg.CONF[self.name].legacy_domain_id)
        LOG.debug('Domain: %r' % zone)

        data = extra.copy()
        LOG.debug('Event data: %s' % data)
        data['zone'] = zone['name']

        context = DesignateContext.get_admin_context(all_tenants=True)

        # We have a hack elsewhere in keystone to ensure that tenant id == tenant name.
        #  So... we can safely use the id in the fqdn.
        data['project_name'] = data['tenant_id']

        for addr in addresses:
            event_data = data.copy()
            event_data.update(self._get_ip_data(addr))

            if addr['version'] == 4:
                reverse_format = cfg.CONF[self.name].get('reverse_format')
                reverse_zone_id = cfg.CONF[self.name].get('reverse_domain_id')
                if reverse_format and reverse_zone_id:
                    reverse_zone = self.get_zone(reverse_zone_id)
                    LOG.debug('Reverse zone: %r' % reverse_zone)

                    ip_digits = addr['address'].split('.')
                    ip_digits.reverse()
                    name = "%s.in-addr.arpa." % '.'.join(ip_digits)

                    recordset_values = {
                        'zone_id': reverse_zone['id'],
                        'name': name,
                        'type': 'PTR',
                    }
                    recordset = self._find_or_create_recordset(
                        context, **recordset_values)

                    record_values = {'data': reverse_format % event_data}

                    if managed:
                        record_values.update({
                            'managed':
                            managed,
                            'managed_plugin_name':
                            self.get_plugin_name(),
                            'managed_plugin_type':
                            self.get_plugin_type(),
                            'managed_resource_type':
                            resource_type,
                            'managed_resource_id':
                            resource_id
                        })

                    LOG.warn(
                        'Creating reverse record in %s / %s with values %r',
                        reverse_zone['id'], recordset['id'], record_values)
                    central_api.create_record(context, reverse_zone['id'],
                                              recordset['id'],
                                              Record(**record_values))

            for fmt in cfg.CONF[self.name].get('format'):
                self._create_record(context, fmt, zone, event_data, addr,
                                    managed, resource_type, resource_id)

            event_data['zone'] = legacy_zone['name']
            for fmt in cfg.CONF[self.name].get('legacy_format'):
                self._create_record(context, fmt, legacy_zone, event_data,
                                    addr, managed, resource_type, resource_id)
Esempio n. 41
0
 def get_admin_context(self):
     return DesignateContext.get_admin_context()
    def process_notification(self, context, event_type, payload):
        """Process floating IP notifications from Neutron"""

        LOG.info('%s received notification - %s' %
                 (self.get_canonical_name(), event_type))

        # We need a context that will allow us to manipulate records that are
        # flagged as managed, so we can't use the context that was provided
        # with the notification.
        elevated_context = DesignateContext(tenant=context['tenant']).elevated()
        elevated_context.all_tenants = True
        elevated_context.edit_managed_records = True

        # Create an object from the original context so we can use it with the
        # RPC API calls.  We want this limited to the single tenant so we can
        # use it to find their domains.
        orig_context = DesignateContext(tenant=context['tenant']).elevated()

        # When an instance is deleted, we never get a floating IP update event,
        # we just get notified that the underlying port was deleted.  In that
        # case look for it under the other key.
        if event_type.startswith('port.delete'):
            self._disassociate_port_id(context=elevated_context,
                                       port_id=payload['port_id'])

        if event_type.startswith('floatingip.'):
            # A floating IP can only be associated with a single instance at a
            # time, so the first thing we always do is remove any existing
            # association when we get an update.  This is always safe whether
            # or not we're deleting it or reassigning it.
            if 'floatingip' in payload:
                # floatingip.update.end
                floating_ip = payload['floatingip']['floating_ip_address']
                floating_ip_id = payload['floatingip']['id']
            elif 'floatingip_id' in payload:
                # floatingip.delete.end
                floating_ip = None
                floating_ip_id = payload['floatingip_id']

            self._disassociate_floating_ip(context=elevated_context,
                                           floating_ip_id=floating_ip_id,
                                           )

        # If it turns out that the event is an update and it has a fixed ip in
        # the update, then we create the new record.
        if event_type.startswith('floatingip.update'):
            if payload['floatingip']['fixed_ip_address']:
                domain = self._pick_tenant_domain(orig_context,
                                                  default_regex=cfg.CONF[self.name].default_regex,
                                                  require_default_regex=cfg.CONF[self.name].require_default_regex,
                                                  )
                if domain is None:
                    LOG.info('No domains found for tenant %s(%s), ignoring Floating IP update for %s' %
                             (context['tenant_name'], context['tenant_id'], floating_ip))
                else:
                    LOG.debug('Using domain %s(%s) for tenant %s(%s)' %
                              (domain.name, domain.id,
                               context['tenant_name'], context['tenant_id']))

                    kc = keystone_c.Client(token=context['auth_token'],
                                           tenant_id=context['tenant_id'],
                                           region_name=cfg.CONF[self.name].region_name,
                                           auth_url=cfg.CONF[self.name].keystone_auth_uri)

                    port_id = payload['floatingip']['port_id']
                    instance_info = self._get_instance_info(kc, port_id)

                    extra = payload.copy()
                    extra.update({'instance_name': instance_info['name'],
                                  'instance_short_name': instance_info['name'].partition('.')[0],
                                  'domain': domain.name})
                    self._associate_floating_ip(context=elevated_context,
                                                domain_id=domain.id,
                                                extra=extra,
                                                floating_ip_id=floating_ip_id,
                                                floating_ip=floating_ip,
                                                port_id=port_id)
Esempio n. 43
0
 def get_admin_context(self):
     return DesignateContext.get_admin_context(tenant=utils.generate_uuid(),
                                               user=utils.generate_uuid())
Esempio n. 44
0
 def __init__(self, central_service):
     super(Backend, self).__init__()
     self.central_service = central_service
     self.admin_context = DesignateContext.get_admin_context()
     self.admin_context.all_tenants = True
Esempio n. 45
0
 def get_context(self, **kwargs):
     return DesignateContext(**kwargs)
Esempio n. 46
0
 def get_domain(self, domain_id):
     """
     Return the domain for this context
     """
     context = DesignateContext.get_admin_context()
     return central_api.get_domain(context, domain_id)
Esempio n. 47
0
 def __init__(self, central_service):
     super(Backend, self).__init__()
     self.central_service = central_service
     self.admin_context = DesignateContext.get_admin_context()
Esempio n. 48
0
    def _delete(self,
                extra,
                managed=True,
                resource_id=None,
                resource_type='instance',
                criterion={}):
        """
        Handle a generic delete of a fixed ip within a domain

        :param criterion: Criterion to search and destroy records
        """

        domain = self.get_domain(cfg.CONF[self.name].domain_id)

        data = extra.copy()
        LOG.debug('Event data: %s' % data)
        data['domain'] = domain['name']

        data['project_name'] = data['tenant_id']

        event_data = data.copy()

        fqdn = cfg.CONF[self.name].fqdn_format % event_data
        fqdn = fqdn.rstrip('.').encode('utf8')

        # Clean salt and puppet keys for deleted instance
        if cfg.CONF[self.name].puppet_master_host:
            LOG.debug('Cleaning puppet key %s' % fqdn)
            self._run_remote_command(
                cfg.CONF[self.name].puppet_master_host,
                cfg.CONF[self.name].certmanager_user,
                'sudo puppet cert clean %s' % pipes.quote(fqdn))

        if cfg.CONF[self.name].salt_master_host:
            LOG.debug('Cleaning salt key %s' % fqdn)
            self._run_remote_command(
                cfg.CONF[self.name].salt_master_host,
                cfg.CONF[self.name].certmanager_user,
                'sudo salt-key -y -d  %s' % pipes.quote(fqdn))

        # Clean up the puppet config for this instance, if there is one
        self._delete_puppet_config(data['tenant_id'], fqdn)

        # Finally, delete any proxy records pointing to this instance.
        #
        # For that, we need the IP which we can dig out of the old DNS record.
        crit = criterion.copy()

        # Make sure we only look at forward records
        crit['domain_id'] = cfg.CONF[self.name].domain_id

        if managed:
            crit.update({
                'managed': managed,
                'managed_resource_id': resource_id,
                'managed_resource_type': resource_type
            })

        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        records = central_api.find_records(context, crit)

        # We only care about the IP, and that's the same in both records.
        ip = records[0].data
        LOG.debug("Cleaning up proxy records for IP %s" % ip)
        self._delete_proxies_for_ip(data['project_name'], ip)
Esempio n. 49
0
    def _delete(self,
                managed=True,
                resource_id=None,
                resource_type='instance',
                criterion={}):
        """
        Handle a generic delete of a fixed ip within a zone

        :param criterion: Criterion to search and destroy records
        """
        context = DesignateContext().elevated()
        context.all_tenants = True
        context.edit_managed_records = True

        forward_crit = criterion.copy()
        forward_crit['zone_id'] = cfg.CONF[self.name].domain_id

        if managed:
            forward_crit.update({
                'managed': managed,
                'managed_plugin_name': self.get_plugin_name(),
                'managed_plugin_type': self.get_plugin_type(),
                'managed_resource_id': resource_id,
                'managed_resource_type': resource_type
            })

        records = central_api.find_records(context, forward_crit)

        for record in records:
            LOG.warn('Deleting forward record %s in recordset %s' %
                     (record['id'], record['recordset_id']))

            central_api.delete_record(context, cfg.CONF[self.name].domain_id,
                                      record['recordset_id'], record['id'])

        legacy_zone_id = cfg.CONF[self.name].get('legacy_domain_id')
        if legacy_zone_id:
            legacy_crit = criterion.copy()
            legacy_crit['zone_id'] = legacy_zone_id

            if managed:
                legacy_crit.update({
                    'managed':
                    managed,
                    'managed_plugin_name':
                    self.get_plugin_name(),
                    'managed_plugin_type':
                    self.get_plugin_type(),
                    'managed_resource_id':
                    resource_id,
                    'managed_resource_type':
                    resource_type
                })

            records = central_api.find_records(context, legacy_crit)

            for record in records:
                LOG.warn('Deleting legacy record %s in recordset %s' %
                         (record['id'], record['recordset_id']))

                central_api.delete_record(context, legacy_zone_id,
                                          record['recordset_id'], record['id'])

        reverse_zone_id = cfg.CONF[self.name].get('reverse_domain_id')
        if reverse_zone_id:
            reverse_crit = criterion.copy()
            reverse_crit.update({'zone_id': reverse_zone_id})

            if managed:
                reverse_crit.update({
                    'managed':
                    managed,
                    'managed_plugin_name':
                    self.get_plugin_name(),
                    'managed_plugin_type':
                    self.get_plugin_type(),
                    'managed_resource_id':
                    resource_id,
                    'managed_resource_type':
                    resource_type
                })

            records = central_api.find_records(context, reverse_crit)

            for record in records:
                LOG.warn('Deleting reverse record %s in recordset %s' %
                         (record['id'], record['recordset_id']))

                central_api.delete_record(context, reverse_zone_id,
                                          record['recordset_id'], record['id'])
Esempio n. 50
0
    def _create(self,
                addresses,
                extra,
                managed=True,
                resource_type=None,
                resource_id=None):
        """
        Create a a record from addresses

        :param addresses: Address objects like
                          {'version': 4, 'ip': '10.0.0.1'}
        :param extra: Extra data to use when formatting the record
        :param managed: Is it a managed resource
        :param resource_type: The managed resource type
        :param resource_id: The managed resource ID
        """
        LOG.debug('Using DomainID: %s' % cfg.CONF[self.name].domain_id)
        domain = self.get_domain(cfg.CONF[self.name].domain_id)
        LOG.debug('Domain: %r' % domain)

        data = extra.copy()
        LOG.debug('Event data: %s' % data)
        data['domain'] = domain['name']

        context = DesignateContext.get_admin_context(all_tenants=True)

        # Extra magic!  The event record contains a tenant id but not a tenant name.  So
        #  if our formats include project_name then we need to ask keystone for the name.
        need_project_name = False
        for fmt in cfg.CONF[self.name].get('format'):
            if 'project_name' in fmt:
                need_project_name = True
                break
        if 'project_name' in cfg.CONF[self.name].get('reverse_format'):
            need_project_name = True
        if need_project_name:
            project_name = self._resolve_project_name(data['tenant_id'])
            data['project_name'] = project_name

        for addr in addresses:
            event_data = data.copy()
            event_data.update(self._get_ip_data(addr))

            if addr['version'] == 4:
                reverse_format = cfg.CONF[self.name].get('reverse_format')
                reverse_domain_id = cfg.CONF[self.name].get(
                    'reverse_domain_id')
                if reverse_format and reverse_domain_id:
                    reverse_domain = self.get_domain(reverse_domain_id)
                    LOG.debug('Reverse domain: %r' % reverse_domain)

                    ip_digits = addr['address'].split('.')
                    ip_digits.reverse()
                    name = "%s.in-addr.arpa." % '.'.join(ip_digits)

                    recordset_values = {
                        'domain_id': reverse_domain['id'],
                        'name': name,
                        'type': 'PTR',
                    }
                    recordset = self._find_or_create_recordset(
                        context, **recordset_values)

                    record_values = {'data': reverse_format % event_data}

                    if managed:
                        record_values.update({
                            'managed':
                            managed,
                            'managed_plugin_name':
                            self.get_plugin_name(),
                            'managed_plugin_type':
                            self.get_plugin_type(),
                            'managed_resource_type':
                            resource_type,
                            'managed_resource_id':
                            resource_id
                        })

                    LOG.debug('Creating record in %s / %s with values %r',
                              reverse_domain['id'], recordset['id'],
                              record_values)
                    central_api.create_record(context, reverse_domain['id'],
                                              recordset['id'],
                                              Record(**record_values))

            for fmt in cfg.CONF[self.name].get('format'):
                recordset_values = {
                    'domain_id': domain['id'],
                    'name': fmt % event_data,
                    'type': 'A' if addr['version'] == 4 else 'AAAA'
                }

                recordset = self._find_or_create_recordset(
                    context, **recordset_values)

                record_values = {'data': addr['address']}

                if managed:
                    record_values.update({
                        'managed':
                        managed,
                        'managed_plugin_name':
                        self.get_plugin_name(),
                        'managed_plugin_type':
                        self.get_plugin_type(),
                        'managed_resource_type':
                        resource_type,
                        'managed_resource_id':
                        resource_id
                    })

                LOG.debug('Creating record in %s / %s with values %r',
                          domain['id'], recordset['id'], record_values)
                central_api.create_record(context, domain['id'],
                                          recordset['id'],
                                          Record(**record_values))
Esempio n. 51
0
 def get_admin_context(self):
     return DesignateContext.get_admin_context(
         tenant=utils.generate_uuid(),
         user=utils.generate_uuid())
Esempio n. 52
0
    def run(self, parsed_args):
        self.context = DesignateContext.get_admin_context(
            request_id="designate-manage")

        return super(Command, self).run(parsed_args)