Skip to content

Commit 85b2ccd

Browse files
committed
Added known issue to atempt to forestall python2 openssl bug reports
Added test certs to manifest so the demos work out of the box pinned ruamel.yaml in install controls added requirement for requests to use new security enhancements per best practice tweaked security functions to make it clearer when the cert is failing on handshake
1 parent db31205 commit 85b2ccd

File tree

10 files changed

+39
-25
lines changed

10 files changed

+39
-25
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ include docs/history.rst
44
include LICENSE
55
include README.rst
66
include requirements.txt
7+
include nipyapi/demo/resources/keys/*
78

89
recursive-include nipyapi *
910
recursive-exclude * *.py[co]

README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,5 @@ Python Requirements
105105
-------------------
106106

107107
| Python 2.7 or 3.6 supported, though other versions may work.
108+
| Tested on Ubuntu and OSX 10.11.x - Windows automated testing not attempted
108109
| Outside of the standard Python modules, we make use of lxml, DeepDiff and ruamel.yaml

docs/history.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ History
1818
* Standardised bad user submission on AssertionError, bad API submission errors on ValueError, and general API errors on ApiException. This standard should flow forwards
1919
* Switched ruamel.yaml from >15 to <15 as advised in the project documentation, as >15 is not considered production ready
2020

21+
**Known Issues**
22+
23+
* Python2 environments with older versions of openssl may run into errors like 'SSLV3_ALERT_HANDSHAKE_FAILURE' when working in secured environments. This is not a NiPyApi bug, it's a problem with py2/openssl which is fixed by either upgrading openssl or moving to Python3 like you know you should
24+
2125
**New Features**
2226

2327
* Added support for working with secured NiFi environments, contributed by KevDoran
@@ -35,6 +39,7 @@ History
3539
* Implemented import/export to json/yaml in versioning
3640
* Added regression/backtesting for many functions going back through major release versions to NiFi-1.1.2. More details will be obvious from reading tests/conftest.py
3741
* Test suites now more reliably clean up after themselves when executed on long-running environments
42+
* Apparently logging is popular, so standard Python logging is now included
3843

3944
**Other notes**
4045

nipyapi/config.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
long_max_wait = 120
4747

4848

49-
5049
# --- Object Filters ------
5150
# This sets the mappings of where in the native datatype objects to find
5251
# particularly useful fields, like UUID or NAME.

nipyapi/demo/secure_connection.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
log = logging.getLogger(__name__)
1515
log.setLevel(logging.INFO)
16+
logging.getLogger('nipyapi.utils').setLevel(logging.INFO)
17+
logging.getLogger('nipyapi.security').setLevel(logging.INFO)
18+
logging.getLogger('nipyapi.versioning').setLevel(logging.INFO)
1619

1720
# Uncomment the block below to enable debug logging
1821
# nipyapi.config.nifi_config.debug=True
@@ -29,8 +32,9 @@
2932
secured_registry_url = 'https://localhost:18443/nifi-registry-api'
3033
secured_nifi_url = 'https://localhost:8443/nifi-api'
3134

32-
host_certs_path = path.abspath(
33-
nipyapi.config.PROJECT_ROOT_DIR + "/demo/resources/keys"
35+
host_certs_path = path.join(
36+
nipyapi.config.PROJECT_ROOT_DIR,
37+
"demo/resources/keys"
3438
)
3539

3640
tls_env_vars = {
@@ -191,11 +195,12 @@ def bootstrap_nifi_access_policies():
191195

192196
log.info("Creating Registry security context")
193197
nipyapi.utils.set_endpoint(secured_registry_url)
198+
log.info("Using demo certs from %s", host_certs_path)
194199
nipyapi.security.set_service_ssl_context(
195200
service='registry',
196-
ca_file=host_certs_path + '/localhost-ts.pem',
197-
client_cert_file=host_certs_path + '/client-cert.pem',
198-
client_key_file=host_certs_path + '/client-key.pem',
201+
ca_file=path.join(host_certs_path, 'localhost-ts.pem'),
202+
client_cert_file=path.join(host_certs_path, 'client-cert.pem'),
203+
client_key_file=path.join(host_certs_path, 'client-key.pem'),
199204
client_key_password='clientPassword'
200205
)
201206
log.info("Waiting for Registry to be ready for login")

nipyapi/security.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def get_service_access_status(service='nifi', bool_response=False):
195195
Returns:
196196
(bool) if bool_response, else the Service Access Status of the User
197197
"""
198-
log.info("Called get_registry_access_status with args %s", locals())
198+
log.info("Called get_service_access_status with args %s", locals())
199199
assert service in _valid_services
200200
assert isinstance(bool_response, bool)
201201
if bool_response:
@@ -204,12 +204,14 @@ def get_service_access_status(service='nifi', bool_response=False):
204204
log.debug("- bool_response is True, disabling urllib3 warnings")
205205
logging.getLogger('urllib3').setLevel(logging.ERROR)
206206
try:
207-
return getattr(nipyapi, service).AccessApi().get_access_status()
207+
out = getattr(nipyapi, service).AccessApi().get_access_status()
208+
log.info("Got server response, returning")
209+
return out
208210
except urllib3.exceptions.MaxRetryError as e:
209211
log.debug("- Caught exception %s", type(e))
210212
if bool_response:
211-
log.debug("- bool_response is True, returning False instead of"
212-
" raising exception")
213+
log.debug("Connection failed with error %s and bool_response is "
214+
"True, returning False", e)
213215
return False
214216
log.debug("- bool_response is False, raising Exception")
215217
raise e
@@ -507,7 +509,8 @@ def set_service_ssl_context(
507509
ssl_context.load_cert_chain(
508510
certfile=client_cert_file,
509511
keyfile=client_key_file,
510-
password=client_key_password)
512+
password=client_key_password
513+
)
511514
except FileNotFoundError as e:
512515
raise FileNotFoundError(
513516
"Unable to read keyfile {0} or certfile {1}, error was "

nipyapi/utils.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -329,29 +329,29 @@ def start_docker_containers(docker_containers, network_name='demo'):
329329
Returns: Nothing
330330
331331
"""
332-
log.info("- Creating Docker client using Environment Variables")
332+
log.info("Creating Docker client using Environment Variables")
333333
d_client = docker.from_env()
334334

335335
for target in docker_containers:
336336
assert isinstance(target, DockerContainer)
337337

338338
# Pull relevant Images
339-
log.info("- Pulling relevant Docker Images")
339+
log.info("Pulling relevant Docker Images")
340340
for image in set([(c.image_name + ':' + c.image_tag)
341341
for c in docker_containers]):
342-
log.info("- - Pulling %s", image)
342+
log.info("Pulling %s", image)
343343
d_client.images.pull(image)
344344

345345
# Clear previous containers
346-
log.info("- Clearing previous containers for this demo")
346+
log.info("Clearing previous containers for this demo")
347347
d_clear_list = [li for li in d_client.containers.list(all=True)
348348
if li.name in [i.name for i in docker_containers]]
349349
for c in d_clear_list:
350-
log.info("- - Removing old container %s", c.name)
350+
log.info("Removing old container %s", c.name)
351351
c.remove(force=True)
352352

353353
# Deploy/Get Network
354-
log.info("- Getting Docker bridge network")
354+
log.info("Getting Docker bridge network")
355355
d_n_list = [li for li in d_client.networks.list()
356356
if network_name in li.name]
357357
if not d_n_list:
@@ -364,13 +364,13 @@ def start_docker_containers(docker_containers, network_name='demo'):
364364
raise EnvironmentError("Too many test networks found")
365365
else:
366366
d_network = d_n_list[0]
367-
log.info("- - Using Docker network: %s", d_network.name)
367+
log.info("Using Docker network: %s", d_network.name)
368368

369369
# Deploy Containers
370-
log.info("- Starting relevant Docker Containers")
370+
log.info("Starting relevant Docker Containers")
371371
c_hooks = {}
372372
for c in docker_containers:
373-
log.info("- - Starting Container %s", c.name)
373+
log.info("Starting Container %s", c.name)
374374
c_hooks[c.name] = d_client.containers.run(
375375
image=c.image_name + ':' + c.image_tag,
376376
detach=True,

nipyapi/versioning.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,8 +582,8 @@ def export_flow_version(bucket_id, flow_id, version=None, file_path=None,
582582
Args:
583583
bucket_id (str): the UUID of the bucket containing the Flow
584584
flow_id (str): the UUID of the Flow to be retrieved from the Bucket
585-
version (Optional [None, Str]): 'None' to retrieve the latest version, or a version
586-
number as a string to get that version
585+
version (Optional [None, Str]): 'None' to retrieve the latest version,
586+
or a version number as a string to get that version
587587
file_path (str): The path and filename to write to. Defaults to None
588588
which returns the serialised obj
589589
mode (str): 'json' or 'yaml' to specific the encoding format

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ deepdiff>=3.3.0
1414

1515
# Demo deployment automation
1616
docker>=2.5.1
17-
requests>=2.18
17+
requests[security]>=2.18

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
'lxml', # Required for parsing NiFi Templates
1919
'deepdiff', # Required for comparing configurations
2020
'six', # Required for managing Python version compatibility
21-
'ruamel.yaml', # Required for parsing Json/Yaml consistently
21+
'ruamel.yaml==0.14.12', # Required for parsing Json/Yaml consistently
2222
'docker', # Used to deploy demo assemblies
23-
'requests' # Used in utils functions
23+
'requests[security]' # Used in utils functions, security extras for Py2
2424
]
2525

2626
setup_requirements = [

0 commit comments

Comments
 (0)