Repository navigation
Conversation
|
The 03:20 TASK [ansible-galaxy-collection : ensure we can download the published collection - pulp_v2] ***
03:21 fatal: [testhost]: FAILED! => {"changed": true, "cmd": ["ansible-galaxy", "collection", "install", "-s", "pulp_v2", "-p", "/tmp/ansible.mk27mu05.test/publish/pulp_v2", "ansible_test.my_collection==1.0.0", "-v"], "delta": "0:00:00.470485", "end": "2023-12-11 13:56:52.273680", "msg": "non-zero return code", "rc": 1, "start": "2023-12-11 13:56:51.803195", "stderr": "\u001b[1;35m[WARNING]: The specified \"api_version\" configuration for the galaxy server\u001b[0m\n\u001b[1;35m\"pulp_v2\" is not a public configuration, and may be removed at any time without\u001b[0m\n\u001b[1;35mwarning.\u001b[0m\n\u001b[1;35m[WARNING]: The specified collections path\u001b[0m\n\u001b[1;35m'/tmp/ansible.mk27mu05.test/publish/pulp_v2' is not part of the configured\u001b[0m\n\u001b[1;35mAnsible collections paths\u001b[0m\n\u001b[1;35m'/root/.ansible/collections:/usr/share/ansible/collections'. The installed\u001b[0m\n\u001b[1;35mcollection will not be picked up in an Ansible run, unless within a playbook-\u001b[0m\n\u001b[1;35madjacent collections directory.\u001b[0m\n\u001b[0;31mERROR! Error when getting the collection info for ansible_test.my_collection from pulp_v2 (http://galaxy-pulp/pulp_ansible/galaxy/primary/api/) (HTTP Code: 500, Message: Internal Server Error Code: Unknown)\u001b[0m", "stderr_lines": ["\u001b[1;35m[WARNING]: The specified \"api_version\" configuration for the galaxy server\u001b[0m", "\u001b[1;35m\"pulp_v2\" is not a public configuration, and may be removed at any time without\u001b[0m", "\u001b[1;35mwarning.\u001b[0m", "\u001b[1;35m[WARNING]: The specified collections path\u001b[0m", "\u001b[1;35m'/tmp/ansible.mk27mu05.test/publish/pulp_v2' is not part of the configured\u001b[0m", "\u001b[1;35mAnsible collections paths\u001b[0m", "\u001b[1;35m'/root/.ansible/collections:/usr/share/ansible/collections'. The installed\u001b[0m", "\u001b[1;35mcollection will not be picked up in an Ansible run, unless within a playbook-\u001b[0m", "\u001b[1;35madjacent collections directory.\u001b[0m", "\u001b[0;31mERROR! Error when getting the collection info for ansible_test.my_collection from pulp_v2 (http://galaxy-pulp/pulp_ansible/galaxy/primary/api/) (HTTP Code: 500, Message: Internal Server Error Code: Unknown)\u001b[0m"], "stdout": "\u001b[0;34mUsing /tmp/ansible.mk27mu05.test/galaxy/ansible.cfg as config file\u001b[0m\nStarting galaxy collection install process\nProcess install dependency map", "stdout_lines": ["\u001b[0;34mUsing /tmp/ansible.mk27mu05.test/galaxy/ansible.cfg as config file\u001b[0m", "Starting galaxy collection install process", "Process install dependency map"]}The unescaped stderr: [WARNING]: The specified "api_version" configuration for the galaxy server
"pulp_v2" is not a public configuration, and may be removed at any time without
warning.
[WARNING]: The specified collections path
'/tmp/ansible.mk27mu05.test/publish/pulp_v2' is not part of the configured
Ansible collections paths
'/root/.ansible/collections:/usr/share/ansible/collections'. The installed
collection will not be picked up in an Ansible run, unless within a playbook-
adjacent collections directory.
ERROR! Error when getting the collection info for ansible_test.my_collection from pulp_v2 (http://galaxy-pulp/pulp_ansible/galaxy/primary/api/) (HTTP Code: 500, Message: Internal Server Error Code: Unknown) |
|
Sticking a cc @sivel FYI |
|
Seems like the only way to know for sure what is failing, is to attach to the container logs for the galaxy container, and see the traceback causing the 500 ISE and then go from there. |
|
Yeah, that's what I thought. |
|
I attached and saw it streaming things like pulp [a0feea53400f4988b47590376543557d]: django.request:ERROR: Internal Server Error: /api/galaxy/v3/plugin/ansible/content/primary/collections/index/
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
return view_func(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 497, in dispatch
self.initial(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 415, in initial
self.check_permissions(request)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 332, in check_permissions
if not permission.has_permission(request, self):
File "/usr/local/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 69, in has_permission
allowed = self._evaluate_statements(statements, request, view, action)
File "/usr/local/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 113, in _evaluate_statements
matched = self._get_statements_matching_conditions(
File "/usr/local/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 262, in _get_statements_matching_conditions
passed = self._check_condition(condition, request, view, action)
File "/usr/local/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 288, in _check_condition
result = method(request, view, action)
File "/usr/local/lib/python3.8/site-packages/galaxy_ng/app/access_control/access_policy.py", line 253, in v3_can_view_repo_content
distro = ansible_models.AnsibleDistribution.objects.get(base_path=path)
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 637, in get
raise self.model.DoesNotExist(
pulp_ansible.app.models.AnsibleDistribution.DoesNotExist: AnsibleDistribution matching query does not exist.
pulp [a0feea53400f4988b47590376543557d]: 127.0.0.1 - admin [11/Dec/2023:18:14:34 +0000] "GET /api/galaxy/v3/plugin/ansible/content/primary/collections/index/?limit=100&offset=0 HTTP/1.0" 500 145 "-" "ansible-httpget"
pulp [f01fb13dcfa242b4b291212793ad06b6]: django.request:ERROR: Internal Server Error: /api/galaxy/v3/plugin/ansible/content/secondary/collections/index/
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
return view_func(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 497, in dispatch
self.initial(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 415, in initial
self.check_permissions(request)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 332, in check_permissions
if not permission.has_permission(request, self):
File "/usr/local/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 69, in has_permission
allowed = self._evaluate_statements(statements, request, view, action)
File "/usr/local/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 113, in _evaluate_statements
matched = self._get_statements_matching_conditions(
File "/usr/local/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 262, in _get_statements_matching_conditions
passed = self._check_condition(condition, request, view, action)
File "/usr/local/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 288, in _check_condition
result = method(request, view, action)
File "/usr/local/lib/python3.8/site-packages/galaxy_ng/app/access_control/access_policy.py", line 253, in v3_can_view_repo_content
distro = ansible_models.AnsibleDistribution.objects.get(base_path=path)
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 637, in get
raise self.model.DoesNotExist(
pulp_ansible.app.models.AnsibleDistribution.DoesNotExist: AnsibleDistribution matching query does not exist.even before that download test... |
|
And this is the end of the log (I paused the test playbook after running that failing download command): pulp [0c53ee324d834cfaa90d4d605c486e87]: 127.0.0.1 - admin [11/Dec/2023:18:14:50 +0000] "POST /api/galaxy/v3/auth/token/ HTTP/1.0" 200 52 "-" "ansible-httpget"
pulp [8e4c4fd15e4544329b7495a59bce908d]: 127.0.0.1 - admin [11/Dec/2023:18:15:34 +0000] "POST /pulp_ansible/galaxy/primary/api/v2/collections/ HTTP/1.0" 202 78 "-" "ansible-galaxy/2.17.0.dev0 (Linux; python:3.12.0)"
pulp [8e4c4fd15e4544329b7495a59bce908d]: pulpcore.tasking.tasks:INFO: Starting task 018c5a17-6f71-7930-a58b-e0f94b80e573
pulp [8e4c4fd15e4544329b7495a59bce908d]: pulp_ansible.app.tasks.collections:INFO: Processing collection from tmp/files/01/8c5a17-6f65-73e8-9649-33a56a764ef7
pulp [8e4c4fd15e4544329b7495a59bce908d]: pulp_ansible.app.tasks.utils:INFO: Reading MANIFEST.json from tmp/files/01/8c5a17-6f65-73e8-9649-33a56a764ef7
pulp [8e4c4fd15e4544329b7495a59bce908d]: pulp_ansible.app.tasks.utils:INFO: Reading FILES.json from tmp/files/01/8c5a17-6f65-73e8-9649-33a56a764ef7
/usr/lib64/python3.8/tarfile.py:2230: RuntimeWarning: The default behavior of tarfile extraction has been changed to disallow common exploits (including CVE-2007-4559). By default, absolute/parent paths are disallowed and some mode bits are cleared. See https://access.redhat.com/articles/7004769 for more details.
warnings.warn(
pulp [6edadb4393614c8aa74faf59532b5b89]: 127.0.0.1 - admin [11/Dec/2023:18:15:35 +0000] "GET /pulp_ansible/galaxy/primary/api/v2/collection-imports/018c5a17-6f71-7930-a58b-e0f94b80e573/ HTTP/1.0" 200 649 "-" "ansible-galaxy/2.17.0.dev0 (Linux; python:3.12.0)"
pulp [8e4c4fd15e4544329b7495a59bce908d]: pulpcore.tasking.tasks:INFO: Task completed 018c5a17-6f71-7930-a58b-e0f94b80e573
pulp [565b91ac991b45ddbdeece69b4e8edaa]: 127.0.0.1 - admin [11/Dec/2023:18:15:37 +0000] "GET /pulp_ansible/galaxy/primary/api/v2/collection-imports/018c5a17-6f71-7930-a58b-e0f94b80e573/ HTTP/1.0" 200 676 "-" "ansible-galaxy/2.17.0.dev0 (Linux; python:3.12.0)"
pulp [be92b47f2f5c4616b9d34eb0a74694e7]: django.request:ERROR: Internal Server Error: /pulp_ansible/galaxy/primary/api/v2/collections/ansible_test/my_collection/
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
return view_func(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 104, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/pulp_ansible/app/galaxy/views.py", line 154, in get
return response.Response(GalaxyCollectionSerializer(collection, context=context).data)
File "/usr/local/lib/python3.8/site-packages/rest_framework/serializers.py", line 555, in data
ret = super().data
File "/usr/local/lib/python3.8/site-packages/rest_framework/serializers.py", line 253, in data
self._data = self.to_representation(self.instance)
File "/usr/local/lib/python3.8/site-packages/rest_framework/serializers.py", line 522, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/usr/local/lib/python3.8/site-packages/rest_framework/fields.py", line 1838, in to_representation
return method(value)
File "/usr/local/lib/python3.8/site-packages/pulp_ansible/app/galaxy/serializers.py", line 116, in get_latest_version
"version": rv.version,
AttributeError: 'NoneType' object has no attribute 'version'
pulp [be92b47f2f5c4616b9d34eb0a74694e7]: 127.0.0.1 - admin [11/Dec/2023:18:15:38 +0000] "GET /pulp_ansible/galaxy/primary/api/v2/collections/ansible_test/my_collection/ HTTP/1.0" 500 145 "-" "ansible-galaxy/2.17.0.dev0 (Linux; python:3.12.0)" |
|
Some of those may be expected. See: |
|
jeez |
|
I think this is the relevant bit File "/usr/local/lib/python3.8/site-packages/pulp_ansible/app/galaxy/serializers.py", line 116, in get_latest_version
"version": rv.version,
AttributeError: 'NoneType' object has no attribute 'version'which suggests another bug in |
8a74e33 to
ecf2426
Compare
ecf2426 to
e1b0878
Compare
This patch adjusts the metadata processing to swallow 404 and handle other cases as a cache reset request. Ref: ansible#82396 (comment)
It updates the underlying `pulp_ansible` to v0.20.2, which fixes a race condition that is occasionally observable in our CI when provisioning the initial dummy collections for testing. Refs: * https://github.com/ansible/galaxy_ng/releases/tag/4.9.0 * ansible/galaxy_ng#1950 * ansible/galaxy#3267 * pulp/pulp_ansible#1571 * pulp/pulp_ansible#1572 * pulp/pulp_ansible#1595 * pulp/pulp_ansible#1623 * pulp/pulp_ansible#1624
Co-authored-by: Sloane Hertel <19572925+s-hertel@users.noreply.github.com>
This patch adjusts the metadata processing to swallow 404 and handle other cases as a cache reset request. Ref: ansible#82396 (comment)
9a9aba3 to
cd32765
Compare
galaxy_ng to v4.9.0 in testsgalaxy_ng to v4.9.2 in tests
| if err.http_code == 404: | ||
| # No collection found, return an empty list to keep things consistent with the various APIs | ||
| return [] | ||
| elif err.http_code != 500 or 'v3' in self.available_api_versions: | ||
| raise | ||
| # No collection found, return an empty list to keep things consistent with the various APIs | ||
| return [] | ||
|
|
||
| # v2 appears to have a bug on some versions, where the metadata URL is an HTTP error 500 | ||
| # since this URL is only used to handle the cache, proceed as if the cache needs to be refreshed. | ||
| modified_date = None | ||
| if '%s.%s' % (namespace, name) in modified_cache: | ||
| del modified_cache['%s.%s' % (namespace, name)] | ||
| self._set_cache() |
There was a problem hiding this comment.
@webknjaz Since v2 GalaxyAPI is deprecated and close to removal, I'm second-guessing this. Can we just remove the v2 tests early, instead of adding code to support the lack of fully functional v2 in 4.9.2?
Or, could we keep using an older galaxy ng for v2 coverage until 2.20 development starts and we can delete everything v2?
There was a problem hiding this comment.
@s-hertel I think that coverage is a good reason to keep this. But also, I was looking forward to backporting this to reduce the CI flakiness. I feel like this might be okay to backport, but removals wouldn't be.
Should we merge+backport this and then delete whatever in follow-ups when 2.20 comes? The main value in this for me is the CI stability, which spans across several branches IIRC.
cc @mattclay would this be acceptable to backport for the sake of CI?
There was a problem hiding this comment.
Since this is a bug fix for V2, it seems like a good idea to backport it. We should continue testing V2 for versions that support it. Once we branch for 2.20 we'll be able to rip out all the V2 code and tests.
There was a problem hiding this comment.
If v2 was used by anything other than old galaxy and custom servers mimicking the v2 endpoint, I'd be more in favor of backporting this. This seems featureish for 3rd party galaxy servers, which should conform with https://old-galaxy.ansible.com v2 or GalaxyNG v3.
IMO we should not be adding more code for v2, unless it fixes issues with https://old-galaxy.ansible.com.
There was a problem hiding this comment.
@s-hertel doesn't it fix issues with our own CI where it uses v2 in old branches? How else would we address that?
There was a problem hiding this comment.
@webknjaz How will we know fixes on old branches are compatible with https://old-galaxy.ansible.com/ if we no longer test against a compatible v2? Specifying the api version is internal, so if someone's using a recent version of GalaxyNG, they'll be using v3 via the public API, not v2. We should keep backwards compat with old galaxy since that's how people use v2.
Or, could we keep using an older galaxy ng for v2 coverage until 2.20 development starts and we can delete everything v2?
Have you taken a look at which GalaxyNG version it actually breaks in and why? Can the image can be updated to a lesser extent to pull in some of the linked fixes and still work with v2?
There was a problem hiding this comment.
Dunno, I haven't looked deeper. I was originally hoping for just an image update, but these changes grew on top, as you and sivel suggested.
mattclay
left a comment
There was a problem hiding this comment.
I think this looks good overall. Since we're changing code, not just tests, this should be turned into a bugfix and have a changelog fragment.
| if err.http_code == 404: | ||
| # No collection found, return an empty list to keep things consistent with the various APIs | ||
| return [] | ||
| elif err.http_code != 500 or 'v3' in self.available_api_versions: | ||
| raise | ||
| # No collection found, return an empty list to keep things consistent with the various APIs | ||
| return [] | ||
|
|
||
| # v2 appears to have a bug on some versions, where the metadata URL is an HTTP error 500 | ||
| # since this URL is only used to handle the cache, proceed as if the cache needs to be refreshed. | ||
| modified_date = None | ||
| if '%s.%s' % (namespace, name) in modified_cache: | ||
| del modified_cache['%s.%s' % (namespace, name)] | ||
| self._set_cache() |
There was a problem hiding this comment.
Since this is a bug fix for V2, it seems like a good idea to backport it. We should continue testing V2 for versions that support it. Once we branch for 2.20 we'll be able to rip out all the V2 code and tests.
|
@mattclay no, I haven't. I guess I missed that PR. It looks like it might've fixed it. I'll keep an eye out for this test failures. |
|
@mattclay I think this is an example of said issue on |
|
@webknjaz I wasn't planning on backporting the entire PR, but it makes sense to backport the galaxy test fixes. Can you open backports for just those fixes? |
|
Looks like |
|
@mattclay this makes me think that #84763 didn't fully address the issue and merging DT made it more frequent (two jobs in the same CI run failing like this used to be rare). |
|
@webknjaz Thanks for monitoring this issue. Since the random sleep only improves the situation, rather than eliminating the it completely, it occurred to me that we could simply disable the parallel publishing in the test. If the parallel publishing is the source of this issue, then #85000 should resolve it. |
|
@mattclay thanks! It doesn't seem to have helped: #85000 (comment). Pretty sure that it is failing on cleanup, not on publishing. |
|
Yeah, this looks like a different error though -- not related to the publishing problems we were seeing. |
@mattclay perhaps we were talking about different things, then. I checked a few log links in my previous comments above, and all of them exhibit the same race condition in the pulp reset task. Here's one from today's nightly: https://dev.azure.com/ansible/ansible/_build/results?buildId=143192&view=logs&j=02bf57c0-d919-5e2d-1c94-7b4ef705afdf&t=a9b57ab5-2f0b-5a77-0352-06fbabf684da&l=5473 |
|
Now that the test isn't retrying, and isn't publishing in parallel, we're now seeing the publishing step time out instead: This timeout was occurring previously, but it was more difficult to notice because the test was being retried, and the retry failure was due to concurrency issues -- most likely because the previous publish was still running. I've opened #85016 to increase the publish timeout, to see if that's sufficient to get the tests to pass consistently. |
Looks like that did help. And you're right: I was confusing normal runs vs. reruns. |
|
Here {
"rc": 1,
"stderr": "\u001b[1;35m[WARNING]: The specified \"api_version\" configuration for the galaxy server\u001b[0m\n\u001b[1;35m\"pulp_v2\" is not a public configuration, and may be removed at any time without\u001b[0m\n\u001b[1;35mwarning.\u001b[0m\n\u001b[1;35m[WARNING]: Galaxy import warning message: No changelog found. Add a\u001b[0m\n\u001b[1;35mCHANGELOG.rst, CHANGELOG.md, or changelogs/changelog.yaml file.\u001b[0m\n\u001b[0;31mERROR! Galaxy import process failed: duplicate key value violates unique constraint \"unique_is_highest\"\u001b[0m\n\u001b[0;31mDETAIL: Key (collection_id, is_highest)=(839aeb95-f5e3-4a2e-a853-1a73a8e4767c, t) already exists.\u001b[0m\n\u001b[0;31m (Code: UNKNOWN)\u001b[0m\n",
"stdout": "Publishing collection artifact '/root/.ansible/tmp/ansible-moduletmp-1745565311.5552013-pjw5iaof/namespace1-name1-0.0.7/namespace1-name1-0.0.7.tar.gz' to galaxy_ng [http://galaxy-pulp/api/galaxy/content/primary/\nCollection](http://galaxy-pulp/api/galaxy/content/primary//nCollection) has been published to the Galaxy server galaxy_ng [http://galaxy-pulp/api/galaxy/content/primary/\nWaiting](http://galaxy-pulp/api/galaxy/content/primary//nWaiting) until Galaxy import task http://galaxy-pulp/api/galaxy/content/primary/v3/imports/collections/2b6dc0bb-d568-4d8f-bd9e-3d23598fa3ab/ has completed\n"
} |
It updates the underlying
pulp_ansibleto v0.20.2, which fixes a race condition that is occasionally observable in our CI when provisioning the initial dummy collections for testing.Refs:
is_highestupdate query can still fail since Django doesn't order the query for Postgres pulp/pulp_ansible#1623SUMMARY
$sbj.
ISSUE TYPE
ADDITIONAL INFORMATION
N/A