insightconnect-plugin-runtime 6.4.0__py3-none-any.whl → 6.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- insightconnect_plugin_runtime/clients/aws_client.py +18 -3
- insightconnect_plugin_runtime/helper.py +1 -1
- insightconnect_plugin_runtime/server.py +3 -2
- {insightconnect_plugin_runtime-6.4.0.dist-info → insightconnect_plugin_runtime-6.4.2.dist-info}/METADATA +16 -14
- {insightconnect_plugin_runtime-6.4.0.dist-info → insightconnect_plugin_runtime-6.4.2.dist-info}/RECORD +9 -9
- tests/unit/test_aws_action.py +66 -11
- tests/unit/test_connection.py +6 -6
- {insightconnect_plugin_runtime-6.4.0.dist-info → insightconnect_plugin_runtime-6.4.2.dist-info}/WHEEL +0 -0
- {insightconnect_plugin_runtime-6.4.0.dist-info → insightconnect_plugin_runtime-6.4.2.dist-info}/top_level.txt +0 -0
|
@@ -19,6 +19,7 @@ from insightconnect_plugin_runtime.exceptions import (
|
|
|
19
19
|
ConnectionTestException,
|
|
20
20
|
)
|
|
21
21
|
from insightconnect_plugin_runtime.helper import clean
|
|
22
|
+
from insightconnect_plugin_runtime.util import is_running_in_cloud
|
|
22
23
|
|
|
23
24
|
REGION = "region"
|
|
24
25
|
EXTERNAL_ID = "external_id"
|
|
@@ -371,6 +372,7 @@ class AWSAction(Action):
|
|
|
371
372
|
aws_service: str,
|
|
372
373
|
aws_command: str,
|
|
373
374
|
pagination_helper: PaginationHelper = None,
|
|
375
|
+
close_client: bool = None,
|
|
374
376
|
):
|
|
375
377
|
"""
|
|
376
378
|
|
|
@@ -382,6 +384,8 @@ class AWSAction(Action):
|
|
|
382
384
|
:param output: The output schema object
|
|
383
385
|
:param aws_service: The AWS service. Should be snake case.
|
|
384
386
|
:param aws_command: The type of request to invoke. Should be snake case.
|
|
387
|
+
:param pagination_helper: Paginating helper indicate attrs like max_pages and token location.
|
|
388
|
+
:param close_client: Determine if the created client should be closed at the end of the action.
|
|
385
389
|
"""
|
|
386
390
|
|
|
387
391
|
super().__init__(
|
|
@@ -391,6 +395,11 @@ class AWSAction(Action):
|
|
|
391
395
|
self.aws_command = aws_command
|
|
392
396
|
self.pagination_helper = pagination_helper
|
|
393
397
|
|
|
398
|
+
# when running in cloud mode we won't hold this connection, so each call to action.run() will spawn a new
|
|
399
|
+
# client, in this case we should close the client unless otherwise specified. A use case to not close
|
|
400
|
+
# is on a task plugin that re-uses the client for list_objects_v2 and get_bucket_content.
|
|
401
|
+
self.close_client = is_running_in_cloud() if close_client is None else close_client
|
|
402
|
+
|
|
394
403
|
def _handle_botocore_function(
|
|
395
404
|
self, client_function: Callable, params: Dict
|
|
396
405
|
) -> Dict:
|
|
@@ -441,6 +450,9 @@ class AWSAction(Action):
|
|
|
441
450
|
raise PluginException(
|
|
442
451
|
cause="Error occurred when invoking the aws-cli.", data=error
|
|
443
452
|
)
|
|
453
|
+
finally:
|
|
454
|
+
if self.close_client:
|
|
455
|
+
self.connection.client.close()
|
|
444
456
|
return response
|
|
445
457
|
|
|
446
458
|
def _handle_format_output(self, response: Dict, helper: ActionHelper) -> Dict:
|
|
@@ -542,6 +554,9 @@ class AWSAction(Action):
|
|
|
542
554
|
if not self.pagination_helper.max_pages:
|
|
543
555
|
self.pagination_helper.remove_keys(response)
|
|
544
556
|
|
|
557
|
+
if self.close_client:
|
|
558
|
+
self.connection.client.close()
|
|
559
|
+
|
|
545
560
|
return response
|
|
546
561
|
|
|
547
562
|
def test(self, params={}):
|
|
@@ -610,14 +625,14 @@ class AWSAction(Action):
|
|
|
610
625
|
}
|
|
611
626
|
)
|
|
612
627
|
)
|
|
628
|
+
sts_client.close()
|
|
613
629
|
except ClientError as error:
|
|
614
630
|
raise PluginException(
|
|
615
631
|
cause=f"Boto3 raised following error during assume role: {error.response['Error']['Code']}",
|
|
616
632
|
assistance="Please verify your role ARN and external ID are correct",
|
|
617
633
|
)
|
|
618
634
|
credentials = assumed_role_object["Credentials"]
|
|
619
|
-
|
|
620
|
-
boto_session = session.create_client(
|
|
635
|
+
boto_client = boto3.client(
|
|
621
636
|
service_name,
|
|
622
637
|
aws_access_key_id=credentials["AccessKeyId"],
|
|
623
638
|
aws_secret_access_key=credentials["SecretAccessKey"],
|
|
@@ -625,4 +640,4 @@ class AWSAction(Action):
|
|
|
625
640
|
region_name=assume_role_params[REGION],
|
|
626
641
|
)
|
|
627
642
|
|
|
628
|
-
return
|
|
643
|
+
return boto_client
|
|
@@ -71,7 +71,7 @@ def hash_sha1(log: Dict[str, Any], keys: Optional[List[str]] = None) -> str:
|
|
|
71
71
|
|
|
72
72
|
# Iterate through items to hash and hash
|
|
73
73
|
for key, value in items_to_hash:
|
|
74
|
-
hash_.update(f"{key}{value}".encode(ENCODE_TYPE))
|
|
74
|
+
hash_.update(f"{key}{value}".encode(ENCODE_TYPE, errors="ignore"))
|
|
75
75
|
|
|
76
76
|
return hash_.hexdigest()
|
|
77
77
|
|
|
@@ -11,7 +11,7 @@ from apispec.ext.marshmallow import MarshmallowPlugin
|
|
|
11
11
|
from apispec_webframeworks.flask import FlaskPlugin
|
|
12
12
|
from flask import Flask, request_started, request
|
|
13
13
|
from gunicorn.arbiter import Arbiter
|
|
14
|
-
from pythonjsonlogger.jsonlogger import JsonFormatter
|
|
14
|
+
from pythonjsonlogger.jsonlogger import JsonFormatter, RESERVED_ATTRS
|
|
15
15
|
from requests import get as request_get
|
|
16
16
|
from requests.exceptions import (
|
|
17
17
|
HTTPError,
|
|
@@ -146,7 +146,8 @@ class PluginServer(gunicorn.app.base.BaseApplication):
|
|
|
146
146
|
console_handler = logging.StreamHandler()
|
|
147
147
|
if is_running_in_cloud():
|
|
148
148
|
console_handler.setFormatter(
|
|
149
|
-
|
|
149
|
+
# since python bump to 3.13 the logging lib now includes a bunch of extra keywords we want to discard
|
|
150
|
+
JsonFormatter(reserved_attrs=RESERVED_ATTRS + ("taskName",))
|
|
150
151
|
) # Only log in JSON if running in cloud
|
|
151
152
|
|
|
152
153
|
logger.addHandler(console_handler)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: insightconnect-plugin-runtime
|
|
3
|
-
Version: 6.4.
|
|
3
|
+
Version: 6.4.2
|
|
4
4
|
Summary: InsightConnect Plugin Runtime
|
|
5
5
|
Home-page: https://github.com/rapid7/komand-plugin-sdk-python
|
|
6
6
|
Author: Rapid7 Integrations Alliance
|
|
@@ -12,27 +12,27 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
12
12
|
Classifier: Natural Language :: English
|
|
13
13
|
Classifier: Topic :: Software Development :: Build Tools
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
|
-
Requires-Dist: requests==2.32.
|
|
15
|
+
Requires-Dist: requests==2.32.5
|
|
16
16
|
Requires-Dist: python_jsonschema_objects==0.5.2
|
|
17
17
|
Requires-Dist: jsonschema==4.22.0
|
|
18
|
-
Requires-Dist: certifi==
|
|
19
|
-
Requires-Dist: Flask==3.1.
|
|
18
|
+
Requires-Dist: certifi==2026.1.4
|
|
19
|
+
Requires-Dist: Flask==3.1.2
|
|
20
20
|
Requires-Dist: gunicorn==23.0.0
|
|
21
|
-
Requires-Dist: greenlet==3.
|
|
21
|
+
Requires-Dist: greenlet==3.3.0
|
|
22
22
|
Requires-Dist: gevent==25.5.1
|
|
23
|
-
Requires-Dist: marshmallow==3.
|
|
23
|
+
Requires-Dist: marshmallow==3.26.2
|
|
24
24
|
Requires-Dist: apispec==6.5.0
|
|
25
25
|
Requires-Dist: apispec-webframeworks==1.0.0
|
|
26
26
|
Requires-Dist: blinker==1.9.0
|
|
27
|
-
Requires-Dist: structlog==25.
|
|
27
|
+
Requires-Dist: structlog==25.5.0
|
|
28
28
|
Requires-Dist: python-json-logger==2.0.7
|
|
29
29
|
Requires-Dist: Jinja2==3.1.6
|
|
30
30
|
Requires-Dist: python-dateutil==2.9.0.post0
|
|
31
|
-
Requires-Dist: opentelemetry-sdk==1.
|
|
32
|
-
Requires-Dist: opentelemetry-instrumentation-flask==0.
|
|
33
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.
|
|
34
|
-
Requires-Dist: opentelemetry-instrumentation-requests==0.
|
|
35
|
-
Requires-Dist: urllib3==2.
|
|
31
|
+
Requires-Dist: opentelemetry-sdk==1.39.1
|
|
32
|
+
Requires-Dist: opentelemetry-instrumentation-flask==0.60b1
|
|
33
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.39.1
|
|
34
|
+
Requires-Dist: opentelemetry-instrumentation-requests==0.60b1
|
|
35
|
+
Requires-Dist: urllib3==2.6.3
|
|
36
36
|
Dynamic: author
|
|
37
37
|
Dynamic: author-email
|
|
38
38
|
Dynamic: classifier
|
|
@@ -63,10 +63,10 @@ to get started.
|
|
|
63
63
|
|
|
64
64
|
## Development of the InsightConnect Plugin Runtime
|
|
65
65
|
|
|
66
|
-
The Python Runtime codebase is built to support Python 3.
|
|
66
|
+
The Python Runtime codebase is built to support Python 3.13 as of version 6.4.0. The following dependencies will need
|
|
67
67
|
to be installed when developing or testing the Plugin Runtime:
|
|
68
68
|
|
|
69
|
-
- Python 3.11
|
|
69
|
+
- Python 3.13.11
|
|
70
70
|
- Docker
|
|
71
71
|
- make
|
|
72
72
|
- tox
|
|
@@ -226,6 +226,8 @@ contributed. Black is installed as a test dependency and the hook can be initial
|
|
|
226
226
|
after cloning this repository.
|
|
227
227
|
|
|
228
228
|
## Changelog
|
|
229
|
+
* 6.4.2 - Added error handling for `hash_sha1` in helpers | Updated base images to Python 3.13.11 | Updated dependencies
|
|
230
|
+
* 6.4.1 - Fix logging on cloud mode to remove `taskName` | Close boto client after assuming role
|
|
229
231
|
* 6.4.0 - When running in cloud mode, always create a new connection object | Bump Python version to 3.13.9 | Docker build tidyup to reduce image size
|
|
230
232
|
* 6.3.10 - Fixed tracing name to better allign otel standards
|
|
231
233
|
* 6.3.9 - Fixed `monitor_task_delay` decorator handling of millisecond epoch timestamps | Allow `test_task` connection method to accept task name parameter | Updated base images to Python 3.11.13
|
|
@@ -4,11 +4,11 @@ insightconnect_plugin_runtime/cli.py,sha256=Pb-Janu-XfRlSXxPHh30OIquljWptrhhS51C
|
|
|
4
4
|
insightconnect_plugin_runtime/connection.py,sha256=4uWclDTFSKZXbvzrq2VGwIM0_o54XaqHeGje3IMFCSA,2672
|
|
5
5
|
insightconnect_plugin_runtime/dispatcher.py,sha256=ru7njnyyWE1-oD-VbZJ-Z8tELwvDf69rM7Iezs4rbnw,1774
|
|
6
6
|
insightconnect_plugin_runtime/exceptions.py,sha256=LeZR2H_seHIUALLwnKyH5W7PX3VNa-lOTxJ0vZJra8I,8068
|
|
7
|
-
insightconnect_plugin_runtime/helper.py,sha256=
|
|
7
|
+
insightconnect_plugin_runtime/helper.py,sha256=saD2Vl_9Pt86pmrQOc5FvjjJAcHl5wgmKkcbyS8c4gE,34011
|
|
8
8
|
insightconnect_plugin_runtime/metrics.py,sha256=hf_Aoufip_s4k4o8Gtzz90ymZthkaT2e5sXh5B4LcF0,3186
|
|
9
9
|
insightconnect_plugin_runtime/plugin.py,sha256=5CNxVAmiAwdEXviBU-_oA3_Ud03PYO_fs-ph9x_2yO0,27286
|
|
10
10
|
insightconnect_plugin_runtime/schema.py,sha256=6MVw5hqGATU1VLgwfOWfPsP3hy1OnsugCTsgX8sknes,521
|
|
11
|
-
insightconnect_plugin_runtime/server.py,sha256=
|
|
11
|
+
insightconnect_plugin_runtime/server.py,sha256=OCJ_cr3y744RaDhuwoOclzdVSQzbn42Me7s2hh7HUJc,13317
|
|
12
12
|
insightconnect_plugin_runtime/step.py,sha256=KdERg-789-s99IEKN61DR08naz-YPxyinPT0C_T81C4,855
|
|
13
13
|
insightconnect_plugin_runtime/task.py,sha256=d-H1EAzVnmSdDEJtXyIK5JySprxpF9cetVoFGtWlHrg,123
|
|
14
14
|
insightconnect_plugin_runtime/telemetry.py,sha256=ZOG4Gv9o4JgO46RbqIsSkWSMuQnbfTnmgc5WURe5FTs,8026
|
|
@@ -19,7 +19,7 @@ insightconnect_plugin_runtime/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
|
|
|
19
19
|
insightconnect_plugin_runtime/api/endpoints.py,sha256=ddqqYM7s1huvXFD0nCjpV_J2XULDn8F5sRakdjq-AKU,38893
|
|
20
20
|
insightconnect_plugin_runtime/api/schemas.py,sha256=jRmDrwLJTBl-iQOnyZkSwyJlCWg4eNjAnKfD9Eko4z0,2754
|
|
21
21
|
insightconnect_plugin_runtime/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
insightconnect_plugin_runtime/clients/aws_client.py,sha256=
|
|
22
|
+
insightconnect_plugin_runtime/clients/aws_client.py,sha256=BTQ-NTIRr08K-AezA62ADSXxv06SwghF4NFyPN3K9-A,23931
|
|
23
23
|
insightconnect_plugin_runtime/clients/oauth.py,sha256=bWtAGRMwdK4dw9vMPcw9usklyIHBDtZh55kMZ7sWROc,2453
|
|
24
24
|
insightconnect_plugin_runtime/data/input_message_schema.json,sha256=7_BcHi6UOBiVWGrrJHHn5IoddteXjL7GOKETdO9T2DE,1770
|
|
25
25
|
insightconnect_plugin_runtime/data/output_message_schema.json,sha256=Qya6U-NR5MfOlw4V98VpQzGBVq75eGMUQhI-j3yxOHI,1137
|
|
@@ -65,8 +65,8 @@ tests/plugin/hello_world/tests/test_server.py,sha256=7QfMNVsNcRoX5aAL0xM9tXS-ciy
|
|
|
65
65
|
tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
66
|
tests/unit/test_action.py,sha256=0SVen1qNrFLKKAXMurN9T4NpItpftnSpDZ71AdrGZeo,1683
|
|
67
67
|
tests/unit/test_api.py,sha256=uZ1dWMmgQ-ZePYjmcZfjc-qOTJsjs20Wic0Uf4U12-8,4441
|
|
68
|
-
tests/unit/test_aws_action.py,sha256=
|
|
69
|
-
tests/unit/test_connection.py,sha256=
|
|
68
|
+
tests/unit/test_aws_action.py,sha256=qsDP56m5mWNYTyck4I3udgj__ZbJqByHeDCbM5_F98U,13379
|
|
69
|
+
tests/unit/test_connection.py,sha256=AOQm1PYkaqXK22evyjKV4_ZsdgUeIbXQ0pt6vmzphK4,5832
|
|
70
70
|
tests/unit/test_custom_encoder.py,sha256=KLYyVOTq9MEkZXyhVHqjm5LVSW6uJS4Davgghsw9DGk,2207
|
|
71
71
|
tests/unit/test_endpoints.py,sha256=Ef0f6EudnAA_o6jZJ7rvgwgQHHswPuBEiyyo1D7BWMc,11523
|
|
72
72
|
tests/unit/test_exceptions.py,sha256=Y4F-ij8WkEJkUU3mPvxlEchqE9NCdxDvR8bJzPVVNao,5328
|
|
@@ -80,7 +80,7 @@ tests/unit/test_server_spec.py,sha256=je97BaktgK0Fiz3AwFPkcmHzYtOJJNqJV_Fw5hrvqX
|
|
|
80
80
|
tests/unit/test_trigger.py,sha256=E53mAUoVyponWu_4IQZ0IC1gQ9lakBnTn_9vKN2IZfg,1692
|
|
81
81
|
tests/unit/test_variables.py,sha256=OUEOqGYZA3Nd5oKk5GVY3hcrWKHpZpxysBJcO_v5gzs,291
|
|
82
82
|
tests/unit/utils.py,sha256=hcY0A2H_DMgCDXUTvDtCXMdMvRjLQgTaGcTpATb8YG0,2236
|
|
83
|
-
insightconnect_plugin_runtime-6.4.
|
|
84
|
-
insightconnect_plugin_runtime-6.4.
|
|
85
|
-
insightconnect_plugin_runtime-6.4.
|
|
86
|
-
insightconnect_plugin_runtime-6.4.
|
|
83
|
+
insightconnect_plugin_runtime-6.4.2.dist-info/METADATA,sha256=ZIS-QYMiVGgGODEBRwOXRq_2dk5dx2rQ9frEWS0NX5I,17628
|
|
84
|
+
insightconnect_plugin_runtime-6.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
85
|
+
insightconnect_plugin_runtime-6.4.2.dist-info/top_level.txt,sha256=AJtyJOpiFzHxsbHUICTcUKXyrGQ3tZxhrEHsPjJBvEA,36
|
|
86
|
+
insightconnect_plugin_runtime-6.4.2.dist-info/RECORD,,
|
tests/unit/test_aws_action.py
CHANGED
|
@@ -3,6 +3,7 @@ import io
|
|
|
3
3
|
import json
|
|
4
4
|
import unittest
|
|
5
5
|
import unittest.mock
|
|
6
|
+
from os import environ
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
import botocore.exceptions as be
|
|
@@ -28,6 +29,10 @@ class Boto3Stub:
|
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
def close(self):
|
|
33
|
+
# stub for closing the sts client after assuming the role
|
|
34
|
+
pass
|
|
35
|
+
|
|
31
36
|
|
|
32
37
|
class TestAwsAction(unittest.TestCase):
|
|
33
38
|
def setUp(self) -> None:
|
|
@@ -37,6 +42,12 @@ class TestAwsAction(unittest.TestCase):
|
|
|
37
42
|
}
|
|
38
43
|
self.region = "us-east"
|
|
39
44
|
|
|
45
|
+
self.assume_role_params = {
|
|
46
|
+
"role_arn": "test_role",
|
|
47
|
+
"external_id": "test_id",
|
|
48
|
+
"region": "test-region",
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
self.aws_action = AWSAction(
|
|
41
52
|
"NewAction", "Description", None, None, "ec2", "service"
|
|
42
53
|
)
|
|
@@ -45,19 +56,11 @@ class TestAwsAction(unittest.TestCase):
|
|
|
45
56
|
self.aws_action.input = Input({})
|
|
46
57
|
self.aws_action.output = Output({})
|
|
47
58
|
|
|
48
|
-
@unittest.mock.patch("botocore.session.Session", return_value=unittest.mock.Mock())
|
|
49
59
|
@unittest.mock.patch("boto3.client", return_value=Boto3Stub())
|
|
50
|
-
def test_assume_role(self,
|
|
51
|
-
assume_role_params
|
|
52
|
-
"role_arn": "test_role",
|
|
53
|
-
"external_id": "test_id",
|
|
54
|
-
"region": "test-region",
|
|
55
|
-
}
|
|
56
|
-
aws_session = unittest.mock.Mock()
|
|
57
|
-
|
|
58
|
-
AWSAction.try_to_assume_role("ec2", assume_role_params, self.auth_params)
|
|
60
|
+
def test_assume_role(self, mock_sts_client):
|
|
61
|
+
AWSAction.try_to_assume_role("ec2", self.assume_role_params, self.auth_params)
|
|
59
62
|
|
|
60
|
-
mock_sts_client.
|
|
63
|
+
self.assertEqual(mock_sts_client.call_count, 2) # twice for assume role and create client afterwards
|
|
61
64
|
|
|
62
65
|
@unittest.mock.patch("botocore.session.Session", return_value=unittest.mock.Mock())
|
|
63
66
|
@unittest.mock.patch("boto3.client", return_value=Boto3Stub())
|
|
@@ -135,6 +138,58 @@ class TestAwsAction(unittest.TestCase):
|
|
|
135
138
|
with self.assertRaises(PluginException):
|
|
136
139
|
self.aws_action.handle_rest_call(mock_call, {})
|
|
137
140
|
|
|
141
|
+
@unittest.mock.patch.dict(environ, {"PLUGIN_RUNTIME_ENVIRONMENT": "orchestrator"})
|
|
142
|
+
@unittest.mock.patch.object(AWSAction, "handle_rest_call", return_value={"mock_key": "mock_value"})
|
|
143
|
+
def test_run_client_non_cloud_mode_in_action_default_behaviour(self, _mock_handle_rest_call):
|
|
144
|
+
# Test AWSAction called for customers running on an orchestrator that their client can remain open
|
|
145
|
+
aws_action = AWSAction("NewAction", "Description", None, None, "s3", "service")
|
|
146
|
+
aws_action.connection = unittest.mock.create_autospec(Connection)
|
|
147
|
+
aws_action.connection.assume_role_params = self.assume_role_params
|
|
148
|
+
aws_action.connection.auth_params = self.auth_params
|
|
149
|
+
aws_action.connection.client = unittest.mock.create_autospec(Boto3Stub)
|
|
150
|
+
aws_action.connection.client.service = unittest.mock.MagicMock()
|
|
151
|
+
aws_action.run()
|
|
152
|
+
aws_action.connection.client.close.assert_not_called()
|
|
153
|
+
|
|
154
|
+
@unittest.mock.patch.dict(environ, {"PLUGIN_RUNTIME_ENVIRONMENT": "cloud"})
|
|
155
|
+
@unittest.mock.patch.object(AWSAction, "handle_rest_call", return_value={"mock_key": "mock_value"})
|
|
156
|
+
def test_run_client_cloud_mode_in_normal_action(self, _mock_handle_rest_call):
|
|
157
|
+
# Test the same AWSAction as above but now running in cloud - we should close this client
|
|
158
|
+
aws_action = AWSAction("NewAction", "Description", None, None, "s3", "service")
|
|
159
|
+
aws_action.connection = unittest.mock.create_autospec(Connection)
|
|
160
|
+
aws_action.connection.assume_role_params = self.assume_role_params
|
|
161
|
+
aws_action.connection.auth_params = self.auth_params
|
|
162
|
+
aws_action.connection.client = unittest.mock.create_autospec(Boto3Stub)
|
|
163
|
+
aws_action.connection.client.service = unittest.mock.MagicMock()
|
|
164
|
+
aws_action.run()
|
|
165
|
+
aws_action.connection.client.close.assert_called_once()
|
|
166
|
+
|
|
167
|
+
@unittest.mock.patch.dict(environ, {"PLUGIN_RUNTIME_ENVIRONMENT": "orchestrator"})
|
|
168
|
+
@unittest.mock.patch.object(AWSAction, "handle_rest_call", return_value={"mock_key": "mock_value"})
|
|
169
|
+
def test_run_client_non_cloud_mode_in_action_default_override(self, _mock_handle_rest_call):
|
|
170
|
+
# Test AWSAction when we have specified to close the client
|
|
171
|
+
aws_action = AWSAction("NewAction", "Description", None, None, "s3", "service", close_client=True)
|
|
172
|
+
aws_action.connection = unittest.mock.create_autospec(Connection)
|
|
173
|
+
aws_action.connection.assume_role_params = self.assume_role_params
|
|
174
|
+
aws_action.connection.auth_params = self.auth_params
|
|
175
|
+
aws_action.connection.client = unittest.mock.create_autospec(Boto3Stub)
|
|
176
|
+
aws_action.connection.client.service = unittest.mock.MagicMock()
|
|
177
|
+
aws_action.run()
|
|
178
|
+
aws_action.connection.client.close.assert_called_once()
|
|
179
|
+
|
|
180
|
+
@unittest.mock.patch.dict(environ, {"PLUGIN_RUNTIME_ENVIRONMENT": "cloud"})
|
|
181
|
+
@unittest.mock.patch.object(AWSAction, "handle_rest_call", return_value={"mock_key": "mock_value"})
|
|
182
|
+
def test_run_client_cloud_mode_in_typical_c2c_task(self, _mock_handle_rest_call):
|
|
183
|
+
# Test AWSAction used within a C2C task, we want to keep the client for subsequent calls
|
|
184
|
+
aws_action = AWSAction("NewAction", "Description", None, None, "s3", "service", close_client=False)
|
|
185
|
+
aws_action.connection = unittest.mock.create_autospec(Connection)
|
|
186
|
+
aws_action.connection.assume_role_params = self.assume_role_params
|
|
187
|
+
aws_action.connection.auth_params = self.auth_params
|
|
188
|
+
aws_action.connection.client = unittest.mock.create_autospec(Boto3Stub)
|
|
189
|
+
aws_action.connection.client.service = unittest.mock.MagicMock()
|
|
190
|
+
aws_action.run()
|
|
191
|
+
aws_action.connection.client.close.assert_not_called()
|
|
192
|
+
|
|
138
193
|
def mocked_requests_get(*args, **kwargs):
|
|
139
194
|
class MockResponse:
|
|
140
195
|
def __init__(self, json_data, status_code):
|
tests/unit/test_connection.py
CHANGED
|
@@ -64,7 +64,7 @@ class TestCloudConnections(TestCase):
|
|
|
64
64
|
def test_running_onprem_has_cached_connection(self):
|
|
65
65
|
conn = self.connection_cache.get(self.connection, self.logger)
|
|
66
66
|
self.assertEqual(conn.parameters, self.connection)
|
|
67
|
-
self.
|
|
67
|
+
self.assertNotEqual(self.connection_cache.connections, {})
|
|
68
68
|
|
|
69
69
|
# the connection cache key should exist
|
|
70
70
|
hashed_key = key(conn.parameters)
|
|
@@ -81,13 +81,13 @@ class TestCloudConnections(TestCase):
|
|
|
81
81
|
# first call the connection cache for the first time adding a new entry
|
|
82
82
|
conn = self.connection_cache.get(self.connection, self.logger)
|
|
83
83
|
self.assertEqual(len(self.connection_cache.connections), 1)
|
|
84
|
-
self.
|
|
85
|
-
self.
|
|
84
|
+
self.assertEqual(list(self.connection_cache.connections.values())[0], pretend_obj)
|
|
85
|
+
self.assertEqual(conn, pretend_obj)
|
|
86
86
|
self.assertEqual(stub_key.call_count, 1)
|
|
87
87
|
|
|
88
88
|
# on a second call we get the same value but the create_and_validate shouldn't be called again
|
|
89
89
|
conn2 = self.connection_cache.get(self.connection, self.logger)
|
|
90
|
-
self.
|
|
90
|
+
self.assertEqual(conn, conn2)
|
|
91
91
|
stub_create.assert_called_once_with(self.connection, self.logger)
|
|
92
92
|
|
|
93
93
|
# on a third call we add a new entry to the cached connections
|
|
@@ -103,11 +103,11 @@ class TestCloudConnections(TestCase):
|
|
|
103
103
|
_conn = self.connection_cache.get(self.connection, self.logger)
|
|
104
104
|
|
|
105
105
|
# this means the connection object is not saved in cache
|
|
106
|
-
self.
|
|
106
|
+
self.assertEqual(self.connection_cache.connections, {})
|
|
107
107
|
|
|
108
108
|
def test_connection_validation_raised(self):
|
|
109
109
|
with self.assertRaises(Exception): # not the expected input to match the connection schema
|
|
110
110
|
_conn = self.connection_cache.get({"not_expected_key": "value"}, self.logger)
|
|
111
111
|
|
|
112
112
|
# this means the connection object is not saved in cache
|
|
113
|
-
self.
|
|
113
|
+
self.assertEqual(self.connection_cache.connections, {})
|
|
File without changes
|
|
File without changes
|