def _delete_proxy_dns_record(self, proxydomain): if not proxydomain.endswith('.'): proxydomain += '.' context = DesignateContext().elevated() context.all_tenants = True context.edit_managed_records = True parentdomain = '.'.join(proxydomain.split('.')[1:]) crit = {'name': parentdomain} domainrecords = central_api.find_domains(context, crit) if len(domainrecords) != 1: LOG.warning("Unable to clean up this DNS proxy record. " "Looked for domain %s and found %s" % (parentdomain, domainrecords)) return crit = {'domain_id': domainrecords[0].id, 'name': proxydomain} recordsets = central_api.find_recordsets(context, crit) if len(recordsets) != 1: LOG.warning("Unable to clean up this DNS proxy record. " "Looked for recordsets for %s and found %s" ( proxydomain, recordsets)) return LOG.warning("Deleting DNS entry for proxy: %s" % recordsets[0]) central_api.delete_recordset(context, domainrecords[0].id, recordsets[0].id)
def _delete_proxy_dns_record(self, proxyzone): if not proxyzone.endswith('.'): proxyzone += '.' context = DesignateContext().elevated() context.all_tenants = True context.edit_managed_records = True parentzone = '.'.join(proxyzone.split('.')[1:]) crit = {'name': parentzone} zonerecords = central_api.find_zones(context, crit) if len(zonerecords) != 1: LOG.warning("Unable to clean up this DNS proxy record. " "Looked for zone %s and found %s" % (parentzone, zonerecords)) return crit = {'zone_id': zonerecords[0].id, 'name': proxyzone} recordsets = central_api.find_recordsets(context, crit) if len(recordsets) != 1: LOG.warning("Unable to clean up this DNS proxy record. " "Looked for recordsets for %s and found %s" ( proxyzone, recordsets)) return LOG.warning("Deleting DNS entry for proxy: %s" % recordsets[0]) central_api.delete_recordset(context, zonerecords[0].id, recordsets[0].id)
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'])
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))
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))
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))
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().elevated() context.all_tenants = True context.edit_managed_records = True forward_crit = criterion.copy() forward_crit['domain_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']) reverse_domain_id = cfg.CONF[self.name].get('reverse_domain_id') if reverse_domain_id: reverse_crit = criterion.copy() reverse_crit.update({'domain_id': reverse_domain_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_domain_id, record['recordset_id'], record['id'])
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'} 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 } self._create_or_update_recordset( context, [Record(**record_values)], **recordset_values )
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( _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'])
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'])
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"])
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))
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() # Clean salt and puppet keys for deleted instance if (cfg.CONF[self.name].puppet_key_format and cfg.CONF[self.name].puppet_master_host): puppetkey = cfg.CONF[self.name].puppet_key_format % event_data puppetkey = puppetkey.rstrip('.').encode('utf8') LOG.debug('Cleaning puppet key %s' % puppetkey) self._run_remote_command( cfg.CONF[self.name].puppet_master_host, cfg.CONF[self.name].certmanager_user, 'sudo puppet cert clean %s' % pipes.quote(puppetkey)) if (cfg.CONF[self.name].salt_key_format and cfg.CONF[self.name].salt_master_host): saltkey = cfg.CONF[self.name].salt_key_format % event_data saltkey = saltkey.rstrip('.').encode('utf8') LOG.debug('Cleaning salt key %s' % saltkey) 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(saltkey)) # 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)
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)
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)