Skip to content

Commit ee59347

Browse files
feat(cloud): add polling for instance action and interfaces attach/detach
* feat(cloud): add polling for attach/detach instance interfaces * feat(cloud): update instances examples * refactor(cloud): format fixes * feat(cloud): add instance action polling methods * feat(cloud): add instance action polling async methods * feat(cloud): add action_and_poll to wrapper classes * fix(cloud): linting errors * feat(cloud): add instance interfaces poll methods to wrapper classes
1 parent 7e1ed77 commit ee59347

File tree

4 files changed

+796
-12
lines changed

4 files changed

+796
-12
lines changed

examples/cloud/instances.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,20 +216,22 @@ def remove_from_placement_group(*, client: Gcore, instance_id: str) -> None:
216216

217217
def detach_interface(*, client: Gcore, instance_id: str, ip_address: str, port_id: str) -> None:
218218
print("\n=== DETACH INTERFACE ===")
219-
response = client.cloud.instances.interfaces.detach(instance_id=instance_id, ip_address=ip_address, port_id=port_id)
220-
client.cloud.tasks.poll(task_id=response.tasks[0])
221-
219+
interfaces = client.cloud.instances.interfaces.detach_and_poll(
220+
instance_id=instance_id, ip_address=ip_address, port_id=port_id
221+
)
222+
for count, interface in enumerate(interfaces.results, 1):
223+
print(f" {count}. Interface: PortID={interface.port_id}, NetworkID={interface.network_id}")
222224
print(f"Detached interface (IP: {ip_address}, Port: {port_id}) from instance: {instance_id}")
223225
print("========================")
224226

225227

226228
def attach_interface(*, client: Gcore, instance_id: str, network_id: str) -> None:
227229
print("\n=== ATTACH INTERFACE ===")
228-
response = client.cloud.instances.interfaces.attach(
230+
interfaces = client.cloud.instances.interfaces.attach_and_poll(
229231
instance_id=instance_id, type="any_subnet", network_id=network_id
230232
)
231-
client.cloud.tasks.poll(task_id=response.tasks[0])
232-
233+
for count, interface in enumerate(interfaces.results, 1):
234+
print(f" {count}. Interface: PortID={interface.port_id}, NetworkID={interface.network_id}")
233235
print(f"Attached interface to any available subnet in network {network_id} (instance: {instance_id})")
234236
print("========================")
235237

examples/cloud/instances_async.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,22 +221,22 @@ async def remove_from_placement_group(*, client: AsyncGcore, instance_id: str) -
221221

222222
async def detach_interface(*, client: AsyncGcore, instance_id: str, ip_address: str, port_id: str) -> None:
223223
print("\n=== DETACH INTERFACE ===")
224-
response = await client.cloud.instances.interfaces.detach(
224+
interfaces = await client.cloud.instances.interfaces.detach_and_poll(
225225
instance_id=instance_id, ip_address=ip_address, port_id=port_id
226226
)
227-
await client.cloud.tasks.poll(task_id=response.tasks[0])
228-
227+
for count, interface in enumerate(interfaces.results, 1):
228+
print(f" {count}. Interface: PortID={interface.port_id}, NetworkID={interface.network_id}")
229229
print(f"Detached interface (IP: {ip_address}, Port: {port_id}) from instance: {instance_id}")
230230
print("========================")
231231

232232

233233
async def attach_interface(*, client: AsyncGcore, instance_id: str, network_id: str) -> None:
234234
print("\n=== ATTACH INTERFACE ===")
235-
response = await client.cloud.instances.interfaces.attach(
235+
interfaces = await client.cloud.instances.interfaces.attach_and_poll(
236236
instance_id=instance_id, type="any_subnet", network_id=network_id
237237
)
238-
await client.cloud.tasks.poll(task_id=response.tasks[0])
239-
238+
for count, interface in enumerate(interfaces.results, 1):
239+
print(f" {count}. Interface: PortID={interface.port_id}, NetworkID={interface.network_id}")
240240
print(f"Attached interface to any available subnet in network {network_id} (instance: {instance_id})")
241241
print("========================")
242242

src/gcore/resources/cloud/instances/instances.py

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,125 @@ def action(
773773
cast_to=TaskIDList,
774774
)
775775

776+
@overload
777+
def action_and_poll(
778+
self,
779+
instance_id: str,
780+
*,
781+
project_id: int | None = None,
782+
region_id: int | None = None,
783+
action: Literal["start"],
784+
activate_profile: Optional[bool] | NotGiven = NOT_GIVEN,
785+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
786+
# The extra values given here take precedence over values defined on the client or passed to this method.
787+
extra_headers: Headers | None = None,
788+
extra_query: Query | None = None,
789+
extra_body: Body | None = None,
790+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
791+
) -> Instance:
792+
"""
793+
The action can be one of: start, stop, reboot, powercycle, suspend or resume.
794+
Suspend and resume are not available for bare metal instances.
795+
796+
Args:
797+
action: Instance action name
798+
799+
activate_profile: Used on start instance to activate Advanced DDoS profile
800+
801+
extra_headers: Send extra headers
802+
803+
extra_query: Add additional query parameters to the request
804+
805+
extra_body: Add additional JSON properties to the request
806+
807+
timeout: Override the client-level default timeout for this request, in seconds
808+
"""
809+
...
810+
811+
@overload
812+
def action_and_poll(
813+
self,
814+
instance_id: str,
815+
*,
816+
project_id: int | None = None,
817+
region_id: int | None = None,
818+
action: Literal["reboot", "reboot_hard", "resume", "stop", "suspend"],
819+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
820+
# The extra values given here take precedence over values defined on the client or passed to this method.
821+
extra_headers: Headers | None = None,
822+
extra_query: Query | None = None,
823+
extra_body: Body | None = None,
824+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
825+
) -> Instance:
826+
"""
827+
The action can be one of: start, stop, reboot, powercycle, suspend or resume.
828+
Suspend and resume are not available for bare metal instances.
829+
830+
Args:
831+
action: Instance action name
832+
833+
extra_headers: Send extra headers
834+
835+
extra_query: Add additional query parameters to the request
836+
837+
extra_body: Add additional JSON properties to the request
838+
839+
timeout: Override the client-level default timeout for this request, in seconds
840+
"""
841+
...
842+
843+
@required_args(["action"])
844+
def action_and_poll(
845+
self,
846+
instance_id: str,
847+
*,
848+
project_id: int | None = None,
849+
region_id: int | None = None,
850+
action: Literal["start", "reboot", "reboot_hard", "resume", "stop", "suspend"],
851+
activate_profile: Optional[bool] | NotGiven = NOT_GIVEN,
852+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
853+
# The extra values given here take precedence over values defined on the client or passed to this method.
854+
extra_headers: Headers | None = None,
855+
extra_query: Query | None = None,
856+
extra_body: Body | None = None,
857+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
858+
) -> Instance:
859+
"""
860+
Perform the action on the instance and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method.
861+
"""
862+
if project_id is None:
863+
project_id = self._client._get_cloud_project_id_path_param()
864+
if region_id is None:
865+
region_id = self._client._get_cloud_region_id_path_param()
866+
if not instance_id:
867+
raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}")
868+
response = self._post(
869+
f"/cloud/v2/instances/{project_id}/{region_id}/{instance_id}/action",
870+
body=maybe_transform(
871+
{
872+
"action": action,
873+
"activate_profile": activate_profile,
874+
},
875+
instance_action_params.InstanceActionParams,
876+
),
877+
options=make_request_options(
878+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
879+
),
880+
cast_to=TaskIDList,
881+
)
882+
if not response.tasks:
883+
raise ValueError("Expected at least one task to be created")
884+
self._client.cloud.tasks.poll(
885+
task_id=response.tasks[0],
886+
extra_headers=extra_headers,
887+
)
888+
return self.get(
889+
instance_id=instance_id,
890+
project_id=project_id,
891+
region_id=region_id,
892+
extra_headers=extra_headers,
893+
)
894+
776895
def add_to_placement_group(
777896
self,
778897
instance_id: str,
@@ -2023,6 +2142,125 @@ async def action(
20232142
cast_to=TaskIDList,
20242143
)
20252144

2145+
@overload
2146+
async def action_and_poll(
2147+
self,
2148+
instance_id: str,
2149+
*,
2150+
project_id: int | None = None,
2151+
region_id: int | None = None,
2152+
action: Literal["start"],
2153+
activate_profile: Optional[bool] | NotGiven = NOT_GIVEN,
2154+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
2155+
# The extra values given here take precedence over values defined on the client or passed to this method.
2156+
extra_headers: Headers | None = None,
2157+
extra_query: Query | None = None,
2158+
extra_body: Body | None = None,
2159+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
2160+
) -> Instance:
2161+
"""
2162+
The action can be one of: start, stop, reboot, powercycle, suspend or resume.
2163+
Suspend and resume are not available for bare metal instances.
2164+
2165+
Args:
2166+
action: Instance action name
2167+
2168+
activate_profile: Used on start instance to activate Advanced DDoS profile
2169+
2170+
extra_headers: Send extra headers
2171+
2172+
extra_query: Add additional query parameters to the request
2173+
2174+
extra_body: Add additional JSON properties to the request
2175+
2176+
timeout: Override the client-level default timeout for this request, in seconds
2177+
"""
2178+
...
2179+
2180+
@overload
2181+
async def action_and_poll(
2182+
self,
2183+
instance_id: str,
2184+
*,
2185+
project_id: int | None = None,
2186+
region_id: int | None = None,
2187+
action: Literal["reboot", "reboot_hard", "resume", "stop", "suspend"],
2188+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
2189+
# The extra values given here take precedence over values defined on the client or passed to this method.
2190+
extra_headers: Headers | None = None,
2191+
extra_query: Query | None = None,
2192+
extra_body: Body | None = None,
2193+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
2194+
) -> Instance:
2195+
"""
2196+
The action can be one of: start, stop, reboot, powercycle, suspend or resume.
2197+
Suspend and resume are not available for bare metal instances.
2198+
2199+
Args:
2200+
action: Instance action name
2201+
2202+
extra_headers: Send extra headers
2203+
2204+
extra_query: Add additional query parameters to the request
2205+
2206+
extra_body: Add additional JSON properties to the request
2207+
2208+
timeout: Override the client-level default timeout for this request, in seconds
2209+
"""
2210+
...
2211+
2212+
@required_args(["action"])
2213+
async def action_and_poll(
2214+
self,
2215+
instance_id: str,
2216+
*,
2217+
project_id: int | None = None,
2218+
region_id: int | None = None,
2219+
action: Literal["start", "reboot", "reboot_hard", "resume", "stop", "suspend"],
2220+
activate_profile: Optional[bool] | NotGiven = NOT_GIVEN,
2221+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
2222+
# The extra values given here take precedence over values defined on the client or passed to this method.
2223+
extra_headers: Headers | None = None,
2224+
extra_query: Query | None = None,
2225+
extra_body: Body | None = None,
2226+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
2227+
) -> Instance:
2228+
"""
2229+
Perform the action on the instance and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method.
2230+
"""
2231+
if project_id is None:
2232+
project_id = self._client._get_cloud_project_id_path_param()
2233+
if region_id is None:
2234+
region_id = self._client._get_cloud_region_id_path_param()
2235+
if not instance_id:
2236+
raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}")
2237+
response = await self._post(
2238+
f"/cloud/v2/instances/{project_id}/{region_id}/{instance_id}/action",
2239+
body=await async_maybe_transform(
2240+
{
2241+
"action": action,
2242+
"activate_profile": activate_profile,
2243+
},
2244+
instance_action_params.InstanceActionParams,
2245+
),
2246+
options=make_request_options(
2247+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
2248+
),
2249+
cast_to=TaskIDList,
2250+
)
2251+
if not response.tasks:
2252+
raise ValueError("Expected at least one task to be created")
2253+
await self._client.cloud.tasks.poll(
2254+
task_id=response.tasks[0],
2255+
extra_headers=extra_headers,
2256+
)
2257+
return await self.get(
2258+
instance_id=instance_id,
2259+
project_id=project_id,
2260+
region_id=region_id,
2261+
extra_headers=extra_headers,
2262+
)
2263+
20262264
async def add_to_placement_group(
20272265
self,
20282266
instance_id: str,
@@ -2591,6 +2829,9 @@ def __init__(self, instances: InstancesResource) -> None:
25912829
self.action = to_raw_response_wrapper(
25922830
instances.action,
25932831
)
2832+
self.action_and_poll = to_raw_response_wrapper(
2833+
instances.action_and_poll,
2834+
)
25942835
self.add_to_placement_group = to_raw_response_wrapper(
25952836
instances.add_to_placement_group,
25962837
)
@@ -2655,6 +2896,9 @@ def __init__(self, instances: AsyncInstancesResource) -> None:
26552896
self.action = async_to_raw_response_wrapper(
26562897
instances.action,
26572898
)
2899+
self.action_and_poll = async_to_raw_response_wrapper(
2900+
instances.action_and_poll,
2901+
)
26582902
self.add_to_placement_group = async_to_raw_response_wrapper(
26592903
instances.add_to_placement_group,
26602904
)
@@ -2719,6 +2963,9 @@ def __init__(self, instances: InstancesResource) -> None:
27192963
self.action = to_streamed_response_wrapper(
27202964
instances.action,
27212965
)
2966+
self.action_and_poll = to_streamed_response_wrapper(
2967+
instances.action_and_poll,
2968+
)
27222969
self.add_to_placement_group = to_streamed_response_wrapper(
27232970
instances.add_to_placement_group,
27242971
)
@@ -2783,6 +3030,9 @@ def __init__(self, instances: AsyncInstancesResource) -> None:
27833030
self.action = async_to_streamed_response_wrapper(
27843031
instances.action,
27853032
)
3033+
self.action_and_poll = async_to_streamed_response_wrapper(
3034+
instances.action_and_poll,
3035+
)
27863036
self.add_to_placement_group = async_to_streamed_response_wrapper(
27873037
instances.add_to_placement_group,
27883038
)

0 commit comments

Comments
 (0)