示例#1
0
def get_service_descriptors():
    """Returns info on all available service descriptors.

    :returns: A list. [0] is a bool with the result. [1] is a list of 
        dictionaries. Each dictionary contains an nsd.
    """

    # get current list of service descriptors
    resp = requests.get(env.service_descriptor_api,
                        timeout=env.timeout,
                        headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for service descriptors returned with " +
                  (str(resp.status_code)))
        return False, []

    services = json.loads(resp.text)

    services_res = []
    for service in services:
        if service['platform'] != '5gtango':
            continue
        dic = {
            'descriptor_uuid': service['uuid'],
            'name': service['nsd']['name'],
            'version': service['nsd']['version'],
            'created_at': service['created_at']
        }
        LOG.debug(str(dic))
        services_res.append(dic)

    return True, services_res
示例#2
0
def get_function_instances():
    """Returns info on all available function instances.

    :returns: A tuple. [0] is a bool with the result. [1] is a list of 
        dictionaries. Each dictionary contains a vnfr.
    """

    # get current list of function instances
    resp = requests.get(env.function_instance_api,
                        timeout=env.timeout,
                        headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for function instances returned with " +
                  (str(resp.status_code)))
        return False, []

    functions = json.loads(resp.text)

    functions_res = []
    for function in functions:
        dic = {
            'instance_uuid': function['uuid'],
            'status': function['status'],
            'version': function['version'],
            'created_at': function['created_at']
        }
        LOG.debug(str(dic))
        functions_res.append(dic)

    return True, functions_res
示例#3
0
文件: vimwim.py 项目: ubitech/tng-cli
def get_wims(wim_type=None):
    """Obtain the available Wims.

    :param type: optional type of wim

    :returns: A list. [0] is a bool with the result. [1] is a list of 
        dictionaries. Each dictionary contains a wim.
    """

    # get current list of wims
    url = env.ia_api + '/wims'
    if wim_type:
        url = url + '?type=' + wim_type
    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for wims returned with " + (str(resp.status_code)))
        return False, []

    wims = json.loads(resp.text)

    wims_res = []
    for wim in wims:
        dic = {
            'wim_uuid': wim['uuid'],
            'name': wim['name'],
            'type': wim['type']
        }
        wims_res.append(dic)

    return True, wims_res
示例#4
0
文件: slas.py 项目: ubitech/tng-cli
def get_violations(nsi_uuid=None):
    """Returns info on all SLA violations.

    :param nsi_uuid:  (Default value = None) uuid of a service instance.

    :returns: A list. [0] is a bool with the result. [1] is a list of 
        SLA violations associated to a service instance.
    """

    url = env.sl_violations_api
    if nsi_uuid:
        url = env.sl_violations_api + '/service/' + nsi_uuid

    # get current list of violations
    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    violations = json.loads(resp.text)
    return True, violations
示例#5
0
文件: slas.py 项目: ubitech/tng-cli
def get_violations_per_nsi_sla(sla_uuid, nsi_uuid):
    """Returns the vaiolations for a specific SLA.

    :param sla_uuid: uuid of SLA template.
    :param nsi_uuid: uuid of network service instance.

    :returns: A list. [0] is a bool with the result. [1] is a list of 
        SLA violations associated to a service instance and an SLA 
        template.
    """

    url = env.sl_violations_api + '/' + sla_uuid + '/' + nsi_uuid

    # get current list of violations
    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    violations = json.loads(resp.text)

    return True, violations
示例#6
0
文件: slas.py 项目: ubitech/tng-cli
def get_sla_guarantees():
    """Returns info on all available SLA guarantees.

    :returns: A list. [0] is a bool with the result. [1] is a list of 
        dictionaries. Each dictionary contains an SLA guarantee.
    """

    # get current list of templates
    resp = requests.get(env.sl_guarantees_api,
                        timeout=env.timeout,
                        headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    guarantees = json.loads(resp.text)['guaranteeTerms']

    guar_res = []

    for guarantee in guarantees:
        dic = {
            'name': guarantee['guarantee_name'],
            'id': guarantee['guaranteeID'],
            'operator': guarantee['guarantee_operator'],
            'value': guarantee['guarantee_threshold']
        }
        LOG.debug(str(dic))
        guar_res.append(dic)

    return True, guar_res
示例#7
0
文件: slas.py 项目: ubitech/tng-cli
def get_agreements(nsi_uuid=None):
    """Returns info on all available SLA agreements.

    :param nsi_uuid:  (Default value = None) uuid of a service instance.

    :returns: A list. [0] is a bool with the result. [1] is a list of 
        dictonaries. Each dictionary contains an SLA agreement.
    """

    url = env.sl_agreements_api
    if nsi_uuid:
        url = env.sl_agreements_api + '/service/' + nsi_uuid

    # get current list of agreements
    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    if nsi_uuid:
        agreements = json.loads(resp.text)['cust_sla']
    else:
        agreements = json.loads(resp.text)['agreements']

    return True, agreements
示例#8
0
def create_policy(path):
    """Uploads a policy descriptor.

    :param path: relative path where policy descriptor is stored.

    :returns: A list. [0] is a bool with the result. [1] is a string containing
        the uuid of the uploaded policy descriptor.
    """

    ext = os.path.splitext(path)[1]

    if ext == '.json':
        template_raw = open(path, 'r')
        template = json.load(template_raw)
    elif ext in ['.yaml', '.yml']:
        template_raw = open(path, 'rb')
        template = yaml.load(template_raw)
    else:
        return False, "Provide json or yaml file"

    resp = requests.post(env.policy_api,
                         json=template,
                         timeout=env.timeout,
                         headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    uuid = json.loads((json.loads(resp.text)['returnobject']))['uuid']

    return True, uuid
示例#9
0
文件: slas.py 项目: ubitech/tng-cli
def get_sla_templates():
    """Returns info on all available SLA templates.

    :returns: A list. [0] is a bool with the result. [1] is a list of 
        dictionaries. Each dictionary contains an SLA template.
    """

    # get current list of templates
    resp = requests.get(env.sl_templates_api,
                        timeout=env.timeout,
                        headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    templates = json.loads(resp.text)

    temp_res = []

    for template in templates:
        dic = {
            'name': template['slad']['name'],
            'created_at': template['created_at'],
            'service': template['slad']['sla_template']['service']['ns_name'],
            'sla_uuid': template['uuid'],
        }
        LOG.debug(str(dic))
        temp_res.append(dic)

    return True, temp_res
示例#10
0
def get_policies():
    """Returns info on all available policiy descriptors.

    :returns: A list. [0] is a bool with the result. [1] is a list of 
        dictionaries. Each dictionary contains a policy descriptor.
    """

    # get current list of policies
    resp = requests.get(env.policy_api,
                        timeout=env.timeout,
                        headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for policies returned with " +
                  (str(resp.status_code)))
        return False, []

    policies = json.loads(resp.text)

    policies_res = []
    for pol in policies:
        dic = {'policy_uuid': pol['uuid'],
               'name': pol['pld']['name'],
               'service': pol['pld']['network_service']['name'],
               'created_at': pol['created_at']}
        LOG.debug(str(dic))
        policies_res.append(dic)

    return True, policies_res
示例#11
0
def attach_policy(policy_uuid, service_uuid, sla_uuid):
    """Attaches a policy to a service and SLA.

    :param policy_uuid: uuid of a policy descriptor.
    :param service_uuid: uuid of a network service.
    :param sla_uuid: uuid of an SLA.

    :returns: A list. [0] is a bool with the result. [1] is a string indicating
        the result.
    """

    data = {'nsid': service_uuid, 'slaid': sla_uuid}
    resp = requests.patch(env.policy_bind_api + '/' + policy_uuid,
                          json=data,
                          timeout=env.timeout,
                          headers=env.header)

    env.set_return_header(resp.headers)
  
    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    message = json.loads(resp.text)['message']

    return True, message
示例#12
0
def get_packages():
    """Returns info on all available packages.

    :returns: A tuple. [0] is a bool with the result. [1] is a list of 
        dictionaries. Each dictionary contains a package descriptor.
    """

    # get current list of packages
    resp = requests.get(env.pkg_api, timeout=env.timeout, headers=env.header)

    if resp.status_code != 200:
        LOG.debug("Request for packages returned with " +
                  (str(resp.status_code)))
        return False, []

    pkgs = json.loads(resp.text)

    pkg_res = []
    for pkg in pkgs:
        dic = {
            'package_uuid': pkg['uuid'],
            'name': pkg['pd']['name'],
            'version': pkg['pd']['version'],
            'created_at': pkg['created_at']
        }
        LOG.debug(str(dic))
        pkg_res.append(dic)

    env.set_return_header(resp.headers)
    return True, pkg_res
示例#13
0
文件: slices.py 项目: tsoenen/tng-cli
def get_slice_templates():
    """Returns info on all available slice templates.

    :returns: A tuple. [0] is a bool with the result. [1] is a list of 
        dictionaries. Each dictionary contains a slice template.
    """

    # get current list of slices
    resp = requests.get(env.slice_template_api,
                        timeout=env.timeout,
                        headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for slices returned with " +
                  (str(resp.status_code)))
        return False, []

    slices = json.loads(resp.text)

    slices_res = []
    for slc in slices:
        dic = {
            'slice_uuid': slc['uuid'],
            'name': slc['nstd']['name'],
            'version': slc['nstd']['version'],
            'created_at': slc['created_at']
        }
        LOG.debug(str(dic))
        slices_res.append(dic)

    return True, slices_res
示例#14
0
def create_sla_template(templateName,
                        nsd_uuid,
                        expireDate,
                        guaranteeId,
                        service_licence_type,
                        allowed_service_instances,
                        service_licence_expiration_date,
                        template_initiator,
                        provider_name,
                        dflavour_name=None):
    """Generates an initial SLA template.

    :param templateName: name for the SLA template. 
    :param nsd_uuid: uuid of the network service.
    :param expireDate: DD/MM/YYYY expiration date.
    :param guaranteeId: id of the SLA guarantee.
    :param template_initiator: the one who creates the sla template e.g. Uprc.
    :param provider_name: the vendor on behalf of whom the sla template is 
        generated e.g. Telefonica.
    :param dflavour_name: the mapped deployment flavor.
    :param service_licence_type: the selected license 
        type (public|trial|private).
    :param allowed_service_instances: the allowed ns instances based on 
        the license.
    :param service_licence_expiration_date: DD/MM/YYYY license expiration date.

    :returns: A tuple. [0] is a bool with the result. [1] is a string containing
        the uuid of the created SLA template.
    """

    # generate sla template
    data = {
        'templateName': templateName,
        'nsd_uuid': nsd_uuid,
        'guaranteeId': guaranteeId,
        'expireDate': expireDate,
        'template_initiator': template_initiator,
        'provider_name': provider_name,
        'dflavour_name': dflavour_name,
        'service_licence_type': service_licence_type,
        'allowed_service_instances': allowed_service_instances,
        'service_licence_expiration_date': service_licence_expiration_date
    }

    resp = requests.post(env.sl_templates_api,
                         data=data,
                         timeout=env.timeout,
                         headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 201:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    uuid = json.loads(resp.text)['uuid']

    return True, uuid
示例#15
0
def upload_package(pkg_path, url=False, return_process_uuid=False):
    """Uploads a package from file.

    :param pkg_path: relative path to the package that needs uploading, or url
    :param pkg_path: A bool, True if pkg_path is an url
    :param return_process_uuid: A bool, if you want the package_process_uuid
        returned instead of the package_uuid

    :returns: A list. [0] is a bool with the result. [1] is a string containing
        either the uuid of the uploaded package, the process uuid of the package
         or an error message.
    """

    if not url:
        pkg = (os.path.basename(pkg_path), open(pkg_path, 'rb'))

    else:
        pkg = (pkg_path.split('/')[-1], requests.get(pkg_path).content)

    resp = requests.post(env.pkg_api,
                         files={"package": pkg},
                         timeout=env.timeout,
                         headers=env.header)

    pyld = json.loads(resp.text)
    LOG.debug(pyld)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug(str(pyld))
        return False, str(pyld)

    pkg_proc_id = pyld['package_process_uuid']
    url = env.pkg_status_api + '/' + pkg_proc_id

    for i in range(10):
        resp = requests.get(url, timeout=env.timeout, headers=env.header)
        pyld = json.loads(resp.text)
        LOG.debug(pyld)
        if resp.status_code != 200:
            return False, str(pyld)

        if 'package_process_status' in pyld:
            status = pyld['package_process_status']
            if status == 'success':
                if return_process_uuid:
                    return True, pkg_proc_id
                return True, pyld['package_id']
            elif status == 'failed':
                error = str(pyld["package_metadata"]["error"])
                return False, error
            else:
                return False, "upload status: " + str(status)
        time.sleep(1)

    msg = "Couldn't upload package. Is file really a package?"
    LOG.debug(msg)
    return False, msg
示例#16
0
def delete_users():
    """Clean the DB deleting all users .

    :returns: A tuple. [0] is a bool with the result
    """
    resp = requests.delete(env.user_api, timeout=env.timeout)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        LOG.debug(str(resp.text))
        return False, json.loads(resp.text)

    return True, json.loads(resp.text)
示例#17
0
def _post_request(data):
    """ Generic request maker. """

    resp = requests.post(env.request_api,
                         json=data,
                         timeout=env.timeout,
                         headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 201:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        LOG.debug(str(resp.text))
        return False, json.loads(resp.text)

    return True, json.loads(resp.text)['id']
示例#18
0
def update_token(username, password, store_token=False):
    """Obtain a new authentication token

    :param username: A string.
    :param password: A string.
    :returns: A string containing the token.

    """

    data = {}
    data['username'] = username
    data['password'] = password

    resp = requests.post(env.session_api,
                         json=data,
                         timeout=env.timeout)
    
    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " +
                  (str(resp.status_code)))
        LOG.debug(str(resp.text))
        return False, json.loads(resp.text)

    token = json.loads(resp.text)['token']

    if store_token:
        payload = {}

        try:
            with open('/tmp/tngcli.txt', 'r') as file:
                for line in file:
                    payload = json.loads(line)
        except:
            pass

        payload[env.get_sp_path()] = {'token': token}
        #datetime to string. Return with strptime(s, format)
        exp_t = datetime.now().strftime('%Y-%m-%d %H:%M')
        payload[env.get_sp_path()]['exp_t'] = exp_t
        with open('/tmp/tngcli.txt', 'w+') as file:
            file.write(json.dumps(payload))
            file.close()

    return True, token
示例#19
0
def get_test_descriptors():
    """Returns info on all available test descriptors.

    :returns: A tuple. [0] is a bool with the result. [1] is a list of
        dictionaries. Each dictionary contains a test descriptor.
    """

    # get current list of test descriptors
    resp = requests.get(env.test_descriptors_api,
                        timeout=env.timeout,
                        headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for test descriptors returned with " +
                  (str(resp.status_code)))
        return False, []

    descriptors = json.loads(resp.text)

    descriptors_res = []
    for descriptor in descriptors:

        platforms = ""
        for platform in descriptor['testd']['service_platforms']:
            print(platform)
            if platforms == "":
                platforms = platform
            else:
                platforms = platforms + "," + platform

        dic = {
            'uuid': descriptor['uuid'],
            'name': descriptor['testd']['name'],
            'vendor': descriptor['testd']['vendor'],
            'version': descriptor['testd']['version'],
            'platforms': platforms,
            'status': descriptor['status'],
            'updated_at': descriptor['updated_at']
        }
        LOG.debug(str(dic))
        descriptors_res.append(dic)

    return True, descriptors_res
示例#20
0
def user_info(username):
    """Log out the session user.

    :param username:  Logged in username

    :returns: A tuple. [0] is a bool with the result [1] is a json with the user information
    """
    url = env.user_api + '/' + username
    resp = requests.get(url, timeout=env.timeout)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        LOG.debug(str(resp.text))
        return False, None

    return True, json.loads(resp.text)
示例#21
0
def delete_user(username):
    """Deleting a specific user

    :param username:  username of the user

    :returns: A tuple. [0] is a bool with the result
    """
    url = env.user_api + '/' + username

    resp = requests.delete(url, timeout=env.timeout, headers=env.header)
    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        LOG.debug(str(resp.text))
        return False, None

    return True, None
示例#22
0
def delete_wim(wim_uuid):
    """Delete a wim.

    :param wim_uuid: uuid of the wim to be deleted.

    :returns: A tuple. [0] is a bool with the result. [1] is response message.
    """

    url = env.ia_api + '/wims/' + wim_uuid

    resp = requests.delete(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for wims returned with " + (str(resp.status_code)))
        return False, []

    return True, json.loads(resp.text)
示例#23
0
def get_vim(vim_uuid):
    """Get a vim.

    :param vim_uuid: uuid of the vim.

    :returns: A tuple. [0] is a bool with the result. [1] is response message.
    """

    url = env.ia_api + '/vims/' + vim_uuid

    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for vims returned with " + (str(resp.status_code)))
        return False, []

    return True, json.loads(resp.text)
示例#24
0
def get_test_plan(uuid):
    """Returns info on a specific test plan.

    :param uuid: uuid of test plan.

    :returns: A list. [0] is a bool with the result. [1] is a dictionary
        containing a test plan.
    """

    url = env.test_plans_api + '/' + uuid
    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for test returned with " + (str(resp.status_code)))
        return False, json.loads(resp.text)

    return True, json.loads(resp.text)
示例#25
0
def get_testing_tags():
    """Returns the currently stored testing tags.

    :returns: A list. [0] is a bool with the result. [1] is a list with
		the currently stored testing tags.
    """

    url = env.recommendations_api + '/test_items'
    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request returned with " + (str(resp.status_code)))
        error = resp.text
        return False, error

    test_items = json.loads(resp.text)

    return True, test_items
示例#26
0
def get_analytic_results():
    """Returns a json array with all available analytic service results.

    :param uuid: none

    :returns: A list. [0] is a bool with the result. [1] is a dictionary
        containing all available analytic service results.
    """

    url = env.analytics_engine_api + '/results/list'
    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for test descriptor returned with " +
                  (str(resp.status_code)))
        return False, json.loads(resp.text)

    return True, len(json.loads(resp.text))
示例#27
0
文件: slices.py 项目: tsoenen/tng-cli
def get_slice_template(slice_template_uuid):
    """Returns info on a specific slice template.

    :param slice_template_uuid: uuid of a slice template.

    :returns: A tuple. [0] is a bool with the result. [1] is a dictionary 
        containing a slice template.
    """

    # get slice info
    url = env.slice_template_api + '/' + slice_template_uuid
    resp = requests.get(url, timeout=env.timeout, headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for slice returned with " + (str(resp.status_code)))
        return False, json.loads(resp.text)

    return True, json.loads(resp.text)
示例#28
0
def get_requests():
    """Returns info on all requests.


    :returns: A tuple. [0] is a bool with the result. [1] is a list of
        dictionaries, each containing a request.

    """

    # get current list of requests
    resp = requests.get(env.request_api,
                        timeout=env.timeout,
                        headers=env.header)

    env.set_return_header(resp.headers)

    if resp.status_code != 200:
        LOG.debug("Request for requests returned with " +
                  (str(resp.status_code)))
        LOG.debug(str(resp.text))
        return False, []

    requests_dic = json.loads(resp.text)

    req_res = []
    for req in requests_dic:
        dic = {
            'request_uuid': req['id'],
            'request_type': req['request_type'],
            'status': req['status'],
            'created_at': req['created_at'],
            'instance_uuid': req['instance_uuid']
        }

        if dic['instance_uuid'] is None:
            dic['instance_uuid'] = ''

        LOG.debug(str(dic))
        req_res.append(dic)

    return True, req_res
示例#29
0
def get_detailed_agreement(sla_uuid, nsi_uuid):
    """Returns info on a specific Agreement.

    :param sla_uuid: uuid of an SLA template.
    :param nsi_uuid: uuid of a service instance.

    :returns: A tuple. [0] is a bool with the result. [1] is a dictionary
        containing details on a single SLA agreement.
    """
    url = env.sl_agreements_api + '/' + sla_uuid + '/' + nsi_uuid

    resp = requests.get(url, timeout=env.timeout, headers=env.header)
    LOG.debug("SLA UUID: " + sla_uuid + "NSI UUID: " + nsi_uuid)
    LOG.debug(str(resp.text))

    env.set_return_header(resp.headers)

    if resp.status_code == 200:
        return True, json.loads(resp.text)
    else:
        return False, json.loads(resp.text)['error']
示例#30
0
def delete_sla_template(sla_template_uuid):
    """Deletes an SLA template.

    :param sla_template_uuid: uuid of an SLA template.

    :returns: A tuple. [0] is a bool with the result. [1] is a string containing
        the uuid of the terminated SLA.
    """

    url = env.sl_templates_api + '/' + sla_template_uuid

    resp = requests.delete(url, timeout=env.timeout, headers=env.header)
    LOG.debug(sla_template_uuid)
    LOG.debug(str(resp.text))

    env.set_return_header(resp.headers)

    if resp.status_code == 200:
        return True, sla_template_uuid
    else:
        return False, json.loads(resp.text)