From c71ae95d1ea651a22213d73cb871957b2260ee21 Mon Sep 17 00:00:00 2001 From: Aziz Ahmad Date: Mon, 15 Dec 2025 10:17:16 +0000 Subject: [PATCH 1/2] ENH: Add days_threshold for errored_vm schema and correct the unittests - The email template is missing the days_threshold value - this assigns the current value of the age_filter_value to the days_threshold. --- actions/email.users.with.errored.vms.yaml | 4 +-- .../email_api/email_template_schemas.yaml | 3 +- lib/workflows/send_errored_vm_email.py | 15 +++++--- .../workflows/test_send_errored_vm_email.py | 34 +++++++++++++------ 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/actions/email.users.with.errored.vms.yaml b/actions/email.users.with.errored.vms.yaml index 9940066a1..704d94b87 100644 --- a/actions/email.users.with.errored.vms.yaml +++ b/actions/email.users.with.errored.vms.yaml @@ -33,11 +33,11 @@ parameters: description: "Comma-spaced project to limit action to - incompatible with all_projects" required: false default: null - age_filter_value: + days_threshold: type: integer description: "An integer which specifies the minimum age (in days) of the servers to be found" required: false - default: -1 + default: 60 all_projects: type: boolean description: "Tick to search in all projects - default True" diff --git a/lib/apis/email_api/email_template_schemas.yaml b/lib/apis/email_api/email_template_schemas.yaml index bab18ba68..4c8e8b130 100644 --- a/lib/apis/email_api/email_template_schemas.yaml +++ b/lib/apis/email_api/email_template_schemas.yaml @@ -80,6 +80,7 @@ errored_vm: schema: username: null error_table: "No Errored VMs" + days_threshold: "No days" html_filepath: "html/errored_vm.html.j2" plaintext_filepath: "plaintext/errored_vm.txt.j2" @@ -100,5 +101,3 @@ decom_capi_image: affected_images_table: "No Images" html_filepath: "html/decom_capi_image.html.j2" plaintext_filepath: "plaintext/decom_capi_image.txt.j2" - - diff --git a/lib/workflows/send_errored_vm_email.py b/lib/workflows/send_errored_vm_email.py index 391931d07..e46e321e2 100644 --- a/lib/workflows/send_errored_vm_email.py +++ b/lib/workflows/send_errored_vm_email.py @@ -18,6 +18,7 @@ def print_email_params( user_name: str, as_html: bool, error_table: str, + days_threshold: int, ): """ Prints email params instead of sending the email. @@ -31,12 +32,14 @@ def print_email_params( f"email_templates errored-email: username {user_name}\n" f"send as html: {as_html}\n" f"error table: {error_table}\n" + f"days_threshold: {days_threshold}\n" ) def build_email_params( user_name: str, error_table: str, + days_threshold: int, **email_kwargs, ) -> EmailParams: """ @@ -50,6 +53,7 @@ def build_email_params( template_params={ "username": user_name, "error_table": error_table, + "days_threshold": days_threshold, }, ) @@ -64,7 +68,7 @@ def send_errored_vm_email( smtp_account: SMTPAccount, cloud_account: Union[CloudDomains, str], limit_by_projects: Optional[List[str]] = None, - age_filter_value: int = -1, + days_threshold: int = 60, all_projects: bool = False, as_html: bool = False, send_email: bool = False, @@ -79,7 +83,7 @@ def send_errored_vm_email( :param smtp_account: (SMTPAccount): SMTP config :param cloud_account: String representing the cloud account to use :param limit_by_projects: A list of project names or ids to limit search in - :param age_filter_value: An integer which specifies the minimum age (in days) of the servers to be found + :param days_threshold: An integer which specifies the minimum age (in days) of the servers to be found :param all_projects: A boolean which, if True, will search in all projects :param as_html: A boolean which, if True, will send the email as html :param send_email: A boolean which, if True, will send the email instead of printing what will be sent @@ -98,7 +102,7 @@ def send_errored_vm_email( ) server_query = find_servers_with_errored_vms( - cloud_account, age_filter_value, limit_by_projects + cloud_account, days_threshold, limit_by_projects ) if not server_query.to_props(): @@ -127,7 +131,9 @@ def send_errored_vm_email( ) if not send_email: - print_email_params(send_to[0], user_name, as_html, server_list) + print_email_params( + send_to[0], user_name, as_html, server_list, days_threshold + ) continue email_params = build_email_params( @@ -135,6 +141,7 @@ def send_errored_vm_email( server_list, email_to=send_to, as_html=as_html, + days_threshold=days_threshold, email_cc=("cloud-support@stfc.ac.uk",) if cc_cloud_support else None, **email_params_kwargs, ) diff --git a/tests/lib/workflows/test_send_errored_vm_email.py b/tests/lib/workflows/test_send_errored_vm_email.py index fea0635f7..66e6dc73e 100644 --- a/tests/lib/workflows/test_send_errored_vm_email.py +++ b/tests/lib/workflows/test_send_errored_vm_email.py @@ -16,15 +16,17 @@ def test_print_email_params(): user_name = "John Doe" as_html = True error_table = "Error Table Content" + days_threshold = "Days Threshold" with patch("builtins.print") as mock_print: - print_email_params(email_addr, user_name, as_html, error_table) + print_email_params(email_addr, user_name, as_html, error_table, days_threshold) mock_print.assert_called_once_with( f"Send Email To: {email_addr}\n" f"email_templates errored-email: username {user_name}\n" f"send as html: {as_html}\n" f"error table: {error_table}\n" + f"days_threshold: {days_threshold}\n" ) @@ -40,9 +42,10 @@ def test_build_params( user_name = "John Doe" error_table = "Error Table Content" + days_threshold = "Days Threshold" email_kwargs = {"arg1": "val1", "arg2": "val2"} - res = build_email_params(user_name, error_table, **email_kwargs) + res = build_email_params(user_name, error_table, days_threshold, **email_kwargs) mock_email_template_details.assert_has_calls( [ call( @@ -50,6 +53,7 @@ def test_build_params( template_params={ "username": user_name, "error_table": error_table, + "days_threshold": days_threshold, }, ), call(template_name="footer", template_params={}), @@ -110,7 +114,7 @@ def test_send_errored_vm_email_send_plaintext( send_errored_vm_email( smtp_account=smtp_account, cloud_account=cloud_account, - age_filter_value=-1, + days_threshold=60, limit_by_projects=limit_by_projects, all_projects=all_projects, as_html=False, @@ -119,7 +123,7 @@ def test_send_errored_vm_email_send_plaintext( **mock_kwargs, ) - mock_find_servers.assert_called_once_with(cloud_account, -1, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_query.to_props.assert_called_once() mock_group_servers_by_user_id.assert_called_once_with(mock_query) mock_grouped_query.to_props.assert_called_once() @@ -137,6 +141,7 @@ def test_send_errored_vm_email_send_plaintext( mock_grouped_query.to_string.return_value, email_to=["user_email1"], as_html=False, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -145,6 +150,7 @@ def test_send_errored_vm_email_send_plaintext( mock_grouped_query.to_string.return_value, email_to=["user_email2"], as_html=False, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -210,7 +216,7 @@ def test_send_errored_vm_email_send_html( send_errored_vm_email( smtp_account=smtp_account, cloud_account=cloud_account, - age_filter_value=-1, + days_threshold=60, limit_by_projects=limit_by_projects, all_projects=all_projects, as_html=True, @@ -219,7 +225,7 @@ def test_send_errored_vm_email_send_html( **mock_kwargs, ) - mock_find_servers.assert_called_once_with(cloud_account, -1, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_query.to_props.assert_called_once() mock_group_servers_by_user_id.assert_called_once_with(mock_query) mock_grouped_query.to_props.assert_called_once() @@ -237,6 +243,7 @@ def test_send_errored_vm_email_send_html( mock_grouped_query.to_html.return_value, email_to=["user_email1"], as_html=True, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -245,6 +252,7 @@ def test_send_errored_vm_email_send_html( mock_grouped_query.to_html.return_value, email_to=["user_email2"], as_html=True, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -308,7 +316,7 @@ def test_send_errored_vm_email_print( send_errored_vm_email( smtp_account=smtp_account, cloud_account=cloud_account, - age_filter_value=-1, + days_threshold=60, limit_by_projects=limit_by_projects, all_projects=all_projects, as_html=False, @@ -317,7 +325,7 @@ def test_send_errored_vm_email_print( **mock_kwargs, ) - mock_find_servers.assert_called_once_with(cloud_account, -1, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_query.to_props.assert_called_once() mock_group_servers_by_user_id.assert_called_once_with(mock_query) mock_grouped_query.to_props.assert_called_once() @@ -335,12 +343,14 @@ def test_send_errored_vm_email_print( "user1", False, mock_grouped_query.to_string.return_value, + 60, ), call( "user_email2", "user2", False, mock_grouped_query.to_string.return_value, + 60, ), ] ) @@ -396,7 +406,7 @@ def test_send_errored_vm_email_use_override( send_errored_vm_email( smtp_account=smtp_account, cloud_account=cloud_account, - age_filter_value=-1, + days_threshold=60, limit_by_projects=limit_by_projects, all_projects=all_projects, as_html=False, @@ -406,7 +416,7 @@ def test_send_errored_vm_email_use_override( **mock_kwargs, ) - mock_find_servers.assert_called_once_with(cloud_account, -1, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_query.to_props.assert_called_once() mock_group_servers_by_user_id.assert_called_once_with(mock_query) mock_grouped_query.to_props.assert_called_once() @@ -424,6 +434,7 @@ def test_send_errored_vm_email_use_override( mock_grouped_query.to_string.return_value, email_to=[override_email_address], as_html=False, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -432,6 +443,7 @@ def test_send_errored_vm_email_use_override( mock_grouped_query.to_string.return_value, email_to=[override_email_address], as_html=False, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -476,7 +488,7 @@ def test_raise_error_when_no_matching_servers_found(mock_find_servers): all_projects=all_projects, ) - mock_find_servers.assert_called_once_with(cloud_account, -1, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_query.to_props.assert_called_once() From 05a3b004b9125150784381814b8fb9fef5b3fe9c Mon Sep 17 00:00:00 2001 From: Aziz Ahmad Date: Tue, 16 Dec 2025 14:38:30 +0000 Subject: [PATCH 2/2] ENH: Add days_threshold for shutoff_vm_email workflow - To make the email template show the number of days as days_threshold in email template which will will be provided in the action. --- actions/email.users.with.shutoff.vms.yaml | 5 +++ .../email_api/email_template_schemas.yaml | 3 +- .../templates/plaintext/shutoff_vm.txt.j2 | 2 +- .../openstack_query_api/server_queries.py | 29 +++++++++++++---- lib/workflows/send_errored_vm_email.py | 2 +- lib/workflows/send_shutoff_vm_email.py | 24 +++++++++++--- .../test_server_queries.py | 25 ++++++++++++++- .../workflows/test_send_errored_vm_email.py | 2 +- .../workflows/test_send_shutoff_vm_email.py | 32 +++++++++++++++---- 9 files changed, 101 insertions(+), 23 deletions(-) diff --git a/actions/email.users.with.shutoff.vms.yaml b/actions/email.users.with.shutoff.vms.yaml index eef1994d6..8dc3fe9aa 100644 --- a/actions/email.users.with.shutoff.vms.yaml +++ b/actions/email.users.with.shutoff.vms.yaml @@ -33,6 +33,11 @@ parameters: description: "Comma-spaced project to limit action to - incompatible with all_projects" required: false default: null + days_threshold: + type: integer + description: "An integer which specifies the minimum age (in days) of the servers to be found" + required: false + default: 60 all_projects: type: boolean description: "Tick to search in all projects - default True" diff --git a/lib/apis/email_api/email_template_schemas.yaml b/lib/apis/email_api/email_template_schemas.yaml index 4c8e8b130..e5c018b62 100644 --- a/lib/apis/email_api/email_template_schemas.yaml +++ b/lib/apis/email_api/email_template_schemas.yaml @@ -43,6 +43,7 @@ shutoff_vm: schema: username: null shutoff_table: "No Shutoff VMs" + days_threshold: 60 html_filepath: "html/shutoff_vm.html.j2" plaintext_filepath: "plaintext/shutoff_vm.txt.j2" @@ -80,7 +81,7 @@ errored_vm: schema: username: null error_table: "No Errored VMs" - days_threshold: "No days" + days_threshold: 60 html_filepath: "html/errored_vm.html.j2" plaintext_filepath: "plaintext/errored_vm.txt.j2" diff --git a/lib/apis/email_api/templates/plaintext/shutoff_vm.txt.j2 b/lib/apis/email_api/templates/plaintext/shutoff_vm.txt.j2 index 565a19c54..6321d1d14 100644 --- a/lib/apis/email_api/templates/plaintext/shutoff_vm.txt.j2 +++ b/lib/apis/email_api/templates/plaintext/shutoff_vm.txt.j2 @@ -1,6 +1,6 @@ Dear Cloud User {{username}}, -We are writing to inform you one or more virtual machines (VMs) associated with your account are currently in a shutoff or errored state and have not been restarted or deleted for the past {{days_threshold}} days. +We are writing to inform you one or more virtual machines (VMs) associated with your account are currently in a shutoff state and have not been restarted or deleted for the past {{days_threshold}} days. Please take a moment to review the list of affected VMs provided below and either restart them or delete them if they are no longer needed: diff --git a/lib/apis/openstack_query_api/server_queries.py b/lib/apis/openstack_query_api/server_queries.py index 232464d44..c2fcf6e06 100644 --- a/lib/apis/openstack_query_api/server_queries.py +++ b/lib/apis/openstack_query_api/server_queries.py @@ -13,6 +13,7 @@ def find_servers_on_hv( webhook: Optional[str] = None, ): """ + Use QueryAPI to find VMs on a hypervisor. :param cloud_account: string represents cloud account to use :param from_projects: A list of project identifiers to limit search in """ @@ -47,7 +48,7 @@ def find_servers_with_flavors( from_projects: Optional[List[str]] = None, ): """ - Use QueryAPI to run the query to find decom flavors + Use QueryAPI to run the query to find decom flavors. :param cloud_account: string represents cloud account to use :param flavor_name_list: A list of flavor names to be decommissioned :param from_projects: A list of project identifiers to limit search in @@ -88,21 +89,22 @@ def find_servers_with_flavors( def find_servers_with_errored_vms( cloud_account: str, - age_filter_value: int, + days_threshold: int = 0, from_projects: Optional[List[str]] = None, ) -> ServerQuery: """ Search for machines that are in error state and returns the user id, name and email address. + if days_threshold is 0, then all of the servers are searched for errored vms. :param cloud_account: String representing cloud account to use - :param age_filter_value: An integer which specifies the minimum age (in days) of the servers to be found + :param days_threshold: An integer which specifies the minimum age (in days) of the servers to be found :param from_projects: A list of project identifiers to limit search to """ server_query = ServerQuery() - if age_filter_value > 0: + if days_threshold > 0: server_query.where( "older_than", "server_last_updated_date", - days=age_filter_value, + days=days_threshold, ) server_query.where("any_in", "server_status", values=["ERROR"]) server_query.run( @@ -119,14 +121,27 @@ def find_servers_with_errored_vms( return server_query -def find_shutoff_servers(cloud_account: str, from_projects: Optional[List[str]] = None): +def find_shutoff_servers( + cloud_account: str, + days_threshold: int = 0, + from_projects: Optional[List[str]] = None, +): """ + Use QueryAPI to find machines that are in shutoff state. + if days_threshold is 0, then all of the servers are searched that are in shutoff state. :param cloud_account: string represents cloud account to use + :param days_threshold: An integer which specifies the minimum age (in days) of the servers to be found :param from_projects: A list of project identifiers to limit search in """ - # Find VMs that have been in shutoff state for more than 60 days + # Find VMs that have been in shutoff state for more than 0 day server_query = ServerQuery() + if days_threshold > 0: + server_query.where( + "older_than", + "server_last_updated_date", + days=days_threshold, + ) server_query.where("any_in", "server_status", values=["SHUTOFF"]) server_query.run( cloud_account, diff --git a/lib/workflows/send_errored_vm_email.py b/lib/workflows/send_errored_vm_email.py index e46e321e2..dd4119002 100644 --- a/lib/workflows/send_errored_vm_email.py +++ b/lib/workflows/send_errored_vm_email.py @@ -68,7 +68,7 @@ def send_errored_vm_email( smtp_account: SMTPAccount, cloud_account: Union[CloudDomains, str], limit_by_projects: Optional[List[str]] = None, - days_threshold: int = 60, + days_threshold: int = 0, all_projects: bool = False, as_html: bool = False, send_email: bool = False, diff --git a/lib/workflows/send_shutoff_vm_email.py b/lib/workflows/send_shutoff_vm_email.py index 8567a7cb9..57c5d764e 100644 --- a/lib/workflows/send_shutoff_vm_email.py +++ b/lib/workflows/send_shutoff_vm_email.py @@ -14,7 +14,11 @@ def print_email_params( - email_addr: str, user_name: str, as_html: bool, shutoff_table: str + email_addr: str, + user_name: str, + as_html: bool, + shutoff_table: str, + days_threshold: int, ): """ Prints email params instead of sending the email. @@ -22,16 +26,20 @@ def print_email_params( :param user_name: Name of user in OpenStack :param as_html: A boolean which if selected will send an email, otherwise prints email details only :param shutoff_table: A table representing info found in OpenStack about VMs in shutoff state + :param days_threshold: An integer which specifies the minimum age (in days) of the servers to be found """ print( f"Send Email To: {email_addr}\n" f"email_templates shutoff-email: username {user_name}\n" f"send as html: {as_html}\n" f"shutoff table: {shutoff_table}\n" + f"days threshold: {days_threshold}\n" ) -def build_email_params(user_name: str, shutoff_table: str, **email_kwargs): +def build_email_params( + user_name: str, shutoff_table: str, days_threshold: int, **email_kwargs +): """ Builds email params dataclass which will be used to configure how to send the email. :param user_name: Name of user in OpenStack @@ -43,6 +51,7 @@ def build_email_params(user_name: str, shutoff_table: str, **email_kwargs): template_params={ "username": user_name, "shutoff_table": shutoff_table, + "days_threshold": days_threshold, }, ) @@ -57,6 +66,7 @@ def send_shutoff_vm_email( smtp_account: SMTPAccount, cloud_account: Union[CloudDomains, str], limit_by_projects: Optional[List[str]] = None, + days_threshold: int = 0, all_projects: bool = False, as_html: bool = False, send_email: bool = False, @@ -71,6 +81,7 @@ def send_shutoff_vm_email( :param smtp_account: (SMTPAccount): SMTP config :param cloud_account: String representing the cloud account to use :param limit_by_projects: A list of project names or ids to limit search in + :param days_threshold: An integer which specifies the minimum age (in days) of the servers to be found :param all_projects: A boolean which, if True, will search in all projects :param send_email: A boolean which, if True, will send the email instead of printing what will be sent :param as_html: A boolean which, if True, will send the email as html @@ -88,7 +99,9 @@ def send_shutoff_vm_email( "please provide either a list of project identifiers or with flag 'all_projects' to run globally" ) - server_query = find_shutoff_servers(cloud_account, limit_by_projects) + server_query = find_shutoff_servers( + cloud_account, days_threshold, limit_by_projects + ) if not server_query.to_props(): raise RuntimeError( @@ -116,7 +129,9 @@ def send_shutoff_vm_email( ) if not send_email: - print_email_params(send_to[0], user_name, as_html, server_list) + print_email_params( + send_to[0], user_name, as_html, server_list, days_threshold + ) continue email_params = build_email_params( @@ -124,6 +139,7 @@ def send_shutoff_vm_email( server_list, email_to=send_to, as_html=as_html, + days_threshold=days_threshold, email_cc=("cloud-support@stfc.ac.uk",) if cc_cloud_support else None, **email_params_kwargs, ) diff --git a/tests/lib/apis/openstack_query_api/test_server_queries.py b/tests/lib/apis/openstack_query_api/test_server_queries.py index 07cb4f57b..870af373e 100644 --- a/tests/lib/apis/openstack_query_api/test_server_queries.py +++ b/tests/lib/apis/openstack_query_api/test_server_queries.py @@ -201,7 +201,30 @@ def test_find_servers_with_shutoff_vms_valid(mock_server_query): """ mock_server_query_obj = mock_server_query.return_value - res = find_shutoff_servers("test-cloud-account", ["project1", "project2"]) + res = find_shutoff_servers("test-cloud-account", -1, ["project1", "project2"]) + + mock_server_query_obj.run.assert_called_once_with( + "test-cloud-account", + as_admin=True, + from_projects=["project1", "project2"], + all_projects=False, + ) + mock_server_query_obj.select.assert_called_once_with("id", "name", "addresses") + + mock_server_query_obj.append_from.assert_called_once_with( + "PROJECT_QUERY", "test-cloud-account", ["name"] + ) + assert res == mock_server_query_obj + + +@patch("apis.openstack_query_api.server_queries.ServerQuery") +def test_find_servers_with_shutoff_vms_valid_age(mock_server_query): + """ + Tests find_servers_with_shutoff_vms() function when filtering by minimum server age + """ + mock_server_query_obj = mock_server_query.return_value + + res = find_shutoff_servers("test-cloud-account", 10, ["project1", "project2"]) mock_server_query_obj.run.assert_called_once_with( "test-cloud-account", diff --git a/tests/lib/workflows/test_send_errored_vm_email.py b/tests/lib/workflows/test_send_errored_vm_email.py index 66e6dc73e..6f1de9a23 100644 --- a/tests/lib/workflows/test_send_errored_vm_email.py +++ b/tests/lib/workflows/test_send_errored_vm_email.py @@ -488,7 +488,7 @@ def test_raise_error_when_no_matching_servers_found(mock_find_servers): all_projects=all_projects, ) - mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 0, limit_by_projects) mock_query.to_props.assert_called_once() diff --git a/tests/lib/workflows/test_send_shutoff_vm_email.py b/tests/lib/workflows/test_send_shutoff_vm_email.py index 5baaea949..4aa537247 100644 --- a/tests/lib/workflows/test_send_shutoff_vm_email.py +++ b/tests/lib/workflows/test_send_shutoff_vm_email.py @@ -29,7 +29,7 @@ def test_raise_error_when_no_matching_servers_found(mock_find_servers): all_projects=all_projects, ) - mock_find_servers.assert_called_once_with(cloud_account, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 0, limit_by_projects) mock_query.to_props.assert_called_once() @@ -41,15 +41,19 @@ def test_print_email_params(): user_name = "John Doe" as_html = True shutoff_table = "Shutoff Table Content" + days_threshold = "Days Threshold" with patch("builtins.print") as mock_print: - print_email_params(email_addr, user_name, as_html, shutoff_table) + print_email_params( + email_addr, user_name, as_html, shutoff_table, days_threshold + ) mock_print.assert_called_once_with( f"Send Email To: {email_addr}\n" f"email_templates shutoff-email: username {user_name}\n" f"send as html: {as_html}\n" f"shutoff table: {shutoff_table}\n" + f"days threshold: {days_threshold}\n" ) @@ -62,9 +66,10 @@ def test_build_params(mock_email_params, mock_email_template_details): user_name = "John Doe" shutoff_table = "Shutoff Table Content" + days_threshold = "Days Threshold" email_kwargs = {"arg1": "val1", "arg2": "val2"} - res = build_email_params(user_name, shutoff_table, **email_kwargs) + res = build_email_params(user_name, shutoff_table, days_threshold, **email_kwargs) mock_email_template_details.assert_has_calls( [ call( @@ -72,6 +77,7 @@ def test_build_params(mock_email_params, mock_email_template_details): template_params={ "username": user_name, "shutoff_table": shutoff_table, + "days_threshold": days_threshold, }, ), call(template_name="footer", template_params={}), @@ -133,6 +139,7 @@ def test_send_shutoff_vm_email_send_plaintext( smtp_account=smtp_account, cloud_account=cloud_account, limit_by_projects=limit_by_projects, + days_threshold=60, all_projects=all_projects, as_html=False, send_email=True, @@ -140,7 +147,7 @@ def test_send_shutoff_vm_email_send_plaintext( **mock_kwargs, ) - mock_find_servers.assert_called_once_with(cloud_account, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_query.to_props.assert_called_once() mock_group_servers_by_user_id.assert_called_once_with(mock_query) mock_grouped_query.to_props.assert_called_once() @@ -158,6 +165,7 @@ def test_send_shutoff_vm_email_send_plaintext( mock_grouped_query.to_string.return_value, email_to=["user_email1"], as_html=False, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -166,6 +174,7 @@ def test_send_shutoff_vm_email_send_plaintext( mock_grouped_query.to_string.return_value, email_to=["user_email2"], as_html=False, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -232,6 +241,7 @@ def test_send_shutoff_vm_email_send_html( smtp_account=smtp_account, cloud_account=cloud_account, limit_by_projects=limit_by_projects, + days_threshold=60, all_projects=all_projects, as_html=True, send_email=True, @@ -239,7 +249,7 @@ def test_send_shutoff_vm_email_send_html( **mock_kwargs, ) - mock_find_servers.assert_called_once_with(cloud_account, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_group_servers_by_user_id.assert_called_once_with(mock_query) mock_grouped_query.to_props.assert_called_once() mock_find_user_info.assert_has_calls( @@ -256,6 +266,7 @@ def test_send_shutoff_vm_email_send_html( mock_grouped_query.to_html.return_value, email_to=["user_email1"], as_html=True, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -264,6 +275,7 @@ def test_send_shutoff_vm_email_send_html( mock_grouped_query.to_html.return_value, email_to=["user_email2"], as_html=True, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -328,6 +340,7 @@ def test_send_shutoff_vm_email_print( smtp_account=smtp_account, cloud_account=cloud_account, limit_by_projects=limit_by_projects, + days_threshold=60, all_projects=all_projects, as_html=False, send_email=False, @@ -335,7 +348,7 @@ def test_send_shutoff_vm_email_print( **mock_kwargs, ) - mock_find_servers.assert_called_once_with(cloud_account, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_query.to_props.assert_called_once() mock_group_servers_by_user_id.assert_called_once_with(mock_query) mock_grouped_query.to_props.assert_called_once() @@ -353,12 +366,14 @@ def test_send_shutoff_vm_email_print( "user1", False, mock_grouped_query.to_string.return_value, + 60, ), call( "user_email2", "user2", False, mock_grouped_query.to_string.return_value, + 60, ), ] ) @@ -415,6 +430,7 @@ def test_send_shutoff_vm_email_use_override( smtp_account=smtp_account, cloud_account=cloud_account, limit_by_projects=limit_by_projects, + days_threshold=60, all_projects=all_projects, as_html=False, send_email=True, @@ -423,7 +439,7 @@ def test_send_shutoff_vm_email_use_override( **mock_kwargs, ) - mock_find_servers.assert_called_once_with(cloud_account, limit_by_projects) + mock_find_servers.assert_called_once_with(cloud_account, 60, limit_by_projects) mock_query.to_props.assert_called_once() mock_group_servers_by_user_id.assert_called_once_with(mock_query) mock_grouped_query.to_props.assert_called_once() @@ -441,6 +457,7 @@ def test_send_shutoff_vm_email_use_override( mock_grouped_query.to_string.return_value, email_to=[override_email_address], as_html=False, + days_threshold=60, email_cc=None, **mock_kwargs, ), @@ -449,6 +466,7 @@ def test_send_shutoff_vm_email_use_override( mock_grouped_query.to_string.return_value, email_to=[override_email_address], as_html=False, + days_threshold=60, email_cc=None, **mock_kwargs, ),