diff --git a/CHANGELOG.md b/CHANGELOG.md index bfaf1019..1c4b6753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [3.16.1] - 2024-10-22 +### Added +- "Delete Volume in a Stateful Instance" API support added in the AWS Elastigroup Client. +- Added `DynamicIops` model for AWS Elastigroup. + +## [3.16.0] - 2024-10-21 +### Added +- Import EC2 instance API support added in the AWS Elastigroup Client. +- Added `VolumeAttachments` and `ResourceRequirements` models for AWS Elastigroup. + ## [3.15.1] - 2024-09-19 ### Fixed - Create/Update rightsizing rule APIs fixed for optional parameters. diff --git a/docs/clients/elastigroup/elastigroup_aws_client.md b/docs/clients/elastigroup/elastigroup_aws_client.md index c1259abe..f5c5644e 100644 --- a/docs/clients/elastigroup/elastigroup_aws_client.md +++ b/docs/clients/elastigroup/elastigroup_aws_client.md @@ -524,6 +524,25 @@ __Returns__ `(Object)`: Elastigroup API response +

delete_volume_in_stateful_instance

+ +```python +ElastigroupAwsClient.delete_volume_in_stateful_instance( + group_id, stateful_instance_id, volume_id) +``` + +Delete stateful instance + +__Arguments__ + +- __group_id (String)__: Elastigroup ID +- __stateful_instance_id (String)__: Stateful Instance ID +- __volume_id (String)__: Volume ID + +__Returns__ + +`(Object)`: Elastigroup API response +

beanstalk_maintenance_status

```python @@ -580,7 +599,8 @@ ElastigroupAwsClient.beanstalk_import(region, env_name=None) ``` -Import beanstalk attributes into JSON. Either env_id or env_name is required, both cannot be null +Import beanstalk attributes into JSON. Either env_id or env_name is +required, both cannot be null __Arguments__ @@ -608,13 +628,35 @@ __Returns__ `(Object)`: Elastigroup API response +

import_instance

+ +```python +ElastigroupAwsClient.import_instance(region, instance_id, + instance: ImportInstanceConfig) +``` + +Import an EC2 instance into a new Elastigroup + +__Arguments__ + +- __region (String)__: Instance Region +- __instance_id (String)__: Instance ID +- __instance (ImportInstanceConfig)__: Import Configuration + +__Returns__ + +`(Object)`: Elastigroup API response +

import_asg

```python -ElastigroupAwsClient.import_asg(region, asg_name, asg, dry_run=None) +ElastigroupAwsClient.import_asg(region, + asg_name, + asg: ASG, + dry_run=None) ``` -import asg attributes as JSON +Create a new Elastigroup using the configuration of an existing Autoscaling group __Arguments__ @@ -886,8 +928,9 @@ __Arguments__ - __group_id(String)__: Elastigroup ID - __to_date (String)__: to date - __from_date (String)__: to date -- __severity(String) (Optional)__: Log level severity -- __resource_id(String) (Optional)__: Filter log extracted entires related to a specific resource id +- __severity (String) (Optional)__: Log level severity +- __resource_id (String) (Optional)__: Filter log extracted entires related to a + specific resource id - __limit(String) (Optional)__: Maximum number of lines to extract in a response __Returns__ diff --git a/docs/models/elastigroup/aws.md b/docs/models/elastigroup/aws.md index 09cc33c1..7784a6e6 100644 --- a/docs/models/elastigroup/aws.md +++ b/docs/models/elastigroup/aws.md @@ -35,10 +35,12 @@ __Arguments__ Strategy( self, availability_vs_cost='d3043820717d74d9a17694c176d39733', + consider_o_d_pricing='d3043820717d74d9a17694c176d39733', risk='d3043820717d74d9a17694c176d39733', utilize_commitments='d3043820717d74d9a17694c176d39733', utilize_reserved_instances='d3043820717d74d9a17694c176d39733', fallback_to_od='d3043820717d74d9a17694c176d39733', + max_replacements_percentage='d3043820717d74d9a17694c176d39733', on_demand_count='d3043820717d74d9a17694c176d39733', draining_timeout='d3043820717d74d9a17694c176d39733', spin_up_time='d3043820717d74d9a17694c176d39733', @@ -54,10 +56,12 @@ Strategy( __Arguments__ - __availability_vs_cost__: str +- __consider_o_d_pricing__: bool - __risk__: int - __utilize_commitments__: bool - __utilize_reserved_instances__: bool - __fallback_to_od__: bool +- __max_replacements_percentage__: int - __on_demand_count__: int - __draining_timeout__: int - __spin_up_time__: int @@ -67,6 +71,7 @@ __Arguments__ - __persistence__: Persistence - __revert_to_spot__: RevertToSpot - __restrict_single_az__: bool +- __immediate_o_d_recover_threshold__: int

Signal

@@ -941,7 +946,8 @@ Compute(self, elastic_ips='d3043820717d74d9a17694c176d39733', private_ips='d3043820717d74d9a17694c176d39733', subnet_ids='d3043820717d74d9a17694c176d39733', - preferred_availability_zones='d3043820717d74d9a17694c176d39733') + preferred_availability_zones='d3043820717d74d9a17694c176d39733', + volume_attachments='d3043820717d74d9a17694c176d39733') ``` __Arguments__ @@ -954,6 +960,7 @@ __Arguments__ - __private_ips__: list[str] - __subnet_ids__: list[str] - __preferred_availability_zones__: list[str] +- __volume_attachments__: VolumeAttachments

AvailabilityZone

@@ -981,7 +988,8 @@ InstanceTypes(self, on_demand_types='d3043820717d74d9a17694c176d39733', spot='d3043820717d74d9a17694c176d39733', weights='d3043820717d74d9a17694c176d39733', - preferred_spot='d3043820717d74d9a17694c176d39733') + preferred_spot='d3043820717d74d9a17694c176d39733', + resource_requirements='d3043820717d74d9a17694c176d39733') ``` __Arguments__ @@ -991,6 +999,29 @@ __Arguments__ - __spot__: list[str] - __weights__: list[Weight] - __preferred_spot__: list[str] +- __resource_requirements__: ResourceRequirements + +

ResourceRequirements

+ +```python +ResourceRequirements( + self, + excluded_instance_families='d3043820717d74d9a17694c176d39733', + excluded_instance_generations='d3043820717d74d9a17694c176d39733', + excluded_instance_types='d3043820717d74d9a17694c176d39733', + required_v_cpu='d3043820717d74d9a17694c176d39733', + required_memory='d3043820717d74d9a17694c176d39733', + required_gpu='d3043820717d74d9a17694c176d39733') +``` + +__Arguments__ + +- __excluded_instance_families__: list[str] +- __excluded_instance_generations__: list[str] +- __excluded_instance_types__: list[str] +- __required_v_cpu__: RequiredMemoryVcpuGpu +- __required_memory__: RequiredMemoryVcpuGpu +- __required_gpu__: RequiredMemoryVcpuGpu

Weight

@@ -1005,6 +1036,19 @@ __Arguments__ - __instance_type__: str - __weighted_capacity__: int +

RequiredMemoryVcpuGpu

+ +```python +RequiredMemoryVcpuGpu(self, + minimum='d3043820717d74d9a17694c176d39733', + maximum='d3043820717d74d9a17694c176d39733') +``` + +__Arguments__ + +- __minimum__: int +- __maximum__: int +

TagSpecification

```python @@ -1177,6 +1221,7 @@ EBS(self, volume_type='d3043820717d74d9a17694c176d39733', kms_key_id='d3043820717d74d9a17694c176d39733', dynamic_volume_size='d3043820717d74d9a17694c176d39733', + dynamic_iops='d3043820717d74d9a17694c176d39733', throughput='d3043820717d74d9a17694c176d39733') ``` @@ -1190,6 +1235,7 @@ __Arguments__ - __volume_type__: str - __kms_key_id__: str - __dynamic_volume_size__: DynamicVolumeSize +- __dynamic_iops__: DynamicIops - __throughput__: int

DynamicVolumeSize

@@ -1208,6 +1254,21 @@ __Arguments__ - __resource__: str - __size_per_resource_unit__: int +

DynamicIops

+ +```python +DynamicIops(self, + base_size='d3043820717d74d9a17694c176d39733', + resource='d3043820717d74d9a17694c176d39733', + size_per_resource_unit='d3043820717d74d9a17694c176d39733') +``` + +__Arguments__ + +- __base_size__: int +- __resource__: str +- __size_per_resource_unit__: int +

Tag

```python @@ -1292,6 +1353,29 @@ __Arguments__ - __http_tokens__: str - __instance_metadata_tags__: str +

VolumeAttachments

+ +```python +VolumeAttachments(self, volumes='d3043820717d74d9a17694c176d39733') +``` + +__Arguments__ + +- __volumes__: list[Volume] + +

Volume

+ +```python +Volume(self, + device_name='d3043820717d74d9a17694c176d39733', + volume_id='d3043820717d74d9a17694c176d39733') +``` + +__Arguments__ + +- __device_name__: str +- __volume_id__: str +

Roll

```python @@ -1392,12 +1476,28 @@ __Arguments__ ASG(self, product='d3043820717d74d9a17694c176d39733', spot_instance_types='d3043820717d74d9a17694c176d39733', - name='d3043820717d74d9a17694c176d39733') + name='d3043820717d74d9a17694c176d39733', + availability_vs_cost='d3043820717d74d9a17694c176d39733') ``` __Arguments__ - __product__: str +- __spot_instance_types__: List[str] +- __name__: str +- __availability_vs_cost__: str + +

ImportInstanceConfig

+ +```python +ImportInstanceConfig( + self, + spot_instance_types='d3043820717d74d9a17694c176d39733', + name='d3043820717d74d9a17694c176d39733') +``` + +__Arguments__ + - __spot_instance_types__: List[str] - __name__: str diff --git a/spotinst_sdk2/clients/elastigroup/__init__.py b/spotinst_sdk2/clients/elastigroup/__init__.py index 6c7c3263..c5d79076 100644 --- a/spotinst_sdk2/clients/elastigroup/__init__.py +++ b/spotinst_sdk2/clients/elastigroup/__init__.py @@ -7,7 +7,7 @@ import spotinst_sdk2.models.elastigroup.aws.stateful as aws_stateful import spotinst_sdk2.models.elastigroup.aws.deployment as aws_deployment import spotinst_sdk2.models.elastigroup.aws.deployment_action as aws_deployment_action -import spotinst_sdk2.models.elastigroup.aws.asg as aws_asg +import spotinst_sdk2.models.elastigroup.aws.asg as aws_import # endregion # region GCP imports @@ -803,6 +803,28 @@ def pause_stateful_instance(self, group_id, stateful_instance_id): return formatted_response["response"] + def delete_volume_in_stateful_instance(self, group_id, stateful_instance_id, volume_id): + """ + Delete stateful instance + + # Arguments + group_id (String): Elastigroup ID + stateful_instance_id (String): Stateful Instance ID + volume_id (String): Volume ID + + # Returns + (Object): Elastigroup API response + """ + return self.send_delete( + url=self.__base_elastigroup_url + + "/" + + str(group_id) + + "/statefulInstance/" + + str(stateful_instance_id) + + "/volume/" + + str(volume_id), + entity_name='delete volume in stateful instance') + def beanstalk_maintenance_status(self, group_id): """ Beanstalk maintenance status @@ -931,9 +953,48 @@ def beanstalk_reimport(self, group_id): return ret_val - def import_asg(self, region, asg_name, asg, dry_run=None): + def import_instance(self, region, instance_id, instance: aws_import.ImportInstanceConfig): + """ + Import an EC2 instance into a new Elastigroup + + # Arguments + region (String): Instance Region + instance_id (String): Instance ID + instance (ImportInstanceConfig): Import Configuration + + # Returns + (Object): Elastigroup API response + """ + query_params = dict( + region=region, instanceId=instance_id) + + request = aws_import.ImportInstanceRequest(instance) + + excluded_group_dict = self.exclude_missing( + json.loads(request.toJSON())) + + formatted_group_dict = self.convert_json( + excluded_group_dict, self.underscore_to_camel) + + body_json = json.dumps(formatted_group_dict) + + response = self.send_post( + body=body_json, + url=self.__base_elastigroup_url + + "/instance/import", + query_params=query_params, + entity_name='import instance') + + formatted_response = self.convert_json( + response, self.camel_to_underscore) + + ret_val = formatted_response["response"]["items"][0] + + return ret_val + + def import_asg(self, region, asg_name, asg: aws_import.ASG, dry_run=None): """ - import asg attributes as JSON + Create a new Elastigroup using the configuration of an existing Autoscaling group # Arguments region (String): ASG region @@ -947,7 +1008,7 @@ def import_asg(self, region, asg_name, asg, dry_run=None): query_params = dict( region=region, autoScalingGroupName=asg_name, dryRun=dry_run) - asg = aws_asg.ImportASGRequest(asg) + asg = aws_import.ImportASGRequest(asg) excluded_group_dict = self.exclude_missing(json.loads(asg.toJSON())) @@ -1343,8 +1404,8 @@ def get_elastilog(self, group_id, from_date, to_date, severity=None, resource_id group_id(String): Elastigroup ID to_date (String): to date from_date (String): to date - severity(String) (Optional): Log level severity - resource_id(String) (Optional): Filter log extracted entires related to a + severity (String) (Optional): Log level severity + resource_id (String) (Optional): Filter log extracted entires related to a specific resource id limit(String) (Optional): Maximum number of lines to extract in a response @@ -1439,6 +1500,7 @@ def delete_stateful_import(self, stateful_migration_id): formatted_response = self.convert_json( content, self.camel_to_underscore) return formatted_response + # endregion diff --git a/spotinst_sdk2/models/elastigroup/aws/__init__.py b/spotinst_sdk2/models/elastigroup/aws/__init__.py index eeae189e..3fa45440 100755 --- a/spotinst_sdk2/models/elastigroup/aws/__init__.py +++ b/spotinst_sdk2/models/elastigroup/aws/__init__.py @@ -48,10 +48,12 @@ class Strategy: """ # Arguments availability_vs_cost: str + consider_o_d_pricing: bool risk: int utilize_commitments: bool utilize_reserved_instances: bool fallback_to_od: bool + max_replacements_percentage: int on_demand_count: int draining_timeout: int spin_up_time: int @@ -61,15 +63,18 @@ class Strategy: persistence: Persistence revert_to_spot: RevertToSpot restrict_single_az: bool + immediate_o_d_recover_threshold: int """ def __init__( self, availability_vs_cost=none, + consider_o_d_pricing=none, risk=none, utilize_commitments=none, utilize_reserved_instances=none, fallback_to_od=none, + max_replacements_percentage=none, on_demand_count=none, draining_timeout=none, spin_up_time=none, @@ -82,9 +87,11 @@ def __init__( restrict_single_az: bool = none): self.risk = risk + self.consider_o_d_pricing = consider_o_d_pricing self.utilize_commitments = utilize_commitments self.utilize_reserved_instances = utilize_reserved_instances self.fallback_to_od = fallback_to_od + self.max_replacements_percentage = max_replacements_percentage self.on_demand_count = on_demand_count self.availability_vs_cost = availability_vs_cost self.draining_timeout = draining_timeout @@ -1105,6 +1112,7 @@ class Compute: private_ips: list[str] subnet_ids: list[str] preferred_availability_zones: list[str] + volume_attachments: VolumeAttachments """ def __init__( @@ -1116,7 +1124,8 @@ def __init__( elastic_ips=none, private_ips=none, subnet_ids=none, - preferred_availability_zones=none): + preferred_availability_zones=none, + volume_attachments=none): self.elastic_ips = elastic_ips self.private_ips = private_ips @@ -1126,6 +1135,7 @@ def __init__( self.product = product self.launch_specification = launch_specification self.preferred_availability_zones = preferred_availability_zones + self.volume_attachments = volume_attachments class AvailabilityZone: @@ -1158,6 +1168,7 @@ class InstanceTypes: spot: list[str] weights: list[Weight] preferred_spot: list[str] + resource_requirements: ResourceRequirements """ def __init__( @@ -1166,13 +1177,43 @@ def __init__( on_demand_types=none, spot=none, weights=none, - preferred_spot=none): + preferred_spot=none, + resource_requirements=none): self.ondemand = ondemand self.on_demand_types = on_demand_types self.spot = spot self.weights = weights self.preferred_spot = preferred_spot + self.resource_requirements = resource_requirements + + +class ResourceRequirements: + """ + # Arguments + excluded_instance_families: list[str] + excluded_instance_generations: list[str] + excluded_instance_types: list[str] + required_v_cpu: RequiredMemoryVcpuGpu + required_memory: RequiredMemoryVcpuGpu + required_gpu: RequiredMemoryVcpuGpu + """ + + def __init__( + self, + excluded_instance_families=none, + excluded_instance_generations=none, + excluded_instance_types=none, + required_v_cpu=none, + required_memory=none, + required_gpu=none): + + self.excluded_instance_families = excluded_instance_families + self.excluded_instance_generations = excluded_instance_generations + self.excluded_instance_types = excluded_instance_types + self.required_v_cpu = required_v_cpu + self.required_memory = required_memory + self.required_gpu = required_gpu class Weight: @@ -1188,6 +1229,19 @@ def __init__(self, instance_type=none, weighted_capacity=none): self.weighted_capacity = weighted_capacity +class RequiredMemoryVcpuGpu: + """ + # Arguments + minimum: int + maximum: int + """ + + def __init__(self, minimum=none, maximum=none): + + self.minimum = minimum + self.maximum = maximum + + class TagSpecification: """ # Arguments @@ -1393,6 +1447,7 @@ class EBS: volume_type: str kms_key_id: str dynamic_volume_size: DynamicVolumeSize + dynamic_iops: DynamicIops throughput: int """ @@ -1406,6 +1461,7 @@ def __init__( volume_type=none, kms_key_id=none, dynamic_volume_size=none, + dynamic_iops=none, throughput=none): self.delete_on_termination = delete_on_termination @@ -1416,6 +1472,7 @@ def __init__( self.volume_type = volume_type self.kms_key_id = kms_key_id self.dynamic_volume_size = dynamic_volume_size + self.dynamic_iops = dynamic_iops self.throughput = throughput @@ -1438,6 +1495,25 @@ def __init__( self.size_per_resource_unit = size_per_resource_unit +class DynamicIops: + """ + # Arguments + base_size: int + resource: str + size_per_resource_unit: int + """ + + def __init__( + self, + base_size=none, + resource=none, + size_per_resource_unit=none): + + self.base_size = base_size + self.resource = resource + self.size_per_resource_unit = size_per_resource_unit + + class Tag: """ # Arguments @@ -1535,6 +1611,33 @@ def __init__(self, self.http_tokens = http_tokens self.instance_metadata_tags = instance_metadata_tags + +class VolumeAttachments: + """ + # Arguments + volumes: list[Volume] + """ + + def __init__(self, + volumes=none): + + self.volumes = volumes + + +class Volume: + """ + # Arguments + device_name: str + volume_id: str + """ + + def __init__(self, + device_name=none, + volume_id=none): + + self.device_name = device_name + self.volume_id = volume_id + # endregion diff --git a/spotinst_sdk2/models/elastigroup/aws/asg.py b/spotinst_sdk2/models/elastigroup/aws/asg.py index b52b4e44..4582a3d0 100644 --- a/spotinst_sdk2/models/elastigroup/aws/asg.py +++ b/spotinst_sdk2/models/elastigroup/aws/asg.py @@ -11,17 +11,40 @@ class ASG: product: str spot_instance_types: List[str] name: str + availability_vs_cost: str """ def __init__( self, product=none, spot_instance_types=none, - name=none): + name=none, + availability_vs_cost=none): self.product = product self.spot_instance_types = spot_instance_types self.name = name + self.availability_vs_cost = availability_vs_cost + +# endregion + +# region Instance + + +class ImportInstanceConfig: + """ + # Arguments + spot_instance_types: List[str] + name: str + """ + + def __init__( + self, + spot_instance_types=none, + name=none): + + self.spot_instance_types = spot_instance_types + self.name = name # endregion @@ -33,3 +56,12 @@ def __init__(self, group): def toJSON(self): return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4) + + +class ImportInstanceRequest: + def __init__(self, group): + self.group = group + + def toJSON(self): + return json.dumps(self, default=lambda o: o.__dict__, + sort_keys=True, indent=4) diff --git a/spotinst_sdk2/version.py b/spotinst_sdk2/version.py index f3bb9e91..405c30df 100644 --- a/spotinst_sdk2/version.py +++ b/spotinst_sdk2/version.py @@ -1 +1 @@ -__version__ = '3.15.1' +__version__ = '3.16.1'