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
Example #2
0
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
Example #6
0
 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)
Example #8
0
    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')