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