示例#1
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
示例#2
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
示例#3
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))
示例#4
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
示例#5
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
示例#6
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])))
示例#7
0
    def from_resource_group(cls, linstor_controllers, resource_group_name,
                            resource_name, vlm_sizes):
        """
        Spawns a new resource definition from the given resource group.

        :param str linstor_controllers: string of possible linstor controllers, feeded to .controller_uri_list
        :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']
        :return: Resource object of the newly created resource definition
        :rtype: Resource
        """
        with linstor.MultiLinstor(
                linstor.MultiLinstor.controller_uri_list(
                    linstor_controllers)) as lin:
            result = lin.resource_group_spawn(resource_group_name,
                                              resource_name, vlm_sizes)
            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,
                            result[0].message))

            return Resource(resource_name, uri=linstor_controllers)
        return None
示例#8
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
示例#9
0
 def _set_linstor_kv(self, k, v):
     if not self._rw_to_linstor:
         return
     with linstor.MultiLinstor(self.client.uri_list,
                               self.client.timeout,
                               self.client.keep_alive) as lin:
         rs = lin.keyvaluestore_modify(self._name, property_dict={k: v}, delete_props=None)
         if not rs[0].is_success():
             raise linstor.LinstorError('Could not set kv({}:{}): {}'.format(k, v, rs[0]))
示例#10
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, rs[0]))
示例#11
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, rs[0]))
示例#12
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
示例#13
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, 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()
示例#14
0
    def _del_linstor_kv(self, k, is_list_like=False):
        if not self._rw_to_linstor:
            return

        if is_list_like:
            delete_props = list(k)  # allows e.g., tuples
        else:
            delete_props = [k]
        with linstor.MultiLinstor(self.client.uri_list,
                                  self.client.timeout,
                                  self.client.keep_alive) as lin:
            rs = lin.keyvaluestore_modify(self._name, property_dict=None, delete_props=delete_props)
            if not rs[0].is_success():
                raise linstor.LinstorError('Could not delete kv({}): {}'.format(k, rs[0]))
示例#15
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=rs[0]))
             self.volumes[k]._rsc_name = self._linstor_name
示例#16
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)
        ])
        rsc_create_reply = rsc_create_replies[0]
        if rsc_create_reply.is_success() or rsc_create_reply.is_error(
                code=FAIL_EXISTS_RSC):
            return True

        raise linstor.LinstorError(
            'Could not activate resource {} on node {}: {}'.format(
                self, node_name, rsc_create_reply))
示例#17
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
示例#18
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()
示例#19
0
    def _set_nr_volumes(self, nr_volumes):
        have = self._nr_volumes
        want = nr_volumes
        if have == want:
            return True

        if want < 1:
            raise linstor.LinstorError(
                "A resource group needs at least one volume group")

        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            # inc/dec per interation to keep correct count if we fail in the middle
            if have < want:  # increase
                for v in range(have, want):
                    lin.volume_group_create(self._name, volume_nr=v)
                    self._nr_volumes += 1
            elif have > want:  # decrease
                for v in range(have, want, -1):
                    lin.volume_group_delete(self._name, v - 1)
                    self._nr_volumes -= 1
            # else ==, done

        return True