Beispiel #1
0
    def activate(self, node_name):
        """
        Makes a resource available at a given host.

        If the host already contains a diskful assignment, this is a NOOP. Otherwise a diskless assignment is
        created.

        :param str node_name: Name of the node
        :return: True if success, else raises LinstorError
        """
        rsc_create_replies = self._lin.resource_create([
            linstor.ResourceData(node_name, self._linstor_name, diskless=True)
        ])

        if Linstor.all_api_responses_no_error(rsc_create_replies):
            return True
        else:
            error_replies = Linstor.filter_api_call_response_errors(
                rsc_create_replies)
            if len(error_replies) == 1 and error_replies[0].is_error(
                    code=FAIL_EXISTS_RSC):
                return True

        raise linstor.LinstorError(
            'Could not activate resource {} on node {}: {}'.format(
                self, node_name,
                ";".join([str(x) for x in rsc_create_replies])))
Beispiel #2
0
    def snapshot_rollback(self, name):
        """
        Rolls resource data back to snapshot state. The resource must not be in use.
        The snapshot will not be removed and can be used for subsequent rollbacks.
        Only the most recent snapshot may be used; to roll back to an earlier
        snapshot, the intermediate snapshots must first be deleted.

        :param str name: Name of the snapshot
        :return: True if success, else raises LinstorError
        """
        if self._linstor_name is None:
            raise linstor.LinstorError(
                "Resource '{n}' doesn't exist.".format(n=self.name))

        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            rs = lin.snapshot_rollback(rsc_name=self._linstor_name,
                                       snapshot_name=name)
            if not Linstor.all_api_responses_no_error(rs):
                raise linstor.LinstorError(
                    'Could not rollback to snapshot {}: {}'.format(
                        name,
                        Linstor.filter_api_call_response_errors(rs)
                        [0].message))
        return True
Beispiel #3
0
    def _create_or_toggle(self, node_name, diskless):
        is_assigned = self.is_assigned(node_name)
        is_diskless = self.is_diskless(node_name)
        sp = self.placement.diskless_storage_pool
        if is_diskless or (not is_assigned and not diskless):
            sp = self.placement.storage_pool

        if not is_assigned:
            rs = self._lin.resource_create([
                linstor.ResourceData(node_name,
                                     self._linstor_name,
                                     diskless=diskless,
                                     storage_pool=sp)
            ])
            if not Linstor.all_api_responses_no_error(rs):
                raise linstor.LinstorError(
                    'Could not create resource {} on node {} as diskless={}: {}'
                    .format(self, node_name, diskless,
                            Linstor.filter_api_call_response_errors(rs)[0]))
        elif is_diskless != diskless:
            rs = self._lin.resource_toggle_disk(node_name,
                                                self._linstor_name,
                                                diskless=diskless,
                                                storage_pool=sp)
            if not Linstor.all_api_responses_no_error(rs):
                raise linstor.LinstorError(
                    'Could not toggle disk for resource {} on node {} to diskless={}: {}'
                    .format(self, node_name, diskless,
                            Linstor.filter_api_call_response_errors(rs)[0]))
        return True
Beispiel #4
0
    def autoplace(self):
        """
        Automatically place the Resource according to values set in the placement policy.

        Example:
            To autoplace a Resource 'foo' 3 times redundant on the storage pool 'drbdpool' one would::

                $ foo.placement.redundancy = 3
                $ foo.placement.storage_pool = 'drbdpool'
                $ foo.autoplace()

        :return: True if success, else raises LinstorError
        """
        rs = self._lin.resource_auto_place(
            self._linstor_name,
            self.placement.redundancy,
            self.placement.storage_pool,
            do_not_place_with=None,
            do_not_place_with_regex=None,
            replicas_on_same=None,
            replicas_on_different=None,
            diskless_on_remaining=self.placement.diskless_on_remaining)

        if not Linstor.all_api_responses_no_error(rs):
            raise linstor.LinstorError(
                'Could not autoplace resource {}: {}'.format(
                    self,
                    Linstor.filter_api_call_response_errors(rs)[0]))
        return True
Beispiel #5
0
    def drbd_proxy_disable(self, node_name_a, node_name_b):
        if self._linstor_name is None:
            raise linstor.LinstorError(
                "Resource '{n}' doesn't exist.".format(n=self.name))

        proxy_disable_replies = self._lin.drbd_proxy_disable(
            self._linstor_name, node_name_a, node_name_b)
        if not Linstor.all_api_responses_no_error(proxy_disable_replies):
            raise linstor.LinstorError(
                'Could not disable drbd-proxy for resource {} between {} and {}: {}'
                .format(
                    self, node_name_a, node_name_b,
                    Linstor.filter_api_call_response_errors(
                        proxy_disable_replies)))
        return True
Beispiel #6
0
    def size(self, size):  # this has to be an int, otherwise python complains
        size = self._size_to_bytes(size)
        if self._size is not None \
           and self._rsc_name is not None \
           and self._volume_id is not None:
            r, v = self._rsc_name, self._volume_id
            if self._size > size:
                raise ValueError(
                    'shrinking Resource/Volume {}/{} from {} to {} is not allowed'
                    .format(r, v, self._size, size))

            size_kib = linstor.SizeCalc.convert_round_up(
                size, linstor.SizeCalc.UNIT_B, linstor.SizeCalc.UNIT_KiB)
            with linstor.MultiLinstor(self._client_ref.uri_list,
                                      self._client_ref.timeout,
                                      self._client_ref.keep_alive) as lin:
                rs = lin.volume_dfn_modify(r, v, size=size_kib)
                if not linstor.Linstor.all_api_responses_no_error(rs):
                    raise linstor.LinstorError(
                        'Could not resize Resource/Volume {}/{}: {}'.format(
                            r, v,
                            Linstor.filter_api_call_response_errors(rs)[0]))

        # if we are here everything is fine
        self._size = size
Beispiel #7
0
 def _set_properties(self):
     dp = 'yes' if self._allow_two_primaries else 'no'
     props = {'DrbdOptions/Net/allow-two-primaries': dp}
     rs = self._lin.resource_dfn_modify(self._linstor_name,
                                        props,
                                        delete_props=None)
     if not linstor.Linstor.all_api_responses_no_error(rs):
         raise linstor.LinstorError(
             'Could not set DRBD properties for resource {}: {}'.format(
                 self,
                 Linstor.filter_api_call_response_errors(rs)[0]))
Beispiel #8
0
    def snapshot_delete(self, name):
        """
        Deletes a given snapshot of this resource.

        :param str name: Name of the snapshot
        :return: True if success, else raises LinstorError
        """
        if self._linstor_name is None:
            raise linstor.LinstorError(
                "Resource '{n}' doesn't exist.".format(n=self.name))

        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            rs = lin.snapshot_delete(rsc_name=self._linstor_name,
                                     snapshot_name=name)
            if not Linstor.all_api_responses_no_error(rs):
                raise linstor.LinstorError(
                    'Could not delete snapshot {}: {}'.format(
                        name,
                        Linstor.filter_api_call_response_errors(rs)
                        [0].message))
        return True
Beispiel #9
0
 def _delete(self):
     if self._rsc_name is None:  # this volume was created, but never deployed, no linstor action.
         return
     with linstor.MultiLinstor(self._client_ref.uri_list,
                               self._client_ref.timeout,
                               self._client_ref.keep_alive) as lin:
         r, v = self._rsc_name, self._volume_id
         rs = lin.volume_dfn_delete(r, v)
         if not linstor.Linstor.all_api_responses_no_error(rs):
             raise linstor.LinstorError(
                 'Could not delete Resource/Volume {}/{}: {}'.format(
                     r, v,
                     Linstor.filter_api_call_response_errors(rs)[0]))
Beispiel #10
0
    def _delete(self, node_name=None):
        reinit = False
        if node_name is None:
            node_name = 'ALL'  # for error msg
            rs = self._lin.resource_dfn_delete(self._linstor_name)
            reinit = True
            self.defined = False
        else:
            if not self.is_assigned(node_name):
                return True
            rs = self._lin.resource_delete(node_name, self._linstor_name)
            if socket.gethostname() == node_name:  # deleted on myself
                reinit = True

        if not Linstor.all_api_responses_no_error(rs):
            raise linstor.LinstorError(
                'Could not delete resource {} on node {}: {}'.format(
                    self, node_name,
                    Linstor.filter_api_call_response_errors(rs)[0]))
        if reinit:
            self._volumes = _VolumeDict()

        return self.__update_volumes()
Beispiel #11
0
    def restore_from_snapshot(self, snapshot_name, resource_name_to):
        """
        Restores a new resource from a snapshot.

        :param snapshot_name: Snapshot name to use for restoration.
        :param resource_name_to: Name of the new resource.
        :return: A new resource object restored from the snapshot.
        :rtype: Resource
        """
        if self._linstor_name is None:
            raise linstor.LinstorError(
                "Resource '{n}' doesn't exist.".format(n=self.name))

        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            rs = lin.resource_dfn_create(
                resource_name_to, resource_group=self.resource_group_name)
            if not Linstor.all_api_responses_no_error(rs):
                raise linstor.LinstorError(
                    "Could not resource definition '{r}' for snapshot restore: {err}"
                    .format(r=resource_name_to,
                            err=Linstor.filter_api_call_response_errors(rs)
                            [0].message))

            rs = lin.snapshot_volume_definition_restore(
                from_resource=self._linstor_name,
                from_snapshot=snapshot_name,
                to_resource=resource_name_to)

            if not Linstor.all_api_responses_no_error(rs):
                raise linstor.LinstorError(
                    "Could not restore volume definition '{rd}' from snapshot {sn} to resource definition '{tr}': {err}"
                    .format(rd=self._linstor_name,
                            sn=snapshot_name,
                            tr=resource_name_to,
                            err=Linstor.filter_api_call_response_errors(rs)
                            [0].message))

            rs = lin.snapshot_resource_restore(
                node_names=[],  # to all
                from_resource=self._linstor_name,
                from_snapshot=snapshot_name,
                to_resource=resource_name_to)

            if not Linstor.all_api_responses_no_error(rs):
                raise linstor.LinstorError(
                    "Could not restore resource '{rd}' from snapshot {sn} to resource definition '{tr}': {err}"
                    .format(rd=self.name,
                            sn=snapshot_name,
                            tr=resource_name_to,
                            err=Linstor.filter_api_call_response_errors(rs)
                            [0].message))

        return Resource(resource_name_to, ",".join(self.client.uri_list))
Beispiel #12
0
 def _create_volume_definitions(self):
     for k, v in self.volumes.items():
         if v._rsc_name is None:
             size_kib = linstor.SizeCalc.convert_round_up(
                 v.size, linstor.SizeCalc.UNIT_B, linstor.SizeCalc.UNIT_KiB)
             rs = self._lin.volume_dfn_create(
                 self._linstor_name,
                 size_kib,
                 k,
                 v._minor,
                 encrypt=False,
                 storage_pool=self.placement.storage_pool)
             if not linstor.Linstor.all_api_responses_no_error(rs):
                 raise linstor.LinstorError(
                     'Could not create volume definition {n}/{k}: {e}'.
                     format(
                         n=self,
                         k=k,
                         e=Linstor.filter_api_call_response_errors(rs)[0]))
             self.volumes[k]._rsc_name = self._linstor_name
Beispiel #13
0
    def from_resource_group(cls,
                            uri,
                            resource_group_name,
                            resource_name,
                            vlm_sizes,
                            timeout=300,
                            keep_alive=False,
                            definitions_only=False):
        """
        Spawns a new resource definition from the given resource group.

        :param str uri: A list of controller addresses.
         e.g: ``linstor://localhost,10.0.0.2``, ``linstor+ssl://localhost,linstor://192.168.0.1``
        :param str resource_group_name: Name of the resource group
        :param str resource_name: Name of the new resource definition
        :param list[str] vlm_sizes: String list of volume sizes e.g. ['128Mib', '1G']
        :param int timeout: client library timeout
        :param bool keep_alive: keep client connection alive
        :param bool definitions_only: only spawn definitions
        :return: Resource object of the newly created resource definition
        :rtype: Resource
        """
        c = _Client(uri)
        with linstor.MultiLinstor(c.uri_list, timeout, keep_alive) as lin:
            result = lin.resource_group_spawn(
                resource_group_name,
                resource_name,
                vlm_sizes,
                definitions_only=definitions_only)
            if not linstor.Linstor.all_api_responses_no_error(result):
                raise linstor.LinstorError(
                    'Could not spawn resource "{}" from resource group "{}": {}'
                    .format(
                        resource_name, resource_group_name,
                        Linstor.filter_api_call_response_errors(result)
                        [0].message))

            return Resource(resource_name, uri=uri)
        return None
Beispiel #14
0
    def _maybe_create_rd_and_vd(self):
        # resource definition
        if not self.defined:
            rs = self._lin.resource_dfn_create("",
                                               self._port,
                                               external_name=self._name)
            if not linstor.Linstor.all_api_responses_no_error(rs):
                raise linstor.LinstorError(
                    'Could not create resource definition {}: {}'.format(
                        self,
                        Linstor.filter_api_call_response_errors(rs)[0]))
            ors = rs[0].object_refs
            try:
                self._linstor_name = ors['RscDfn']
            except KeyError:
                raise linstor.LinstorError(
                    'Could not get RscDfn for resource definition {}'.format(
                        self))

            self.defined = True
            self._set_properties()

        # volume definitions
        self._create_volume_definitions()