summaryrefslogtreecommitdiff
path: root/designate/manage/pool.py
diff options
context:
space:
mode:
Diffstat (limited to 'designate/manage/pool.py')
-rw-r--r--designate/manage/pool.py326
1 files changed, 176 insertions, 150 deletions
diff --git a/designate/manage/pool.py b/designate/manage/pool.py
index 1c7344e5..c0553d60 100644
--- a/designate/manage/pool.py
+++ b/designate/manage/pool.py
@@ -13,13 +13,14 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-import sys
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging as messaging
+import stevedore.exception
import yaml
+from designate.backend import base as backend_base
from designate.central import rpcapi as central_rpcapi
from designate import exceptions
from designate.manage import base
@@ -27,109 +28,76 @@ from designate import objects
from designate.objects.adapters import DesignateAdapter
from designate import policy
from designate import rpc
+from designate import utils
LOG = logging.getLogger(__name__)
-
-
CONF = cfg.CONF
class PoolCommands(base.Commands):
def __init__(self):
super(PoolCommands, self).__init__()
- self.output_msg = ['']
+ self.central_api = None
+ self.dry_run = False
+ self.skip_verify_drivers = False
- # NOTE(jh): Cannot do this earlier because we are still missing the config
- # at that point, see bug #1651576
- def _startup(self):
+ def _setup(self, dry_run=False, skip_verify_drivers=False):
+ self.dry_run = dry_run
+ self.skip_verify_drivers = skip_verify_drivers
rpc.init(cfg.CONF)
self.central_api = central_rpcapi.CentralAPI()
- def _create_pool(self, pool, dry_run):
- pool = DesignateAdapter.parse('YAML', pool, objects.Pool())
- for ns_record in pool.ns_records:
- try:
- ns_record.validate()
- except exceptions.InvalidObject as e:
- LOG.error(e.errors.to_list()[0]['message'])
- sys.exit(1)
-
- if dry_run:
- self.output_msg.append('Create Pool: %s' % pool)
- else:
- LOG.info('Creating new pool: %s', pool)
- self.central_api.create_pool(self.context, pool)
-
- def _update_zones(self, pool):
- LOG.info('Updating zone masters for pool: %s', pool.id)
-
- def __get_masters_from_pool(pool):
- masters = []
- for target in pool.targets:
- for master in target.get('masters', []):
- master = {'host': master['host'], 'port': master['port']}
- found = False
- for existing_master in masters:
- if master == existing_master:
- found = True
- if not found:
- masters.append(master)
- return masters
-
- policy.init()
-
- self.context.all_tenants = True
- zones = self.central_api.find_zones(
- self.context,
- criterion={'pool_id': pool.id})
-
- for zone in zones:
- zone.masters = objects.ZoneMasterList().from_list(
- __get_masters_from_pool(pool)
- )
- self.central_api.update_zone(
- self.context, zone
- )
-
@base.args('--file', help='The path to the file the yaml output should be '
- 'written to',
+ 'written to',
default='/etc/designate/pools.yaml')
def generate_file(self, file):
- self._startup()
+ self._setup()
+
try:
pools = self.central_api.find_pools(self.context)
+ data = DesignateAdapter.render('YAML', pools)
+ self._write_config_to_file(file, data)
+
except messaging.exceptions.MessagingTimeout:
LOG.critical(
'No response received from designate-central. '
'Check it is running, and retry'
)
- sys.exit(1)
- with open(file, 'w') as stream:
- yaml.dump(
- DesignateAdapter.render('YAML', pools),
- stream,
- default_flow_style=False
- )
+ raise SystemExit(1)
@base.args('--pool_id', help='ID of the pool to be examined',
default=CONF['service:central'].default_pool_id)
def show_config(self, pool_id):
- self._startup()
+ self._setup()
+
+ self.output_message.append('Pool Configuration:')
+ self.output_message.append('-------------------')
+
try:
- pool = self.central_api.find_pool(self.context, {'id': pool_id})
+ if not utils.is_uuid_like(pool_id):
+ self.output_message.append('Not a valid uuid: %s' % pool_id)
+ raise SystemExit(1)
- print('Pool Configuration:')
- print('-------------------')
+ pool = self.central_api.find_pool(self.context, {'id': pool_id})
- print(yaml.dump(DesignateAdapter.render('YAML', pool),
- default_flow_style=False))
+ self.output_message.append(
+ yaml.dump(
+ DesignateAdapter.render('YAML', pool),
+ default_flow_style=False
+ )
+ )
+ except exceptions.PoolNotFound:
+ self.output_message.append('Pool not found')
+ raise SystemExit(1)
except messaging.exceptions.MessagingTimeout:
LOG.critical(
'No response received from designate-central. '
'Check it is running, and retry'
)
- sys.exit(1)
+ raise SystemExit(1)
+ finally:
+ self._print_result()
@base.args('--file', help='The path to the yaml file describing the pools',
default='/etc/designate/pools.yaml')
@@ -144,98 +112,156 @@ class PoolCommands(base.Commands):
help='This will simulate what will happen when you run this command',
action='store_true',
default=False)
- def update(self, file, delete, dry_run):
- self._startup()
- print('Updating Pools Configuration')
- print('****************************')
-
- with open(file, 'r') as stream:
- xpools = yaml.safe_load(stream)
-
- if dry_run:
- self.output_msg.append('The following changes will occur:')
- self.output_msg.append('*********************************')
-
- for xpool in xpools:
- try:
- if 'id' in xpool:
- try:
- pool = self.central_api.get_pool(
- self.context, xpool['id']
- )
- except Exception as e:
- LOG.critical(
- 'Bad ID Supplied for pool. pool_id: '
- '%(pool)s message: %(res)s',
- {
- 'pool': xpool['id'], 'res': e
- }
- )
- continue
- else:
- pool = self.central_api.find_pool(
- self.context, {'name': xpool['name']}
- )
+ @base.args(
+ '--skip-verify-drivers',
+ help='Don\'t verify the designate backend drivers',
+ action='store_true',
+ default=False)
+ def update(self, file, delete, dry_run=False, skip_verify_drivers=False):
+ self._setup(dry_run, skip_verify_drivers)
- LOG.info('Updating existing pool: %s', pool)
+ try:
+ self.output_message.append('Updating Pools Configuration')
+ self.output_message.append('****************************')
- # TODO(kiall): Move the below into the pool object
+ pools_data = self._load_config(file)
- pool = DesignateAdapter.parse('YAML', xpool, pool)
+ if dry_run:
+ self.output_message.append('The following changes will occur:')
+ self.output_message.append('*********************************')
- # TODO(graham): We should be doing a full validation, but right
- # now there is quirks validating through nested objects.
+ for pool_data in pools_data:
+ self._create_or_update_pool(pool_data)
- for ns_record in pool.ns_records:
- try:
- ns_record.validate()
- except exceptions.InvalidObject as e:
- LOG.error(e.errors.to_list()[0]['message'])
- sys.exit(1)
+ if delete:
+ pools = self.central_api.find_pools(self.context)
+ pools_in_db = {pool.name for pool in pools}
+ pools_in_yaml = {pool_data['name'] for pool_data in pools_data}
+ pools_to_delete = pools_in_db - pools_in_yaml
+ for pool_name in pools_to_delete:
+ self._delete_pool(pool_name)
- if dry_run:
- self.output_msg.append('Update Pool: %s' % pool)
- else:
- pool = self.central_api.update_pool(self.context, pool)
- # Bug: Changes in the pool targets should trigger a
- # zone masters update LP: #1879798.
- self._update_zones(pool)
+ except exceptions.InvalidObject as e:
+ self.output_message.append(str(e))
+ raise SystemExit(1)
+ except messaging.exceptions.MessagingTimeout:
+ LOG.critical(
+ 'No response received from designate-central. '
+ 'Check it is running, and retry'
+ )
+ raise SystemExit(1)
+ finally:
+ self._print_result()
- except exceptions.PoolNotFound:
- self._create_pool(xpool, dry_run)
- except messaging.exceptions.MessagingTimeout:
- LOG.critical(
- 'No response received from designate-central. '
- 'Check it is running, and retry'
- )
- sys.exit(1)
+ def _create_or_update_pool(self, pool_data):
+ try:
+ pool = self._get_pool(pool_data)
+ self._update_pool(pool_data, pool)
- if delete:
- pools = self.central_api.find_pools(self.context)
- pools_in_db = {pool.name for pool in pools}
- pools_in_yaml = {xpool['name'] for xpool in xpools}
+ except exceptions.PoolNotFound:
+ self._create_pool(pool_data)
- pools_to_delete = pools_in_db - pools_in_yaml
+ def _get_pool(self, pool_data):
+ if 'id' in pool_data:
+ pool_id = pool_data['id']
+ if not utils.is_uuid_like(pool_id):
+ self.output_message.append('Not a valid uuid: %s' % pool_id)
+ raise SystemExit(1)
- for pool in pools_to_delete:
- try:
- p = self.central_api.find_pool(
- self.context,
- criterion={'name': pool})
+ pool = self.central_api.get_pool(
+ self.context, pool_id
+ )
+ else:
+ pool = self.central_api.find_pool(
+ self.context, {'name': pool_data['name']}
+ )
- if dry_run:
- self.output_msg.append('Delete Pool: %s' % p)
+ return pool
- else:
- LOG.info('Deleting %s', p)
- self.central_api.delete_pool(self.context, p.id)
+ def _create_pool(self, pool_data):
+ pool = DesignateAdapter.parse('YAML', pool_data, objects.Pool())
+ self._validate_pool(pool)
- except messaging.exceptions.MessagingTimeout:
- LOG.critical(
- 'No response received from designate-central. '
- 'Check it is running, and retry'
- )
- sys.exit(1)
+ if self.dry_run:
+ self.output_message.append('Create Pool: %s' % pool)
+ else:
+ LOG.info('Creating new pool: %s', pool)
+ self.central_api.create_pool(self.context, pool)
+
+ return pool
+
+ def _update_pool(self, pool_data, pool):
+ pool = DesignateAdapter.parse('YAML', pool_data, pool)
+ self._validate_pool(pool)
+
+ if self.dry_run:
+ self.output_message.append('Update Pool: %s' % pool)
+ else:
+ pool = self.central_api.update_pool(self.context, pool)
+ self._update_zones(pool)
+
+ def _delete_pool(self, pool_name):
+ pool = self.central_api.find_pool(
+ self.context, criterion={'name': pool_name}
+ )
- for line in self.output_msg:
- print(line)
+ if self.dry_run:
+ self.output_message.append('Delete Pool: %s' % pool_name)
+ else:
+ LOG.info('Deleting %s', pool_name)
+ self.central_api.delete_pool(self.context, pool.id)
+
+ def _update_zones(self, pool):
+ LOG.info('Updating zone masters for pool: %s', pool.id)
+
+ policy.init()
+ self.context.all_tenants = True
+ zones = self.central_api.find_zones(
+ self.context, criterion={'pool_id': pool.id}
+ )
+
+ for zone in zones:
+ zone.masters = objects.ZoneMasterList().from_list(
+ self._get_masters_from_pool(pool)
+ )
+ self.central_api.update_zone(self.context, zone)
+
+ def _validate_pool(self, pool):
+ for ns_record in pool.ns_records:
+ ns_record.validate()
+
+ if not self.skip_verify_drivers:
+ for target in pool.targets:
+ try:
+ backend_base.Backend.get_driver(target.type)
+ except stevedore.exception.NoMatches:
+ self.output_message.append(
+ 'Unable to find designate backend driver type: '
+ '%s' % target.type
+ )
+ if not self.dry_run:
+ raise SystemExit(1)
+
+ @staticmethod
+ def _get_masters_from_pool(pool):
+ masters = []
+ for target in pool.targets:
+ for master in target.get('masters', []):
+ master = {'host': master['host'], 'port': master['port']}
+ found = False
+ for existing_master in masters:
+ if master == existing_master:
+ found = True
+ if not found:
+ masters.append(master)
+ return masters
+
+ @staticmethod
+ def _load_config(filename):
+ with open(filename, 'r') as stream:
+ return yaml.safe_load(stream)
+
+ @staticmethod
+ def _write_config_to_file(filename, data):
+ with open(filename, 'w') as stream:
+ yaml.dump(data, stream, default_flow_style=False)