-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(RHINENG-5484): refactor operating_system filter #2141
base: master
Are you sure you want to change the base?
refactor(RHINENG-5484): refactor operating_system filter #2141
Conversation
e870dce
to
fde51a7
Compare
I added some commits I was not supposed to, I'm fixing it |
fde51a7
to
4f60130
Compare
api/filtering/db_custom_filters.py
Outdated
for os_name in filter_param.keys(): # this doesn't account for "os_name" instead of os names | ||
if os_name not in (os_names := _get_valid_os_names()): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend checking for the key "name" between these 2 lines and doing the custom logic there:
for os_name in filter_param.keys(): # this doesn't account for "os_name" instead of os names | |
if os_name not in (os_names := _get_valid_os_names()): | |
for os_name in filter_param.keys(): | |
if os_name == "name": | |
# Return an OsComparison object that implies all hosts with a matching OS name. | |
# Maybe if OsComparison.comparator is "eq" or "neq" and the major version is None? | |
elif os_name not in (os_names := _get_valid_os_names()): |
api/filtering/db_custom_filters.py
Outdated
@@ -158,6 +169,7 @@ def build_operating_system_filter(filter_param: dict) -> tuple: | |||
os_filter_list.append(os_field.astext.operate(comparator, None)) | |||
|
|||
elif comparison.comparator == "eq": | |||
print("~~~~~~~~~~~~~~~~~~~``", os_field["name"].astext == comparison.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Around here is where you'd convert the OsComparison to an actual DB operation. If we went with the logic I posted above, this next section could be something like this:
print("~~~~~~~~~~~~~~~~~~~``", os_field["name"].astext == comparison.name) | |
os_filters = [ | |
os_field["name"].astext == comparison.name, | |
] | |
if comparison.major is not None: | |
os_filters.append(os_field["major"].astext.cast(Integer) == comparison.major) | |
if comparison.minor: | |
os_filters.append(os_field["minor"].astext.cast(Integer) == comparison.minor) | |
os_filter_list.append(and_(*os_filters)) |
Of course, you'll need to handle "neq" as well :)
0a82b53
to
d58cfc1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly looking good, got a few suggestions. Also, reminder that we'll need to update the documentation as well so people know how to use the filter in this way.
api/filtering/db_custom_filters.py
Outdated
# case insensitive | ||
if real_os_name.lower() not in (os_names := [name.lower() for name in _get_valid_os_names()]): | ||
raise ValidationException(f"operating_system filter only supports these OS names: {os_names}.") | ||
return [OsComparison(real_os_name, comparator, None)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a return statement here will make it so other provided OS filters are ignored. For instance, if the request happens to be ?filter[system_profile][operating_system][name][eq]=RHEL&filter[system_profile][operating_system][RHEL][version][gte]=8
, it will no longer filter on the major version. Instead, the comparison should be appended to os_filter_list
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kruai I guess I need to adjust the logic a little bit or maybe ?filter[system_profile][operating_system][name][eq]=RHEL&filter[system_profile][operating_system][RHEL][version][gte]=8
doesn't make sense. I'm saying this because the query came out like this:
AND (lower(((hbi.hosts.system_profile_facts["operating_system"]) ->> "name")) = "rhel"
AND CAST(((hbi.hosts.system_profile_facts["operating_system"]) ->> "major") AS INTEGER) = "8"
OR lower(((hbi.hosts.system_profile_facts["operating_system"]) ->> "name")) = "rhel")
If someone is looking for RHEL, and they want to specify a version, it's unnecessary to add filter[system_profile][operating_system][name][eq]=RHEL
this is with the return statement as it is. If I just append to the filter list the request returns 500
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's for sure redundant and they shouldn't provide a query like that. But if they do, we should be able to handle it imo.
HTTP 500 just means there was an unhandled exception on our end; what does the exception say in the logs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File "/home/fabriciadiniz/dev/insights-host-inventory/api/filtering/db_custom_filters.py", line 131, in separate_operating_system_filters
if not isinstance(version_node := filter_param[os_name]["version"], dict):
KeyError: 'version'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense - once you add the filter to the list, you don't want to run the rest of the code that generates the usual OS filter. You could just put the rest in an else
, but I feel like we can also simplify it a bit. I'll play around with it a bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@FabriciaDinizRH Suggestion for the code flow: FabriciaDinizRH#1
(Feel free to reject it or tweak as necessary ofc)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
api/filtering/db_custom_filters.py
Outdated
if real_os_name.lower() not in (os_names := [name.lower() for name in _get_valid_os_names()]): | ||
raise ValidationException(f"operating_system filter only supports these OS names: {os_names}.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DRY with the code directly below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for this I can either use pass
instead of raising the validation in the first if and it will be caught in the second if (because "name" is not a supported OS name), or I can extract the raise ValidationException into a function and call it in both ifs. wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If using raise...
, should there be a test asserting for this exception?
api/filtering/db_custom_filters.py
Outdated
@@ -117,7 +118,15 @@ def separate_operating_system_filters(filter_param) -> list[OsComparison]: | |||
|
|||
# filter_param is a dict | |||
for os_name in filter_param.keys(): | |||
if os_name not in (os_names := _get_valid_os_names()): | |||
# [operating_system][name][eq]==real_os_name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# [operating_system][name][eq]==real_os_name |
("[name][eq]=CentOS", True), | ||
("[name][eq]=centos", True), | ||
("[name][eq]=CENTOS", True), | ||
("[name][eq]=centos&filter[system_profile][operating_system][RHEL][version][eq][]=8", True), | ||
("[name][neq]=CENTOS", False), | ||
("[name][neq]=CentOS", False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could use another test to validate the scenario I mentioned above. For example, ?filter[system_profile][operating_system][name][eq]=RHEL&filter[system_profile][operating_system][RHEL][version][eq]=9
should not match either of the host data in this test
api/filtering/db_custom_filters.py
Outdated
@@ -117,7 +118,15 @@ def separate_operating_system_filters(filter_param) -> list[OsComparison]: | |||
|
|||
# filter_param is a dict | |||
for os_name in filter_param.keys(): | |||
if os_name not in (os_names := _get_valid_os_names()): | |||
# [operating_system][name][eq]==real_os_name | |||
if os_name == "name": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename the variable os_name
to key
, which is what is being checked. A name like os_name
causes confusion when a key is being checked NOT its value.
api/filtering/db_custom_filters.py
Outdated
if real_os_name.lower() not in (os_names := [name.lower() for name in _get_valid_os_names()]): | ||
raise ValidationException(f"operating_system filter only supports these OS names: {os_names}.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If using raise...
, should there be a test asserting for this exception?
/retest |
a781377
to
1adf118
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Overview
This PR is being created to address RHINENG-5484.
PR Checklist
Secure Coding Practices Documentation Reference
You can find documentation on this checklist here.
Secure Coding Checklist