Chaffelson / nipyapi

A convenient Python wrapper for Apache NiFi
Other
243 stars 76 forks source link

Unable to connect to secure connection to Nifi in CDP Public Cloud #311

Closed LvffY closed 1 year ago

LvffY commented 2 years ago

Description

I'm trying to request my nifi installation. My server is a Cloudera server behind a ranger/kerberos authentication.

What I Did

I'm trying to set up a simple request :

import nipyapi

nipyapi.config.nifi_config.host = "https://nifi_url/nifi-api"
nipyapi.config.nifi_config.username = "user"
nipyapi.config.nifi_config.password = "password"

parameters = nipyapi.parameters.get_parameter_context('my_id', identifier_type='id')
print(parameters)

With these lines I get the following errors

Traceback (most recent call last):
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\utils.py", line 640, in rest_exceptions
    yield
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\system.py", line 25, in get_system_diagnostics
    return nipyapi.nifi.SystemDiagnosticsApi().get_system_diagnostics()
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\nifi\apis\system_diagnostics_api.py", line 67, in get_system_diagnostics
    (data) = self.get_system_diagnostics_with_http_info(**kwargs)
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\nifi\apis\system_diagnostics_api.py", line 135, in get_system_diagnostics_with_http_info
    return self.api_client.call_api('/system-diagnostics', 'GET',
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\nifi\api_client.py", line 330, in call_api
    return self.__call_api(resource_path, method,
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\nifi\api_client.py", line 150, in __call_api
    response_data = self.request(method, url,
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\nifi\api_client.py", line 353, in request
    return self.rest_client.GET(url,
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\nifi\rest.py", line 240, in GET
    return self.request("GET", url,
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\nifi\rest.py", line 235, in request
    raise ApiException(http_resp=r)
nipyapi.nifi.rest.ApiException: (401)
Reason: Unauthorized
HTTP response headers: HTTPHeaderDict({'Server': 'nginx', 'Date': 'Tue, 26 Jul 2022 13:55:17 GMT', 'Content-Length': '0', 'Connection': 'keep-alive', 'WWW-Authenticate': 'BASIC realm="application"', 'x-response-nginx': 'true'})

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\plugins\modules\nifi\test_nifi.py", line 23, in <module>
    parameters = nipyapi.parameters.get_parameter_context('my_id', identifier_type='id')
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\utils.py", line 652, in wrapper
    return f(*args, **kwargs)
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\parameters.py", line 54, in get_parameter_context
    enforce_min_ver('1.10.0')
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\utils.py", line 572, in enforce_min_ver
    if check_version(min_version, service=service) == 1:
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\utils.py", line 525, in check_version
    nipyapi.system.get_nifi_version_info().ni_fi_version
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\system.py", line 59, in get_nifi_version_info
    diags = get_system_diagnostics()
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\system.py", line 24, in get_system_diagnostics
    with nipyapi.utils.rest_exceptions():
  File "C:\Python310\lib\contextlib.py", line 153, in __exit__
    self.gen.throw(typ, value, traceback)
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\nipyapi\utils.py", line 643, in rest_exceptions
    _raise(ValueError(e.body), e)
  File "C:\Users\aberges\IdeaProjects\GEODIS\ansible_collections\itcorp_datalayer\deploy_app\venv\lib\site-packages\future\utils\__init__.py", line 403, in raise_from
    exec(execstr, myglobals, mylocals)
  File "<string>", line 1, in <module>
ValueError

Process finished with exit code 1

On the other side, if I'm doing simple rest api calls, it works :

import requests
from pprint import pprint

auth = ("user", "pwd")

req = requests.get(f"https://nifi_url/nifi-api/parameter-contexts/my_id", auth=auth)

 pprint(req.json()["component"]["parameters"])

I think that others requests are made but I'm not aware of which requests.

Urgency

It is not really blocking but I would really like to use this API instead of the RAW REST API. The latest I have an answer on this, the toughest it will be on my side to replace REST API calls by the API.

Chaffelson commented 2 years ago

Two initial thoughts:

  1. I think you are being blocked by NiPy attempting to fetch get_system_diagnostics - probably the user you are using doesn't have that authz in Ranger. That call is attempting to determine the version of NiFi to handle some compatibility switches between NiFi and NiFi-Registry, we should probably have it fail more gracefully when the permission is not available.
  2. We don't test on Python 3.10 yet as I've seen some issues with urllib3 that I haven't had time to unpack. If you continue to see issues I also suggest trying python >3.6,<=3.9 to be sure
LvffY commented 2 years ago

@Chaffelson Thanks for your answer :)

import requests
from pprint import pprint

auth = ("user", "pwd")

req = requests.get(f"https://nifi_url/system-diagnostics", auth=auth)

pprint(req.json())

I looked in my ranger audit, but didn't see any failure :(

Now I'm a bit confused ^^'

Chaffelson commented 2 years ago

Ah ok, can I suggest you try using nipyapi.utils.set_endpoint

Nipy doesn't expect you to modify the underlying configs directly, although you can in many cases. For simple activities like you are trying, I created helper methods to ensure that login and logout are completed correctly and with the right security context.

LvffY commented 2 years ago

@Chaffelson I did not see this function, should be useful !

Unfortunately, I still got the same error :(

import nipyapi

nipyapi.utils.set_endpoint(endpoint_url="https://nifi_url/nifi-api", username="user", password="password")

parameters = nipyapi.parameters.get_parameter_context('my_id', identifier_type='id')
print(parameters)
Chaffelson commented 2 years ago

Try:

import nipyapi

nipyapi.utils.set_endpoint(endpoint_url="https://nifi_url/nifi-api", username="user", password="password", login=True)

parameters = nipyapi.parameters.get_parameter_context('my_id', identifier_type='id')
print(parameters)
LvffY commented 2 years ago

@Chaffelson Same error :(

Chaffelson commented 2 years ago

Ok I think we need to sync up on what is not working, hit me up on the Apache NiFi slack and we can diagnose it

LvffY commented 2 years ago

After a call with @Chaffelson (thanks again ;)) we have a working setup :

We think that our problem is only related to our environment (which is a CDP Public Cloud from Cloudera) but in case anyone fall into this, you need to setup the force_basic_auth to True

To work, I did the following code :

import nipyapi

############ For Nifi server
nipyapi.config.nifi_config.force_basic_auth = True
nipyapi.config.nifi_config.username = "user"
nipyapi.config.nifi_config.password = "password"
nipyapi.utils.set_endpoint(endpoint_url=nifi_api)
print(nipyapi.canvas.get_root_pg_id())

########### For Nifi registry
nipyapi.config.registry_config.username = "user"
nipyapi.config.registry_config.password = "password"
nipyapi.config.registry_config.force_basic_auth = True
nipyapi.utils.set_endpoint(self.nifi_reg_endpoint)
Chaffelson commented 2 years ago

I think we should add an enhancement to the set_endpoint method to allow a flag for basic_auth usage