def show(self, full_project_name, name): """Retrieves volume details based on volume name. :param full_project_name: project path of the volume :param name: name of the volume. If the volume is under a project, then full XPath needs to be specified. Example: If VOL1 is a volume under project PROJ1, then the name of volume is PROJ1/VOL1 :returns: Volume details in JSON response payload """ if common.is_uri(name): return name if full_project_name is None: raise common.CoprHdError( common.CoprHdError.NOT_FOUND_ERR, (_("Volume %s : not found") % six.text_type(name))) uris = self.search_volumes(full_project_name) for uri in uris: volume = self.show_by_uri(uri) if volume and 'name' in volume and volume['name'] == name: return volume raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("Volume" " %s : not found") % six.text_type(name)))
def _get_resource_lun_tuple(self, resources, resType, baseResUri, tenantname, projectname, blockTypeName): """Function to validate input volumes and return list of ids and luns. """ copyEntries = [] volumeObject = volume.Volume(self.ipaddr, self.port) for copy in resources: copyParam = [] try: copyParam = copy.split(":") except Exception: raise common.CoprHdError( common.CoprHdError.CMD_LINE_ERR, (_("Please provide valid format volume:" " lun for parameter %s") % resType)) copy = dict() if not len(copyParam): raise common.CoprHdError( common.CoprHdError.CMD_LINE_ERR, (_("Please provide at least one volume for parameter %s") % resType)) if resType == "volumes": full_project_name = tenantname + "/" + projectname copy['id'] = volumeObject.volume_query(full_project_name, copyParam[0]) if len(copyParam) > 1: copy['lun'] = copyParam[1] copyEntries.append(copy) return copyEntries
def exportgroup_query(self, name, project, tenant, varrayuri=None): """Makes REST API call to query the exportgroup by name. :param name: Name/id of the export group :param project: Name of the project :param tenant: Name of the tenant :param varrayuri: URI of the virtual array :returns: id of the export group """ if common.is_uri(name): return name uris = self.exportgroup_list(project, tenant) for uri in uris: exportgroup = self.exportgroup_show(uri, project, tenant) if exportgroup and exportgroup['name'] == name: if varrayuri: varrayobj = exportgroup['varray'] if varrayobj['id'] == varrayuri: return exportgroup['id'] else: continue else: return exportgroup['id'] raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("Export Group %s: not found") % name))
def tenant_query(self, label): """Returns the UID of the tenant specified by the hierarchical name. (ex tenant1/tenant2/tenant3) """ if common.is_uri(label): return label tenant_id = self.tenant_getid() if not label: return tenant_id subtenants = self.tenant_list(tenant_id) subtenants.append(self.tenant_show(None)) for tenant in subtenants: if tenant['name'] == label: rslt = self.tenant_show_by_uri(tenant['id']) if rslt: return tenant['id'] raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("Tenant %s: not found") % label))
def expand(self, full_project_name, volume_name, new_size, sync=False, synctimeout=0): volume_detail = self.show(full_project_name, volume_name) from decimal import Decimal new_size_in_gb = Decimal(Decimal(new_size) / (units.Gi)) current_size = Decimal(volume_detail["provisioned_capacity_gb"]) if new_size_in_gb <= current_size: raise common.CoprHdError( common.CoprHdError.VALUE_ERR, (_("error: Incorrect value of new size: %(new_size_in_gb)s" " GB\nNew size must be greater than current size: " "%(current_size)s GB") % { 'new_size_in_gb': new_size_in_gb, 'current_size': current_size })) body = oslo_serialization.jsonutils.dumps({"new_size": new_size}) (s, h) = common.service_json_request( self.ipaddr, self.port, "POST", Volume.URI_EXPAND.format(volume_detail["id"]), body) if not s: return None o = common.json_decode(s) if sync: return self.check_for_sync(o, sync, synctimeout) return o
def exportgroup_create(self, name, project_name, tenant, varray, exportgrouptype, export_destination=None): """This function creates the Export group with given name. :param name: Name of the export group :param project_name: Name of the project path :param tenant: Container tenant name :param varray: Name of the virtual array :param exportgrouptype: Type of the export group. Ex:Host etc :returns: status of creation """ # check for existence of export group. try: status = self.exportgroup_show(name, project_name, tenant) except common.CoprHdError as e: if e.err_code == common.CoprHdError.NOT_FOUND_ERR: if tenant is None: tenant = "" fullproj = tenant + "/" + project_name projObject = project.Project(self.ipaddr, self.port) projuri = projObject.project_query(fullproj) varrayObject = virtualarray.VirtualArray( self.ipaddr, self.port) nhuri = varrayObject.varray_query(varray) parms = { 'name': name, 'project': projuri, 'varray': nhuri, 'type': exportgrouptype } if exportgrouptype and export_destination: host_obj = host.Host(self.ipaddr, self.port) host_uri = host_obj.query_by_name(export_destination) parms['hosts'] = [host_uri] body = oslo_serialization.jsonutils.dumps(parms) (s, h) = common.service_json_request(self.ipaddr, self.port, "POST", self.URI_EXPORT_GROUP, body) o = common.json_decode(s) return o else: raise if status: raise common.CoprHdError( common.CoprHdError.ENTRY_ALREADY_EXISTS_ERR, (_("Export group with name %s" " already exists") % name))
def vpool_query(self, name, vpooltype): """Makes REST API call to query the vpool by name and type. This function will take the VPOOL name and type of VPOOL as input and get uri of the first occurrence of given VPOOL. :param name: Name of the VPOOL :param vpooltype: Type of the VPOOL {'block'} :returns: uri of the given vpool """ if common.is_uri(name): return name (s, h) = common.service_json_request( self.ipaddr, self.port, "GET", self.URI_VPOOL_SEARCH.format(vpooltype, name), None) o = common.json_decode(s) if len(o['resource']) > 0: # Get the Active vpool ID. for vpool in o['resource']: if self.vpool_show_uri(vpooltype, vpool['id']) is not None: return vpool['id'] # Raise not found exception. as we did not find any active vpool. raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("VPool %(name)s ( %(vpooltype)s ) :" " not found") % {'name': name, 'vpooltype': vpooltype }))
def check_for_sync(self, result, sync, synctimeout=0): if len(result["resource"]) > 0: resource = result["resource"] return (common.block_until_complete("consistencygroup", resource["id"], result["id"], self.ipaddr, self.port, synctimeout)) else: raise common.CoprHdError( common.CoprHdError.SOS_FAILURE_ERR, _("error: task list is empty, no task response found"))
def volume_query(self, full_project_name, volume_name): """Makes REST API call to query the volume by name. :param volume_name: name of volume :param full_project_name: Full project path :returns: Volume details in JSON response payload """ if common.is_uri(volume_name): return volume_name if not full_project_name: raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, _("Project name not specified")) uris = self.search_volumes(full_project_name) for uri in uris: volume = self.show_by_uri(uri) if volume and 'name' in volume and volume['name'] == volume_name: return volume['id'] raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("Volume" "%s: not found") % volume_name))
def get_tenant_by_name(self, tenant): uri = None if not tenant: uri = self.tenant_getid() else: if not common.is_uri(tenant): uri = self.tenant_query(tenant) else: uri = tenant if not uri: raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("Tenant %s: not found") % tenant)) return uri
def list_tags(self, resource_uri): if resource_uri.__contains__("tag") is False: raise common.CoprHdError(common.CoprHdError.VALUE_ERR, _("URI should end with /tag")) (s, h) = common.service_json_request(self.ipaddr, self.port, "GET", resource_uri, None) allTags = [] o = common.json_decode(s) allTags = o['tag'] return allTags
def varray_query(self, name): """Returns the UID of the varray specified by the name.""" if common.is_uri(name): return name uris = self.varray_list() for uri in uris: varray = self.varray_show(uri) if varray and varray['name'] == name: return varray['id'] raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("varray %s: not found") % name))
def snapshot_query(self, storageres_type, storageres_typename, resuri, snapshot_name): if resuri is not None: uris = self.snapshot_list_uri(storageres_type, storageres_typename, resuri) for uri in uris: snapshot = self.snapshot_show_uri(storageres_type, resuri, uri['id']) if (False == common.get_node_value(snapshot, 'inactive') and snapshot['name'] == snapshot_name): return snapshot['id'] raise common.CoprHdError(common.CoprHdError.SOS_FAILURE_ERR, (_("snapshot with the name: " "%s Not Found") % snapshot_name))
def query_by_name(self, host_name, tenant_name=None): """Search host matching host_name and tenant if tenant_name provided. tenant_name is optional """ hostList = self.list_all(tenant_name) for host in hostList: hostUri = host['id'] hostDetails = self.show_by_uri(hostUri) if hostDetails: if hostDetails['name'] == host_name: return hostUri raise common.CoprHdError( common.CoprHdError.NOT_FOUND_ERR, (_("Host with name: %s not found") % host_name))
def consistencygroup_query(self, name, project, tenant): """This function will return consistency group id. :param name : Name/id of the consistency group :param project: Name of the project :param tenant: Name of the tenant :returns: id of the consistency group """ if common.is_uri(name): return name uris = self.list(project, tenant) for uri in uris: congroup = self.show(uri, project, tenant) if congroup and congroup['name'] == name: return congroup['id'] raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("Consistency Group %s: not found") % name))
def project_query(self, name): """Retrieves UUID of project based on its name. :param name: name of project :returns: UUID of project :raises CoprHdError: - when project name is not found """ if common.is_uri(name): return name (tenant_name, project_name) = common.get_parent_child_from_xpath(name) tenant_obj = tenant.Tenant(self.ipaddr, self.port) tenant_uri = tenant_obj.tenant_query(tenant_name) projects = self.project_list(tenant_uri) if projects: for project in projects: if project: project_detail = self.project_show_by_uri(project['id']) if (project_detail and project_detail['name'] == project_name): return project_detail['id'] raise common.CoprHdError(common.CoprHdError.NOT_FOUND_ERR, (_("Project: %s not found") % project_name))
def snapshot_create(self, otype, typename, ouri, snaplabel, inactive, sync, readonly=False, synctimeout=0): """New snapshot is created, for a given volume. :param otype : block type should be provided :param typename : either volume or consistency-groups should be provided :param ouri : uri of volume :param snaplabel : name of the snapshot :param inactive : if true, the snapshot will not activate the synchronization between source and target volumes :param sync : synchronous request :param synctimeout : Query for task status for "synctimeout" secs. If the task doesn't complete in synctimeout secs, an exception is thrown """ # check snapshot is already exist is_snapshot_exist = True try: self.snapshot_query(otype, typename, ouri, snaplabel) except common.CoprHdError as e: if e.err_code == common.CoprHdError.NOT_FOUND_ERR: is_snapshot_exist = False else: raise if is_snapshot_exist: raise common.CoprHdError( common.CoprHdError.ENTRY_ALREADY_EXISTS_ERR, (_("Snapshot with name %(snaplabel)s" " already exists under %(typename)s") % { 'snaplabel': snaplabel, 'typename': typename })) parms = { 'name': snaplabel, # if true, the snapshot will not activate the synchronization # between source and target volumes 'create_inactive': inactive } if readonly is True: parms['read_only'] = readonly body = oslo_serialization.jsonutils.dumps(parms) # REST api call (s, h) = common.service_json_request( self.ipaddr, self.port, "POST", Snapshot.URI_SNAPSHOT_LIST.format(otype, typename, ouri), body) o = common.json_decode(s) task = o["task"][0] if sync: return (common.block_until_complete(otype, task['resource']['id'], task["id"], self.ipaddr, self.port, synctimeout)) else: return o
def create(self, project_name, label, size, varray, vpool, sync, consistencygroup, synctimeout=0): """Makes REST API call to create volume under a project. :param project_name: name of the project under which the volume will be created :param label: name of volume :param size: size of volume :param varray: name of varray :param vpool: name of vpool :param sync: synchronous request :param consistencygroup: To create volume under a consistencygroup :param synctimeout: Query for task status for 'synctimeout' secs. If the task doesn't complete in synctimeout secs, an exception is thrown :returns: Created task details in JSON response payload """ proj_obj = project.Project(self.ipaddr, self.port) project_uri = proj_obj.project_query(project_name) vpool_obj = virtualpool.VirtualPool(self.ipaddr, self.port) vpool_uri = vpool_obj.vpool_query(vpool, "block") varray_obj = virtualarray.VirtualArray(self.ipaddr, self.port) varray_uri = varray_obj.varray_query(varray) request = { 'name': label, 'size': size, 'varray': varray_uri, 'project': project_uri, 'vpool': vpool_uri, 'count': 1 } if consistencygroup: request['consistency_group'] = consistencygroup body = oslo_serialization.jsonutils.dumps(request) (s, h) = common.service_json_request(self.ipaddr, self.port, "POST", Volume.URI_VOLUMES, body) o = common.json_decode(s) if sync: # check task empty if len(o["task"]) > 0: task = o["task"][0] return self.check_for_sync(task, sync, synctimeout) else: raise common.CoprHdError( common.CoprHdError.SOS_FAILURE_ERR, _("error: task list is empty, no task response found")) else: return o
def authenticate_user(self, username, password): """Makes REST API call to generate the authentication token. Authentication token is generated for the specified user after validation :param username: Name of the user :param password: Password for the user :returns: The authtoken """ SEC_REDIRECT = 302 SEC_AUTHTOKEN_HEADER = 'X-SDS-AUTH-TOKEN' LB_API_PORT = 4443 # Port on which load-balancer/reverse-proxy listens to all incoming # requests for CoprHD REST APIs APISVC_PORT = 8443 # Port on which apisvc listens to incoming requests cookiejar = cookie_lib.LWPCookieJar() url = ('https://%(ip)s:%(port)d%(uri)s' % { 'ip': self.ipaddr, 'port': self.port, 'uri': self.URI_AUTHENTICATION }) try: if self.port == APISVC_PORT: login_response = requests.get(url, headers=self.HEADERS, verify=False, auth=(username, password), cookies=cookiejar, allow_redirects=False, timeout=common.TIMEOUT_SEC) if login_response.status_code == SEC_REDIRECT: location = login_response.headers['Location'] if not location: raise common.CoprHdError(common.CoprHdError.HTTP_ERR, (_("The redirect" " location of the" " authentication" " service is not" " provided"))) # Make the second request login_response = requests.get(location, headers=self.HEADERS, verify=False, cookies=cookiejar, allow_redirects=False, timeout=common.TIMEOUT_SEC) if (login_response.status_code != requests.codes['unauthorized']): raise common.CoprHdError(common.CoprHdError.HTTP_ERR, (_("The" " authentication" " service failed" " to reply with" " 401"))) # Now provide the credentials login_response = requests.get(location, headers=self.HEADERS, auth=(username, password), verify=False, cookies=cookiejar, allow_redirects=False, timeout=common.TIMEOUT_SEC) if login_response.status_code != SEC_REDIRECT: raise common.CoprHdError( common.CoprHdError.HTTP_ERR, (_("Access forbidden: Authentication required"))) location = login_response.headers['Location'] if not location: raise common.CoprHdError( common.CoprHdError.HTTP_ERR, (_("The" " authentication service failed to provide the" " location of the service URI when redirecting" " back"))) authtoken = login_response.headers[SEC_AUTHTOKEN_HEADER] if not authtoken: details_str = self.extract_error_detail(login_response) raise common.CoprHdError(common.CoprHdError.HTTP_ERR, (_("The token is not" " generated by" " authentication service." "%s") % details_str)) # Make the final call to get the page with the token new_headers = self.HEADERS new_headers[SEC_AUTHTOKEN_HEADER] = authtoken login_response = requests.get(location, headers=new_headers, verify=False, cookies=cookiejar, allow_redirects=False, timeout=common.TIMEOUT_SEC) if login_response.status_code != requests.codes['ok']: raise common.CoprHdError( common.CoprHdError.HTTP_ERR, (_("Login failure code: " "%(statuscode)s Error: %(responsetext)s") % { 'statuscode': six.text_type(login_response.status_code), 'responsetext': login_response.text })) elif self.port == LB_API_PORT: login_response = requests.get(url, headers=self.HEADERS, verify=False, cookies=cookiejar, allow_redirects=False) if (login_response.status_code == requests.codes['unauthorized']): # Now provide the credentials login_response = requests.get(url, headers=self.HEADERS, auth=(username, password), verify=False, cookies=cookiejar, allow_redirects=False) authtoken = None if SEC_AUTHTOKEN_HEADER in login_response.headers: authtoken = login_response.headers[SEC_AUTHTOKEN_HEADER] else: raise common.CoprHdError( common.CoprHdError.HTTP_ERR, (_("Incorrect port number. Load balanced port is: " "%(lb_api_port)s, api service port is: " "%(apisvc_port)s") % { 'lb_api_port': LB_API_PORT, 'apisvc_port': APISVC_PORT })) if not authtoken: details_str = self.extract_error_detail(login_response) raise common.CoprHdError( common.CoprHdError.HTTP_ERR, (_("The token is not generated by authentication service." " %s") % details_str)) if login_response.status_code != requests.codes['ok']: error_msg = None if login_response.status_code == 401: error_msg = _("Access forbidden: Authentication required") elif login_response.status_code == 403: error_msg = _("Access forbidden: You don't have" " sufficient privileges to perform" " this operation") elif login_response.status_code == 500: error_msg = _("Bourne internal server error") elif login_response.status_code == 404: error_msg = _( "Requested resource is currently unavailable") elif login_response.status_code == 405: error_msg = (_("GET method is not supported by resource:" " %s"), url) elif login_response.status_code == 503: error_msg = _("Service temporarily unavailable:" " The server is temporarily unable" " to service your request") else: error_msg = login_response.text raise common.CoprHdError( common.CoprHdError.HTTP_ERR, (_("HTTP code: %(status_code)s" ", response: %(reason)s" " [%(error_msg)s]") % { 'status_code': six.text_type( login_response.status_code), 'reason': six.text_type(login_response.reason), 'error_msg': six.text_type(error_msg) })) except (exceptions.SSLError, socket.error, exceptions.ConnectionError, exceptions.Timeout) as e: raise common.CoprHdError(common.CoprHdError.HTTP_ERR, six.text_type(e)) return authtoken