# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from oslo_config import cfg from oslo_log import log as logging import oslo_messaging as messaging from designate.i18n import _LI from designate import coordination from designate import exceptions from designate import quota from designate import service from designate import storage from designate import utils from designate.central import rpcapi from designate.zone_manager import tasks LOG = logging.getLogger(__name__) CONF = cfg.CONF NS = 'designate.periodic_tasks' class Service(service.RPCService, coordination.CoordinationMixin, service.Service): RPC_API_VERSION = '1.0' target = messaging.Target(version=RPC_API_VERSION) def __init__(self, threads=None): super(Service, self).__init__(threads=threads) storage_driver = cfg.CONF['service:zone_manager'].storage_driver self.storage = storage.get_storage(storage_driver) # Get a quota manager instance self.quota = quota.get_quota() @property def service_name(self): return 'zone_manager' @property def central_api(self): return rpcapi.CentralAPI.get_instance() def start(self): super(Service, self).start() self._partitioner = coordination.Partitioner( self._coordinator, self.service_name, self._coordination_id, range(0, 4095)) self._partitioner.start() self._partitioner.watch_partition_change(self._rebalance) enabled = CONF['service:zone_manager'].enabled_tasks for task in tasks.PeriodicTask.get_extensions(enabled): LOG.debug("Registering task %s" % task) # Instantiate the task task = task() # Subscribe for partition size updates. self._partitioner.watch_partition_change(task.on_partition_change) interval = CONF[task.get_canonical_name()].interval self.tg.add_timer(interval, task) def _rebalance(self, my_partitions, members, event): LOG.info(_LI("Received rebalance event %s"), event) self.partition_range = my_partitions # Begin RPC Implementation # Zone Export def start_zone_export(self, context, zone, export): criterion = {'zone_id': zone.id} count = self.storage.count_recordsets(context, criterion) export = self._determine_export_method(context, export, count) self.central_api.update_zone_export(context, export) def render_zone(self, context, zone_id): return self._export_zone(context, zone_id) def _determine_export_method(self, context, export, size): synchronous = CONF['service:zone_manager'].export_synchronous # NOTE(timsim): # The logic here with swift will work like this: # cfg.CONF.export_swift_enabled: # An export will land in their swift container, even if it's # small, but the link that comes back will be the synchronous # link (unless export_syncronous is False, in which case it # will behave like the next option) # cfg.CONF.export_swift_preffered: # The link that the user gets back will always be the swift # container, and status of the export resource will depend # on the Swift process. # If the export is too large for synchronous, or synchronous is not # enabled and swift is not enabled, it will fall through to ERROR # swift = False if synchronous: try: self.quota.limit_check( context, context.tenant, api_export_size=size) except exceptions.OverQuota(): LOG.debug('Zone Export too large to perform synchronously') export['status'] = 'ERROR' export['message'] = 'Zone is too large to export' return export export['location'] = \ "designate://v2/zones/tasks/exports/%(eid)s/export" % \ {'eid': export['id']} export['status'] = 'COMPLETE' else: LOG.debug('No method found to export zone') export['status'] = 'ERROR' export['message'] = 'No suitable method for export' return export def _export_zone(self, context, zone_id): zone = self.central_api.get_zone(context, zone_id) criterion = {'zone_id': zone_id} recordsets = self.storage.find_recordsets_export(context, criterion) return utils.render_template('export-zone.jinja2', zone=zone, recordsets=recordsets)