Skip to content

Commit 5faeda8

Browse files
Fix: Handle 403 Forbidden in get_reservation_details for shared reservation (#5117)
1 parent 297bd66 commit 5faeda8

File tree

4 files changed

+70
-6
lines changed

4 files changed

+70
-6
lines changed

community/modules/compute/schedmd-slurm-gcp-v6-nodeset/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ The format of the `reservation_name` input determines the type of reservation us
9494
* `RESERVATION_NAME` is the name assigned to the specific reservation.
9595
* `BLOCK_ID` (Optional) is the identifier for a specific reservation block, if the reservation is composed of multiple blocks.
9696

97-
> **_NOTE:_** Using a shared reservation requires the 'compute.reservations.get'
98-
> permission for the node service account in the host project (HOST_PROJECT_ID).
99-
> Ensure this permission is granted before deploying.
97+
> **_NOTE:_** Using a shared reservation ideally requires the 'compute.reservations.get'
98+
> permission for the node service account in the host project (HOST_PROJECT_ID) to fetch full reservation details.
99+
> However, if this permission is missing, the system will fall back to minimal reservation settings and proceed.
100100

101101
### No Reservation
102102

@@ -240,7 +240,7 @@ modules. For support with the underlying modules, see the instructions in the
240240
| <a name="input_preemptible"></a> [preemptible](#input\_preemptible) | Should use preemptibles to burst. | `bool` | `false` | no |
241241
| <a name="input_project_id"></a> [project\_id](#input\_project\_id) | Project ID to create resources in. | `string` | n/a | yes |
242242
| <a name="input_region"></a> [region](#input\_region) | The default region for Cloud resources. | `string` | n/a | yes |
243-
| <a name="input_reservation_name"></a> [reservation\_name](#input\_reservation\_name) | Name or path of the reservation to use for VM resources. Must be a "SPECIFIC" reservation.<br/>Set to an empty string if using no reservation or automatically-consumed reservations.<br/><br/>Formats:<br/>- Local Reservation: For reservations in the same project as the cluster (var.project\_id), the name is sufficient:<br/> RESERVATION\_NAME[/reservationBlocks/BLOCK\_ID]<br/>- Shared Reservation: For reservations shared from a different project, the full resource path is required:<br/> projects/HOST\_PROJECT\_ID/reservations/RESERVATION\_NAME[/reservationBlocks/BLOCK\_ID]<br/><br/>Where:<br/>- HOST\_PROJECT\_ID: Project ID where the shared reservation was created.<br/>- RESERVATION\_NAME: The name assigned to the specific reservation.<br/>- BLOCK\_ID (Optional): The identifier for a specific reservation block, if the reservation is composed of multiple blocks.<br/><br/>Note: Using a shared reservation requires the 'compute.reservations.get' permission for the node service account in the host project. | `string` | `""` | no |
243+
| <a name="input_reservation_name"></a> [reservation\_name](#input\_reservation\_name) | Name or path of the reservation to use for VM resources. Must be a "SPECIFIC" reservation.<br/>Set to an empty string if using no reservation or automatically-consumed reservations.<br/><br/>Formats:<br/>- Local Reservation: For reservations in the same project as the cluster (var.project\_id), the name is sufficient:<br/> RESERVATION\_NAME[/reservationBlocks/BLOCK\_ID]<br/>- Shared Reservation: For reservations shared from a different project, the full resource path is required:<br/> projects/HOST\_PROJECT\_ID/reservations/RESERVATION\_NAME[/reservationBlocks/BLOCK\_ID]<br/><br/>Where:<br/>- HOST\_PROJECT\_ID: Project ID where the shared reservation was created.<br/>- RESERVATION\_NAME: The name assigned to the specific reservation.<br/>- BLOCK\_ID (Optional): The identifier for a specific reservation block, if the reservation is composed of multiple blocks.<br/><br/>Note: Using a shared reservation ideally requires the 'compute.reservations.get' permission for the node service account in the host project; without it, full details cannot be fetched, but deployment will still proceed with defaults. | `string` | `""` | no |
244244
| <a name="input_resource_manager_tags"></a> [resource\_manager\_tags](#input\_resource\_manager\_tags) | (Optional) A set of key/value resource manager tag pairs to bind to the instances. Keys must be in the format tagKeys/{tag\_key\_id}, and values are in the format tagValues/456. | `map(string)` | `{}` | no |
245245
| <a name="input_service_account"></a> [service\_account](#input\_service\_account) | DEPRECATED: Use `service_account_email` and `service_account_scopes` instead. | <pre>object({<br/> email = string<br/> scopes = set(string)<br/> })</pre> | `null` | no |
246246
| <a name="input_service_account_email"></a> [service\_account\_email](#input\_service\_account\_email) | Service account e-mail address to attach to the compute instances. | `string` | `null` | no |

community/modules/compute/schedmd-slurm-gcp-v6-nodeset/variables.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ variable "reservation_name" {
524524
- RESERVATION_NAME: The name assigned to the specific reservation.
525525
- BLOCK_ID (Optional): The identifier for a specific reservation block, if the reservation is composed of multiple blocks.
526526
527-
Note: Using a shared reservation requires the 'compute.reservations.get' permission for the node service account in the host project.
527+
Note: Using a shared reservation ideally requires the 'compute.reservations.get' permission for the node service account in the host project; without it, full details cannot be fetched, but deployment will still proceed with defaults.
528528
EOD
529529
type = string
530530
default = ""

community/modules/scheduler/schedmd-slurm-gcp-v6-controller/modules/slurm_files/scripts/tests/test_util.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import util
2424
from util import NodeState, MachineType, AcceleratorInfo, UpcomingMaintenance, InstanceResourceStatus, FutureReservation, ReservationDetails
2525
from google.api_core.client_options import ClientOptions # noqa: E402
26+
from googleapiclient.errors import HttpError # type: ignore
2627
from addict import Dict as NSDict # type: ignore
2728

2829
# Note: need to install pytest-mock
@@ -710,3 +711,50 @@ def test_slurm_version(stdout_data, exception_to_raise, expected_version, mocker
710711

711712
assert version == expected_version
712713
mock_run.assert_called_once()
714+
715+
716+
def test_get_reservation_details_403(mocker):
717+
lkp = util.Lookup(TstCfg())
718+
719+
# Mock HttpError 403
720+
mock_resp = Mock()
721+
mock_resp.status = 403
722+
error = HttpError(mock_resp, b'Forbidden')
723+
724+
lkp._get_reservation = Mock(side_effect=error)
725+
726+
details = lkp.get_reservation_details(
727+
project="my-project",
728+
zone="us-central1-a",
729+
name="my-reservation",
730+
bulk_insert_name="projects/my-project/reservations/my-reservation"
731+
)
732+
733+
assert details.policies == []
734+
assert details.deployment_type is None
735+
assert details.reservation_mode is None
736+
assert details.assured_count == 0
737+
assert details.bulk_insert_name == "projects/my-project/reservations/my-reservation"
738+
739+
lkp._get_reservation.assert_called_once_with("my-project", "us-central1-a", "my-reservation")
740+
741+
742+
def test_get_reservation_details_error(mocker):
743+
lkp = util.Lookup(TstCfg())
744+
745+
# Mock HttpError 500
746+
mock_resp = Mock()
747+
mock_resp.status = 500
748+
error = HttpError(mock_resp, b'Internal Server Error')
749+
750+
lkp._get_reservation = Mock(side_effect=error)
751+
752+
with pytest.raises(HttpError):
753+
lkp.get_reservation_details(
754+
project="my-project",
755+
zone="us-central1-a",
756+
name="my-reservation",
757+
bulk_insert_name="projects/my-project/reservations/my-reservation"
758+
)
759+
760+
lkp._get_reservation.assert_called_once_with("my-project", "us-central1-a", "my-reservation")

community/modules/scheduler/schedmd-slurm-gcp-v6-controller/modules/slurm_files/scripts/util.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import googleapiclient.discovery # type: ignore
5252
import google_auth_httplib2 # type: ignore
5353
from googleapiclient.http import set_user_agent # type: ignore
54+
from googleapiclient.errors import HttpError # type: ignore
5455
from google.api_core.client_options import ClientOptions
5556
import httplib2
5657

@@ -1887,7 +1888,22 @@ def _get_future_reservation(self, project:str, zone:str, name: str) -> Any:
18871888
return self.compute.futureReservations().get(project=project, zone=zone, futureReservation=name).execute()
18881889

18891890
def get_reservation_details(self, project:str, zone:str, name:str, bulk_insert_name:str) -> ReservationDetails:
1890-
reservation = self._get_reservation(project, zone, name)
1891+
try:
1892+
reservation = self._get_reservation(project, zone, name)
1893+
except HttpError as e:
1894+
if e.resp.status == 403:
1895+
log.warning(f"Could not fetch reservation details for {project}/{zone}/{name}: {e}. Proceeding with minimal reservation settings.")
1896+
return ReservationDetails(
1897+
project=project,
1898+
zone=zone,
1899+
name=name,
1900+
policies=[],
1901+
bulk_insert_name=bulk_insert_name,
1902+
deployment_type=None,
1903+
reservation_mode=None,
1904+
assured_count=0,
1905+
delete_at_time=None)
1906+
raise e
18911907

18921908
# Converts policy URLs to names, e.g.:
18931909
# projects/111111/regions/us-central1/resourcePolicies/zebra -> zebra

0 commit comments

Comments
 (0)