def collapse_and_filter_broker_requests(self, broker_requests, allowed_ops, require_vp=None): """Extract allowed ops from broker requests into one collapsed request. :param broker_requests: List of broker requests :type broker_requests: List[ch_ceph.CephBrokerRq] :param allowed_ops: Set of ops to allow :type allowed_ops: Set :param require_vp: Map of required key-value pairs in op :type require_vp: Optional[Dict[str,any]] :returns: Collapsed broker request :rtype: Optional[ch_ceph.CephBrokerRq] """ require_vp = require_vp or {} new_rq = ch_ceph.CephBrokerRq() for rq in broker_requests: assert rq['api-version'] == 1 for op in rq['ops']: if op['op'] in allowed_ops: for k, v in require_vp.items(): if k not in op or op[k] != v: break else: new_rq.add_op(op) if len(new_rq.ops): return new_rq
def configure_pools(): local = reactive.endpoint_from_flag('ceph-local.available') remote = reactive.endpoint_from_flag('ceph-remote.available') with charm.provide_charm_instance() as charm_instance: rq = charm_instance.collapse_and_filter_broker_requests( local.broker_requests, set(('create-pool', )), require_vp={'app-name': 'rbd'}) remote_rq = charm_instance.collapse_and_filter_broker_requests( remote.broker_requests, set(('create-pool', )), require_vp={'app-name': 'rbd'}) pools_in_rq = charm_instance.pools_in_broker_request( rq) if rq else set() pools_in_rq |= charm_instance.pools_in_broker_request( remote_rq) if remote_rq else set() for pool, attrs in charm_instance.eligible_pools(local.pools).items(): pool_mirroring_mode = charm_instance.pool_mirroring_mode( pool, [rq, remote_rq]) mirroring_enabled = charm_instance.mirror_pool_enabled( pool, pool_mirroring_mode) has_peers = charm_instance.mirror_pool_has_peers(pool) if not (mirroring_enabled and has_peers): ch_core.hookenv.log( 'Enabling mirroring for pool "{}"'.format(pool), level=ch_core.hookenv.INFO) charm_instance.mirror_pool_enable(pool, pool_mirroring_mode) if (pool not in pools_in_rq and 'erasure_code_profile' not in attrs['parameters']): # A pool exists that there is no broker request for which means # it is a manually created pool. We will forward creation of # replicated pools but forwarding of manually created Erasure # Coded pools is not supported. pg_num = attrs['parameters'].get('pg_num') max_bytes = attrs['quota'].get('max_bytes') max_objects = attrs['quota'].get('max_objects') size = attrs['parameters'].get('size') ch_core.hookenv.log('Adding manually created pool "{}" to ' 'request.'.format(pool), level=ch_core.hookenv.INFO) if not rq: rq = ch_ceph.CephBrokerRq() rq.add_op_create_replicated_pool( pool, replica_count=size if not size else int(size), pg_num=pg_num if not pg_num else int(pg_num), app_name='rbd', max_bytes=max_bytes if not max_bytes else int(max_bytes), max_objects=max_objects if not max_objects else int(max_objects), ) ch_core.hookenv.log('Request for evaluation: "{}"'.format(rq), level=ch_core.hookenv.DEBUG) if rq: remote.maybe_send_rq(rq)
def get_existing_request(self): logging.info("get_existing_request") # json.dumps of the CephBrokerRq() rq = ch_ceph.CephBrokerRq() if self.state.broker_req: try: j = json.loads(self.state.broker_req) logging.info("Json request: {}".format(self.state.broker_req)) rq.set_ops(j['ops']) except ValueError as err: logging.info("Unable to decode broker_req: {}. Error {}" "".format(self.state.broker_req, err)) return rq
def get_current_request(self): """ Retrieve the current Ceph broker request. If no request has been created yet then create a new one. """ json_rq = self.all_joined_units.received['broker_req'] current_request = ch_ceph.CephBrokerRq() if json_rq: try: j = json.loads(json_rq) current_request.set_ops(j['ops']) except (KeyError, json.decoder.JSONDecodeError): raise return current_request
def get_previous_request(self, relation): """Get the previous request. :param relation: Relation to check for existing request. :type relation: ops.model.Relation, :returns: The previous ceph request. :rtype: ch_ceph.CephBrokerRq """ request = None broker_req = relation.data[self.this_unit].get('broker_req') if broker_req: request_data = json.loads(broker_req) request = ch_ceph.CephBrokerRq( api_version=request_data['api-version'], request_id=request_data['request-id']) request.set_ops(request_data['ops']) return request
def test_ceph_broker_rq_class(self): rq = ceph_utils.CephBrokerRq() rq.add_op_create_pool('pool1', replica_count=1) rq.add_op_create_pool('pool2') expected = json.dumps({ 'api-version': 1, 'ops': [{ 'op': 'create-pool', 'name': 'pool1', 'replicas': 1 }, { 'op': 'create-pool', 'name': 'pool2', 'replicas': 3 }] }) self.assertEqual(rq.request, expected)
def create_replicated_pool(self, name, replicas=3, weight=None, pg_num=None, group=None, namespace=None, app_name=None, max_bytes=None, max_objects=None): """Request replicated pool setup. Refer to charm-helpers ``add_op_create_replicated_pool`` function for documentation of parameters. """ # Ensure type of numeric values before sending over the wire replicas = int(replicas) if replicas else None weight = float(weight) if weight else None pg_num = int(pg_num) if pg_num else None max_bytes = int(max_bytes) if max_bytes else None max_objects = int(max_objects) if max_objects else None for relation in self.relations: current_request = ch_ceph.get_previous_request( relation.relation_id) or ch_ceph.CephBrokerRq() for req in current_request.ops: if 'op' in req and 'name' in req: if req['op'] == 'create-pool' and req['name'] == name: # request already exists, don't create a new one return current_request.add_op_create_replicated_pool( name="{}".format(name), replica_count=replicas, pg_num=pg_num, weight=weight, group=group, namespace=namespace, app_name=app_name, max_bytes=max_bytes, max_objects=max_objects) ch_ceph.send_request_if_needed(current_request, relation=self.endpoint_name)
if hookenv.config('autotune'): ceph.utils.tune_dev(dev) mounts = filter(lambda disk: device_path in disk.device, psutil.disk_partitions()) for osd in mounts: osd_id = osd.mountpoint.split('/')[-1].split('-')[-1] request.ops.append({ 'op': 'move-osd-to-bucket', 'osd': "osd.{}".format(osd_id), 'bucket': bucket}) return request def get_devices(): devices = [] for path in hookenv.action_get('osd-devices').split(' '): path = path.strip() if os.path.isabs(path): devices.append(path) return devices if __name__ == "__main__": request = ch_ceph.CephBrokerRq() for dev in get_devices(): request = add_device(request=request, device_path=dev, bucket=hookenv.action_get("bucket")) ch_ceph.send_request_if_needed(request, relation='mon')