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
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
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
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)
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)
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
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]))
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)
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()
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()
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))
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
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]))
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()
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]))
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
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
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()
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
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
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