예제 #1
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
예제 #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
예제 #3
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
예제 #4
0
 def query_max_volume_size(self):
     """
     Queries maximum volume size from the given resource group and returns all possible candidates
     """
     with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                               self.client.keep_alive) as lin:
         return lin.resource_group_qmvs(self._name)
예제 #5
0
    def delete(self, node_name=None, snapshots=True):
        """
        Deletes the resource globally or on the given host.

        If the node name is None, deletes the resource globally.

        :param str node_name: Deletes resource only from the specified node.
        :param bool snapshots: If True deletes snapshots prior deleting the resource

        :return: True if success, else raises LinstorError
        """
        if self._linstor_name is None:
            return True  # resource doesn't exist

        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            self._lin = lin

            if snapshots and node_name is None:  # only remove snapshots if resource definition will be deleted
                snapshot_list = lin.snapshot_dfn_list()[
                    0]  # type: linstor.responses.SnapshotResponse
                for snap in [
                        x for x in snapshot_list.snapshots
                        if x.rsc_name.lower() == self._linstor_name.lower()
                ]:
                    lin.snapshot_delete(rsc_name=self._linstor_name,
                                        snapshot_name=snap.snapshot_name)

            return self._delete(node_name)
예제 #6
0
 def delete(self):
     """
     Deletes the ResourceGroup
     """
     with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                               self.client.keep_alive) as lin:
         lin.resource_group_delete(self._name)
     return True
예제 #7
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]))
예제 #8
0
    def _import(self):
        d = {}
        if self._rw_to_linstor:
            with linstor.MultiLinstor(self.client.uri_list,
                                      self.client.timeout,
                                      self.client.keep_alive) as lin:
                d = {'/'+k: v for k, v in lin.keyvaluestore_list(self._name).properties.items()}

        super(KV, self).clear()
        super(KV, self).update(d)
예제 #9
0
    def _update_or_create(self):
        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            rgs = lin.resource_group_list_raise(
                filter_by_resource_groups=[self._name]).resource_groups
            if len(rgs) == 0:  # does not exist yet
                self._modify_or_create("create")
                self._set_nr_volumes(self._nr_volumes_default)

        return self._update()
예제 #10
0
    def allow_two_primaries(self, value):
        if self._allow_two_primaries == value:
            return

        self._allow_two_primaries = value
        if self.defined:
            with linstor.MultiLinstor(self.client.uri_list,
                                      self.client.timeout,
                                      self.client.keep_alive) as lin:
                self._lin = lin
                self._set_properties()
예제 #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))
예제 #12
0
 def wrapper(self, *args, **kwargs):
     ret = None
     with linstor.MultiLinstor(self.client.uri_list,
                               self.client.timeout,
                               self.client.keep_alive) as lin:
         self._lin = lin
         self._maybe_create_rd_and_vd()
         ret = f(self, *args, **kwargs)
         self.__update_volumes()
     self._lin = None
     return ret
예제 #13
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]))
예제 #14
0
    def is_thin(self):
        """
        Returns if the used storage pool of the resource is thin.

        :return: True if storage pool used is thin.
        :rtype: bool
        """
        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            stor_pool_list = lin.storage_pool_list_raise(
                None, filter_by_stor_pools=[self.volumes[0].storage_pool_name])
            return stor_pool_list.storage_pools[0].is_thin()
예제 #15
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]))
예제 #16
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
예제 #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 __init__(self, name, uri='linstor://localhost'):
        # external properties
        self._name = name  # the user facing name, what linstor calls the "external name"
        self._port = None
        self._resource_group_name = None  # type: Optional[str]
        self.client = _Client(uri)
        self.placement = _Placement()
        self.volumes = _VolumeDict()  # type: dict[int, Volume]
        self.defined = False

        # THINK(rck): maybe a dict, KISS for now
        self._allow_two_primaries = False

        # internal
        self._lin = None  # used to pass in an existing client (e.g,, _update_volumes)
        self._assignments = {}
        self._linstor_name = None

        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            self._lin = lin
            self.__update_volumes()
예제 #19
0
    def _modify_or_create(self, what="modify"):
        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            fn = None
            if what == "create":
                fn = lin.resource_group_create
            elif what == "modify":
                fn = lin.resource_group_modify

            fn(self._name,
               description=self._description,
               place_count=self._redundancy,
               storage_pool=self._storage_pool,
               do_not_place_with=self._do_not_place_with,
               do_not_place_with_regex=self._do_not_place_with_regex,
               replicas_on_same=self._replicas_on_same,
               replicas_on_different=self._replicas_on_different,
               diskless_on_remaining=self._diskless_on_remaining,
               layer_list=self._layer_list,
               provider_list=self._provider_list,
               property_dict=self._property_dict)

        return True
예제 #20
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
예제 #21
0
    def _update(self):
        with linstor.MultiLinstor(self.client.uri_list, self.client.timeout,
                                  self.client.keep_alive) as lin:
            rgs = lin.resource_group_list_raise(
                filter_by_resource_groups=[self._name]).resource_groups
            rg = rgs[0]
            self._name = rg.name
            self._description = rg.description
            sf = rg.select_filter
            self._redundancy = sf.place_count
            self._storage_pool = sf.storage_pool
            self._do_not_place_with = sf.not_place_with_rsc
            self._do_not_place_with_regex = sf.not_place_with_rsc_regex
            self._replicas_on_same = sf.replicas_on_same
            self._replicas_on_different = sf.replicas_on_different
            self._diskless_on_remaining = sf.diskless_on_remaining
            self._layer_list = sf.layer_stack
            self._provider_list = sf.provider_list
            self._property_dict = rg.properties

            self._nr_volumes = len(
                lin.volume_group_list_raise(self._name).volume_groups)

        return True