Example #1
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
Example #2
0
    def clone(self, clone_name, clone_external_name=None, timeout=None):
        """
        Starts a clone operation on the current resource to the given clone_name.

        :param str clone_name: Clone name
        :param Optional[str] clone_external_name: Clone external name
        :param Optional[int] timeout: How long to wait for the clone to finish (secs)
        :return: A new resource object with the cloned resource
        :rtype: linstor.resource.Resource
        :raise LinstorError: On errors
        """
        if self._linstor_name is None:
            raise linstor.LinstorError(
                "Resource '{n}' doesn't exist.".format(n=self.name))

        with self._get_connection() as lin:
            c_started = lin.resource_dfn_clone(self._linstor_name, clone_name,
                                               clone_external_name)

            if not Linstor.all_api_responses_no_error(c_started.messages):
                raise linstor.LinstorError(
                    "Could not clone resource definition '{r}': {err}".format(
                        r=self._linstor_name,
                        err=Linstor.filter_api_call_response_errors(
                            c_started.messages)[0].message))

            lin.resource_dfn_clone_wait_complete(c_started.source_name,
                                                 c_started.clone_name,
                                                 timeout=timeout)

            return Resource(c_started.clone_name,
                            ",".join(self.client.uri_list),
                            existing_client=self._existing_client)
Example #3
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
Example #4
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]))
Example #5
0
 def _delete(self):
     if self._rsc_name is None:  # this volume was created, but never deployed, no linstor action.
         return
     with self._client_ref 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]))
Example #6
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 self._get_connection() 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
Example #7
0
    def from_resource_group(cls,
                            uri,
                            resource_group_name,
                            resource_name,
                            vlm_sizes,
                            timeout=300,
                            keep_alive=False,
                            definitions_only=False,
                            existing_client=None,
                            agent_info=""):
        """
        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
        :param linstor.Linstor existing_client: Client to associate with the resource
        :param str agent_info: Info string added to user-agent
        :return: linstor.resource.Resource object of the newly created resource definition
        :rtype: linstor.resource.Resource
        """
        if existing_client:
            client = existing_client
        else:
            c = _Client(uri)
            client = linstor.MultiLinstor(c.uri_list, timeout, keep_alive,
                                          agent_info)

        with client 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,
                            existing_client=existing_client)
        return None
Example #8
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()
Example #9
0
    def _create_or_toggle(self, node_name, diskless):
        """

        :param str node_name:
        :param bool diskless:
        :return: True if it was successful
        :rtype: bool
        """
        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
Example #10
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 self._get_connection() 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
Example #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: linstor.resource.Resource
        """
        if self._linstor_name is None:
            raise linstor.LinstorError(
                "Resource '{n}' doesn't exist.".format(n=self.name))

        with self._get_connection() 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),
                        existing_client=self._existing_client)
Example #12
0
    def activate(self, node_name, diskful=False):
        """
        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
        :param bool diskful: Make the resource diskful on the node
        :return: True if success, else raises LinstorError
        """
        rsc_available_replies = self._lin.resource_make_available(
            node_name, self._linstor_name, diskful)

        if not Linstor.all_api_responses_no_error(rsc_available_replies):
            raise linstor.LinstorError(
                'Could not make resource {} available on node {}: {}'.format(
                    self, node_name,
                    ";".join([str(x) for x in rsc_available_replies])))
        return True
Example #13
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
Example #14
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 self._client_ref 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
Example #15
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()