diff --git a/README.md b/README.md index 0548dece..5ed7d46a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This repo contains the NixOps AWS Plugin. * [Source code](https://github.com/NixOS/nixops) * [Issue Tracker](https://github.com/NixOS/nixops/issues) * [Mailing list / Google group](https://groups.google.com/forum/#!forum/nixops-users) -* [IRC - #nixos on freenode.net](irc://irc.freenode.net/#nixos) +* [Matrix - #nix:nixos.org](https://matrix.to/#/#nix:nixos.org) ## Developing diff --git a/coverage-tests.py b/coverage-tests.py index 2007904f..60a41262 100755 --- a/coverage-tests.py +++ b/coverage-tests.py @@ -15,7 +15,7 @@ "--cover-package=nixops", "--nocapture", "-e", - "^tests\.py$", + "^tests\\.py$", ] + sys.argv[1:] ) diff --git a/nixops_aws/nix/aws-ec2-launch-template.nix b/nixops_aws/nix/aws-ec2-launch-template.nix new file mode 100644 index 00000000..70b2ffc1 --- /dev/null +++ b/nixops_aws/nix/aws-ec2-launch-template.nix @@ -0,0 +1,124 @@ +{ config, lib, uuid, name, ... }: + +with import ./lib.nix lib; +with lib; + +{ + imports = [ ./common-ec2-auth-options.nix ]; + + options = { + + name = mkOption { + default = "nixops-${uuid}-${name}"; + type = types.str; + description = "Name of the launch template."; + }; + + templateId = mkOption { + default = ""; + type = types.str; + description = "ec2 launch template ID (set by NixOps)"; + }; + + versionDescription = mkOption { + default = ""; + type = types.str; + description = "A description for the version of the launch template"; + }; + + + # we might want to make this in a way similar to ec2.nix + ebsOptimized = mkOption { + default = true; + description = '' + Whether the EC2 instance should be created as an EBS Optimized instance. + ''; + type = types.bool; + }; + + userData = mkOption { + default = null; + type = types.nullOr types.str; + description = '' + The user data to make available to the instance. + It should be valid nix expressions. + ''; + }; + + # add support for ec2 then move to common + disableApiTermination = mkOption { + default = false; + type = types.bool; + description = '' + If set to true , you can't terminate the instance + using the Amazon EC2 console, CLI, or API. + ''; + }; + + # add support for ec2 then move to common + instanceInitiatedShutdownBehavior = mkOption { + default = "terminate"; + type = types.enum ["stop" "terminate"]; + description = '' + Indicates whether an instance stops or terminates + when you initiate shutdown from the instance (using + the operating system command for system shutdown). + ''; + }; + # add support for ec2 then move to common + networkInterfaceId = mkOption { + default = ""; + # must get the id fro mthe name + type = with types; either str (resource "vpc-network-interface"); + apply = x: if builtins.isString x then x else "res-" + x._name "." + x._type; + description = '' + The ID of the network interface. + ''; + }; + + privateIpAddresses = mkOption { + default = null; + type = with types; (nullOr (listOf str)); + description = '' + One or more secondary private IPv4 addresses. + ''; + }; + secondaryPrivateIpAddressCount = mkOption { + default = null; + type = types.nullOr types.int; + description = '' + The number of secondary private IPv4 addresses to assign to a network interface. + When you specify a number of secondary IPv4 addresses, Amazon EC2 selects these + IP addresses within the subnet's IPv4 CIDR range. + You can't specify this option and specify privateIpAddresses in the same time. + ''; + }; + + instanceTags = mkOption { + default = { }; + example = { foo = "bar"; xyzzy = "bla"; }; + type = types.attrsOf types.str; + description = '' + Default tags assigned to each instance launched using the template. Each tag + name can be at most 128 characters, and each tag value can be at most 256 + characters. There can be at most 10 tags. + ''; + }; + + volumeTags = mkOption { + default = { }; + example = { foo = "bar"; xyzzy = "bla"; }; + type = types.attrsOf types.str; + description = '' + Default tags assigned to each volume created using the template. Each tag + name can be at most 128 characters, and each tag value can be at most 256 + characters. There can be at most 10 tags. + ''; + }; + + } + // (import ./common-ec2-options.nix { inherit lib; }) + // (import ./common-ec2-instance-options.nix { inherit lib; }); + + config._type = "aws-ec2-launch-template"; +} \ No newline at end of file diff --git a/nixops_aws/nix/aws-spot-fleet-request.nix b/nixops_aws/nix/aws-spot-fleet-request.nix new file mode 100644 index 00000000..b955a7ac --- /dev/null +++ b/nixops_aws/nix/aws-spot-fleet-request.nix @@ -0,0 +1,208 @@ +{ config, lib, uuid, name, ... }: + +with lib; + + +let + cfg = config.awsSpotFleetRequest; + + launchSpecificationOptions = { + options = { + }; + }; + + fleetLaunchTemplateSpecificationOptions = { + options = { + launchTemplateName = mkOption { + type = types.str; + description = "The name of the launch template. If you specify the template name, you can't specify the template ID."; + }; + + version = mkOption { + type = types.str; + description = '' + The launch template version number, "$Latest", or "$Default". + If the value is "$Latest", Amazon EC2 uses the latest version of the launch template. + If the value is "$Default", Amazon EC2 uses the default version of the launch template. + ''; + }; + }; + }; + + launchTemplateOverridesOptions = { + options = { + spotPrice = mkOption { + default = null; + # example = ; + type = with types; nullOr str; + description = "The maximum price per unit hour that you are willing to pay for a Spot Instance."; + }; + + subnetId = mkOption { + default = null; + # example = ; + type = with types; nullOr str; + # description = "The ID of the subnet in which to launch the instances."; + }; + + availabilityZone = mkOption { + default = null; + # example = ; + type = with types; nullOr str; + description = "The Availability Zone in which to launch the instances."; + }; + + weightedCapacity = mkOption { + default = null; + # example = ; + type = with types; nullOr float; + description = "The number of units provided by the specified instance type."; + }; + + priority = mkOption { + default = null; + # example = ; + type = with types; nullOr float; + description = '' + The priority for the launch template override. The highest priority is launched first. + If OnDemandAllocationStrategy is set to "prioritized", Spot Fleet uses priority to determine which launch template override to use first in fulfilling On-Demand capacity. + If the Spot AllocationStrategy is set to "capacityOptimizedPrioritized", Spot Fleet uses priority on a best-effort basis to determine which launch template override to use in fulfilling Spot capacity, but optimizes for capacity first. + Valid values are whole numbers starting at 0. The lower the number, the higher the priority. If no number is set, the launch template override has the lowest priority. You can set the same priority for different launch template overrides. + ''; + }; + + # Common EC2 instance options + instanceType = mkOption { + default = null; + # example = ; + type = with types; nullOr str; + description = "The instance type."; + }; + }; + }; + + launchTemplateConfigOptions = { + options = { + launchTemplateSpecification = mkOption { + type = types.submodule fleetLaunchTemplateSpecificationOptions; + description = "The launch template."; + }; + + overrides = mkOption { + default = [ ]; # Optional + example = [ + { + instanceType = "m1.small"; + weightedCapacity = 1.; + } + { + instanceType = "m3.medium"; + weightedCapacity = 1.; + } + { + instanceType = "m1.medium"; + weightedCapacity = 1.; + } + ]; + type = with types; listOf (types.submodule launchTemplateOverridesOptions); + description = "Any parameters that you specify override the same parameters in the launch template."; + }; + }; + }; +in +{ + imports = [ ./common-ec2-auth-options.nix ]; + + options = { + + spotFleetRequestId = mkOption { + default = ""; + type = types.str; + description = "Spot fleet request ID (set by NixOps)"; + }; + + iamFleetRole = mkOption { + type = types.str; + description = '' + The Amazon Resource Name (ARN) of an Identity and Access Management + (IAM) role that grants the Spot Fleet the permission to request, + launch, terminate, and tag instances on your behalf. + + Spot Fleet can terminate Spot Instances on your behalf when you cancel + its Spot Fleet request or when the Spot Fleet request expires, if you + set TerminateInstancesWithExpiration. + ''; + }; + + launchTemplateConfigs = mkOption + { + type = with types; listOf (submodule launchTemplateConfigOptions); + description = '' + The launch template and overrides. If you specify LaunchTemplateConfigs, you can't specify LaunchSpecifications. If you include On-Demand capacity in your request, you must use LaunchTemplateConfigs. + ''; + }; + + spotPrice = mkOption { + type = with types; nullOr str; + description = '' + The maximum price per unit hour that you are willing to pay for a Spot Instance. The default is the On-Demand price. + ''; + }; + + spotMaxTotalPrice = mkOption { + type = with types; nullOr str; + description = "The maximum amount per hour for Spot Instances that you're willing to pay. You can use the spotdMaxTotalPrice parameter, the onDemandMaxTotalPrice parameter, or both parameters to ensure that your fleet cost does not exceed your budget. If you set a maximum price per hour for the On-Demand Instances and Spot Instances in your request, Spot Fleet will launch instances until it reaches the maximum amount you're willing to pay. When the maximum amount you're willing to pay is reached, the fleet stops launching instances even if it hasn’t met the target capacity."; + }; + + type = mkOption { + default = "maintain"; + example = "request"; + type = + types.enum [ + "request" + "maintain" + # "instant" # instant is listed but is not used by Spot Fleet. + ]; + description = '' + The type of request. Indicates whether the Spot Fleet only requests + the target capacity or also attempts to maintain it. When this + value is request, the Spot Fleet only places the + required requests. It does not attempt to replenish Spot Instances if + capacity is diminished, nor does it submit requests in alternative Spot + pools if capacity is not available. When this value is + maintain, the Spot Fleet maintains the target capacity. + The Spot Fleet places the required requests to meet capacity and + automatically replenishes any interrupted instances. + ''; + }; + + iamFleetRole = mkOption { + # example = "rolename"; # TODO + type = types.str; + description = '' + The Amazon Resource Name (ARN) of an Identity and Access Management + (IAM) role that grants the Spot Fleet the permission to request, + launch, terminate, and tag instances on your behalf. + + Spot Fleet can terminate Spot Instances on your behalf when you cancel + its Spot Fleet request or when the Spot Fleet request expires, if you + set TerminateInstancesWithExpiration. + ''; + }; + + launchTemplateConfigs = mkOption + { + type = with types; listOf (submodule launchTemplateConfigOptions); + description = '' + The launch template and overrides. If you specify LaunchTemplateConfigs, you can't specify LaunchSpecifications. If you include On-Demand capacity in your request, you must use LaunchTemplateConfigs. + ''; + }; + + } + // (import ./common-ec2-options.nix { inherit lib; }); + + config._type = "aws-spot-fleet-request"; + +} + + diff --git a/nixops_aws/nix/common-ec2-instance-options.nix b/nixops_aws/nix/common-ec2-instance-options.nix new file mode 100644 index 00000000..a4e85976 --- /dev/null +++ b/nixops_aws/nix/common-ec2-instance-options.nix @@ -0,0 +1,168 @@ +# Options shared between an ec2 resource type and the +# launch template resource in EC2 +# instances. + +{ lib }: + +with lib; +with import ./lib.nix lib; +{ + + zone = mkOption { + default = ""; + example = "us-east-1c"; + type = types.str; + description = '' + The EC2 availability zone in which the instance should be + created. If not specified, a zone is selected automatically. + ''; + }; + + # add support for ec2 + monitoring = mkOption { + default = false; + type = types.bool; + description = '' + if set to true, detailed monitoring is enabled. + Otherwise, basic monitoring is enabled. + ''; + }; + + tenancy = mkOption { + default = "default"; + type = types.enum [ "default" "dedicated" "host" ]; + description = '' + The tenancy of the instance (if the instance is running in a VPC). + An instance with a tenancy of dedicated runs on single-tenant hardware. + An instance with host tenancy runs on a Dedicated Host, which is an + isolated server with configurations that you can control. + ''; + }; + + ebsInitialRootDiskSize = mkOption { + default = 0; + type = types.int; + description = '' + Preferred size (G) of the root disk of the EBS-backed instance. By + default, EBS-backed images have a size determined by the + AMI. Only supported on creation of the instance. + ''; + }; + + ami = mkOption { + example = "ami-00000000"; + type = types.str; + description = '' + EC2 identifier of the AMI disk image used in the virtual + machine. This must be a NixOS image providing SSH access. + ''; + }; + + instanceType = mkOption { + default = "m1.small"; + example = "m1.large"; + type = types.str; + description = '' + EC2 instance type. See for a + list of valid Amazon EC2 instance types. + ''; + }; + + instanceProfile = mkOption { + default = ""; + example = "rolename"; + type = types.str; + description = '' + The name of the IAM Instance Profile (IIP) to associate with + the instances. + ''; + }; + + keyPair = mkOption { + example = "my-keypair"; + type = types.either types.str (resource "ec2-keypair"); + apply = x: if builtins.isString x then x else x.name; + description = '' + Name of the SSH key pair to be used to communicate securely + with the instance. Key pairs can be created using the + ec2-add-keypair command. + ''; + }; + + securityGroupIds = mkOption { + default = [ "default" ]; + type = types.listOf types.str; + description = '' + Security Group IDs for the instance. Necessary if starting + an instance inside a VPC/subnet. In the non-default VPC, security + groups needs to be specified by ID and not name. + ''; + }; + + subnetId = mkOption { + default = ""; + example = "subnet-00000000"; + type = types.either types.str (resource "vpc-subnet"); + apply = x: if builtins.isString x then x else "res-" + x._name + "." + x._type; + description = '' + The subnet inside a VPC to launch the instance in. + ''; + }; + + associatePublicIpAddress = mkOption { + default = false; + type = types.bool; + description = '' + If instance in a subnet/VPC, whether to associate a public + IP address with the instance. + ''; + }; + + placementGroup = mkOption { + default = ""; + example = "my-cluster"; + type = types.either types.str (resource "ec2-placement-group"); + apply = x: if builtins.isString x then x else x.name; + description = '' + Placement group for the instance. + ''; + }; + + spotInstancePrice = mkOption { + default = 0; + type = types.int; + description = '' + Price (in dollar cents per hour) to use for spot instances request for the machine. + If the value is equal to 0 (default), then spot instances are not used. + ''; + }; + + spotInstanceRequestType = mkOption { + default = "one-time"; + type = types.enum [ "one-time" "persistent" ]; + description = '' + The type of the spot instance request. It can be either "one-time" or "persistent". + ''; + }; + + spotInstanceInterruptionBehavior = mkOption { + default = "terminate"; + type = types.enum [ "terminate" "stop" "hibernate" ]; + description = '' + Whether to terminate, stop or hibernate the instance when it gets interrupted. + For stop, spotInstanceRequestType must be set to "persistent". + ''; + }; + + spotInstanceTimeout = mkOption { + default = 0; + type = types.int; + description = '' + The duration (in seconds) that the spot instance request is + valid. If the request cannot be satisfied in this amount of + time, the request will be cancelled automatically, and NixOps + will fail with an error message. The default (0) is no timeout. + ''; + }; +} \ No newline at end of file diff --git a/nixops_aws/nix/default.nix b/nixops_aws/nix/default.nix index 380045a7..356f4d01 100644 --- a/nixops_aws/nix/default.nix +++ b/nixops_aws/nix/default.nix @@ -46,5 +46,7 @@ awsVPNConnections = evalResources ./aws-vpn-connection.nix (zipAttrs resourcesByType.awsVPNConnections or []); awsVPNConnectionRoutes = evalResources ./aws-vpn-connection-route.nix (zipAttrs resourcesByType.awsVPNConnectionRoutes or []); awsDataLifecycleManager = evalResources ./aws-data-lifecycle-manager.nix (zipAttrs resourcesByType.awsDataLifecycleManager or []); + awsEc2LaunchTemplate = evalResources ./aws-ec2-launch-template.nix (zipAttrs resourcesByType.awsEc2LaunchTemplate or []); + awsSpotFleetRequest = evalResources ./aws-spot-fleet-request.nix (zipAttrs resourcesByType.awsSpotFleetRequest or []); }; } diff --git a/nixops_aws/nix/ec2-properties.nix b/nixops_aws/nix/ec2-properties.nix index 99f3780d..93934388 100644 --- a/nixops_aws/nix/ec2-properties.nix +++ b/nixops_aws/nix/ec2-properties.nix @@ -17,15 +17,15 @@ "c4.8xlarge" = { allowsEbsOptimized = true; cores = 36; memory = 61440; supportsNVMe = false; }; "c4.large" = { allowsEbsOptimized = true; cores = 2; memory = 3840; supportsNVMe = false; }; "c4.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 7680; supportsNVMe = false; }; - "c5.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 98304; supportsNVMe = false; }; - "c5.18xlarge" = { allowsEbsOptimized = true; cores = 72; memory = 147456; supportsNVMe = false; }; - "c5.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 196608; supportsNVMe = false; }; - "c5.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = false; }; - "c5.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 32768; supportsNVMe = false; }; - "c5.9xlarge" = { allowsEbsOptimized = true; cores = 36; memory = 73728; supportsNVMe = false; }; - "c5.large" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = false; }; - "c5.metal" = { allowsEbsOptimized = true; cores = 96; memory = 196608; supportsNVMe = false; }; - "c5.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = false; }; + "c5.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 98304; supportsNVMe = true; }; + "c5.18xlarge" = { allowsEbsOptimized = true; cores = 72; memory = 147456; supportsNVMe = true; }; + "c5.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 196608; supportsNVMe = true; }; + "c5.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = true; }; + "c5.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 32768; supportsNVMe = true; }; + "c5.9xlarge" = { allowsEbsOptimized = true; cores = 36; memory = 73728; supportsNVMe = true; }; + "c5.large" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = true; }; + "c5.metal" = { allowsEbsOptimized = true; cores = 96; memory = 196608; supportsNVMe = true; }; + "c5.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = true; }; "c5a.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 98304; supportsNVMe = true; }; "c5a.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = true; }; "c5a.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 196608; supportsNVMe = true; }; @@ -51,22 +51,22 @@ "c5d.large" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = true; }; "c5d.metal" = { allowsEbsOptimized = true; cores = 96; memory = 196608; supportsNVMe = true; }; "c5d.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = true; }; - "c5n.18xlarge" = { allowsEbsOptimized = true; cores = 72; memory = 196608; supportsNVMe = false; }; - "c5n.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 21504; supportsNVMe = false; }; - "c5n.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 43008; supportsNVMe = false; }; - "c5n.9xlarge" = { allowsEbsOptimized = true; cores = 36; memory = 98304; supportsNVMe = false; }; - "c5n.large" = { allowsEbsOptimized = true; cores = 2; memory = 5376; supportsNVMe = false; }; - "c5n.metal" = { allowsEbsOptimized = true; cores = 72; memory = 196608; supportsNVMe = false; }; - "c5n.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 10752; supportsNVMe = false; }; - "c6g.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 98304; supportsNVMe = false; }; - "c6g.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = false; }; - "c6g.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = false; }; - "c6g.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 32768; supportsNVMe = false; }; - "c6g.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 65536; supportsNVMe = false; }; - "c6g.large" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = false; }; - "c6g.medium" = { allowsEbsOptimized = true; cores = 1; memory = 2048; supportsNVMe = false; }; - "c6g.metal" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = false; }; - "c6g.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = false; }; + "c5n.18xlarge" = { allowsEbsOptimized = true; cores = 72; memory = 196608; supportsNVMe = true; }; + "c5n.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 21504; supportsNVMe = true; }; + "c5n.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 43008; supportsNVMe = true; }; + "c5n.9xlarge" = { allowsEbsOptimized = true; cores = 36; memory = 98304; supportsNVMe = true; }; + "c5n.large" = { allowsEbsOptimized = true; cores = 2; memory = 5376; supportsNVMe = true; }; + "c5n.metal" = { allowsEbsOptimized = true; cores = 72; memory = 196608; supportsNVMe = true; }; + "c5n.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 10752; supportsNVMe = true; }; + "c6g.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 98304; supportsNVMe = true; }; + "c6g.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = true; }; + "c6g.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = true; }; + "c6g.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 32768; supportsNVMe = true; }; + "c6g.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 65536; supportsNVMe = true; }; + "c6g.large" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = true; }; + "c6g.medium" = { allowsEbsOptimized = true; cores = 1; memory = 2048; supportsNVMe = true; }; + "c6g.metal" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = true; }; + "c6g.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = true; }; "c6gd.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 98304; supportsNVMe = true; }; "c6gd.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = true; }; "c6gd.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = true; }; @@ -76,30 +76,30 @@ "c6gd.medium" = { allowsEbsOptimized = true; cores = 1; memory = 2048; supportsNVMe = true; }; "c6gd.metal" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = true; }; "c6gd.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = true; }; - "c6gn.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 98304; supportsNVMe = false; }; - "c6gn.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = false; }; - "c6gn.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = false; }; - "c6gn.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 32768; supportsNVMe = false; }; - "c6gn.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 65536; supportsNVMe = false; }; - "c6gn.large" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = false; }; - "c6gn.medium" = { allowsEbsOptimized = true; cores = 1; memory = 2048; supportsNVMe = false; }; - "c6gn.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = false; }; + "c6gn.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 98304; supportsNVMe = true; }; + "c6gn.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 131072; supportsNVMe = true; }; + "c6gn.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = true; }; + "c6gn.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 32768; supportsNVMe = true; }; + "c6gn.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 65536; supportsNVMe = true; }; + "c6gn.large" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = true; }; + "c6gn.medium" = { allowsEbsOptimized = true; cores = 1; memory = 2048; supportsNVMe = true; }; + "c6gn.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = true; }; "cr1.8xlarge" = { cores = 32; memory = 249856; allowsEbsOptimized = true; supportsNVMe = false;}; "cc2.8xlarge" = { allowsEbsOptimized = false; cores = 32; memory = 61952; supportsNVMe = false; }; "d2.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 62464; supportsNVMe = false; }; "d2.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 124928; supportsNVMe = false; }; "d2.8xlarge" = { allowsEbsOptimized = true; cores = 36; memory = 249856; supportsNVMe = false; }; "d2.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 31232; supportsNVMe = false; }; - "d3.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = false; }; - "d3.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 131072; supportsNVMe = false; }; - "d3.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 262144; supportsNVMe = false; }; - "d3.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = false; }; - "d3en.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = false; }; - "d3en.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = false; }; - "d3en.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = false; }; - "d3en.6xlarge" = { allowsEbsOptimized = true; cores = 24; memory = 98304; supportsNVMe = false; }; - "d3en.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = false; }; - "d3en.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; + "d3.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = true; }; + "d3.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 131072; supportsNVMe = true; }; + "d3.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 262144; supportsNVMe = true; }; + "d3.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = true; }; + "d3en.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; + "d3en.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; + "d3en.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = true; }; + "d3en.6xlarge" = { allowsEbsOptimized = true; cores = 24; memory = 98304; supportsNVMe = true; }; + "d3en.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = true; }; + "d3en.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; "f1.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 999424; supportsNVMe = false; }; "f1.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 124928; supportsNVMe = true; }; "f1.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 249856; supportsNVMe = true; }; @@ -110,8 +110,10 @@ "g3.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 249856; supportsNVMe = false; }; "g3s.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 31232; supportsNVMe = false; }; "g4ad.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = true; }; + "g4ad.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; "g4ad.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = true; }; "g4ad.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = true; }; + "g4ad.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; "g4dn.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; "g4dn.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = true; }; "g4dn.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; @@ -143,10 +145,10 @@ "i3en.large" = { allowsEbsOptimized = true; cores = 2; memory = 16384; supportsNVMe = true; }; "i3en.metal" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = true; }; "i3en.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = true; }; - "inf1.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 196608; supportsNVMe = false; }; - "inf1.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = false; }; - "inf1.6xlarge" = { allowsEbsOptimized = true; cores = 24; memory = 49152; supportsNVMe = false; }; - "inf1.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = false; }; + "inf1.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 196608; supportsNVMe = true; }; + "inf1.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 16384; supportsNVMe = true; }; + "inf1.6xlarge" = { allowsEbsOptimized = true; cores = 24; memory = 49152; supportsNVMe = true; }; + "inf1.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 8192; supportsNVMe = true; }; "m1.large" = { allowsEbsOptimized = true; cores = 2; memory = 7680; supportsNVMe = false; }; "m1.medium" = { allowsEbsOptimized = false; cores = 1; memory = 3788; supportsNVMe = false; }; "m1.small" = { allowsEbsOptimized = false; cores = 1; memory = 1740; supportsNVMe = false; }; @@ -164,23 +166,23 @@ "m4.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = false; }; "m4.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = false; }; "m4.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; - "m5.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = false; }; - "m5.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = false; }; - "m5.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 393216; supportsNVMe = false; }; - "m5.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = false; }; - "m5.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = false; }; - "m5.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = false; }; - "m5.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = false; }; - "m5.metal" = { allowsEbsOptimized = true; cores = 96; memory = 393216; supportsNVMe = false; }; - "m5.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; - "m5a.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = false; }; - "m5a.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = false; }; - "m5a.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 393216; supportsNVMe = false; }; - "m5a.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = false; }; - "m5a.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = false; }; - "m5a.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = false; }; - "m5a.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = false; }; - "m5a.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; + "m5.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; + "m5.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = true; }; + "m5.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 393216; supportsNVMe = true; }; + "m5.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; + "m5.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = true; }; + "m5.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = true; }; + "m5.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = true; }; + "m5.metal" = { allowsEbsOptimized = true; cores = 96; memory = 393216; supportsNVMe = true; }; + "m5.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; + "m5a.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; + "m5a.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = true; }; + "m5a.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 393216; supportsNVMe = true; }; + "m5a.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; + "m5a.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = true; }; + "m5a.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = true; }; + "m5a.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = true; }; + "m5a.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; "m5ad.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; "m5ad.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = true; }; "m5ad.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 393216; supportsNVMe = true; }; @@ -216,22 +218,22 @@ "m5n.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = true; }; "m5n.metal" = { allowsEbsOptimized = true; cores = 96; memory = 393216; supportsNVMe = true; }; "m5n.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; - "m5zn.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = false; }; - "m5zn.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = false; }; - "m5zn.3xlarge" = { allowsEbsOptimized = true; cores = 12; memory = 49152; supportsNVMe = false; }; - "m5zn.6xlarge" = { allowsEbsOptimized = true; cores = 24; memory = 98304; supportsNVMe = false; }; - "m5zn.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = false; }; - "m5zn.metal" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = false; }; - "m5zn.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; - "m6g.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = false; }; - "m6g.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = false; }; - "m6g.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = false; }; - "m6g.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = false; }; - "m6g.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = false; }; - "m6g.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = false; }; - "m6g.medium" = { allowsEbsOptimized = true; cores = 1; memory = 4096; supportsNVMe = false; }; - "m6g.metal" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = false; }; - "m6g.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; + "m5zn.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; + "m5zn.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; + "m5zn.3xlarge" = { allowsEbsOptimized = true; cores = 12; memory = 49152; supportsNVMe = true; }; + "m5zn.6xlarge" = { allowsEbsOptimized = true; cores = 24; memory = 98304; supportsNVMe = true; }; + "m5zn.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = true; }; + "m5zn.metal" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; + "m5zn.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; + "m6g.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; + "m6g.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = true; }; + "m6g.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; + "m6g.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 65536; supportsNVMe = true; }; + "m6g.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 131072; supportsNVMe = true; }; + "m6g.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = true; }; + "m6g.medium" = { allowsEbsOptimized = true; cores = 1; memory = 4096; supportsNVMe = true; }; + "m6g.metal" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = true; }; + "m6g.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; "m6gd.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 196608; supportsNVMe = true; }; "m6gd.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 262144; supportsNVMe = true; }; "m6gd.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; @@ -261,23 +263,23 @@ "r4.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 249856; supportsNVMe = false; }; "r4.large" = { allowsEbsOptimized = true; cores = 2; memory = 15616; supportsNVMe = false; }; "r4.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 31232; supportsNVMe = false; }; - "r5.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 393216; supportsNVMe = false; }; - "r5.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = false; }; - "r5.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = false; }; - "r5.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = false; }; - "r5.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 131072; supportsNVMe = false; }; - "r5.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 262144; supportsNVMe = false; }; - "r5.large" = { allowsEbsOptimized = true; cores = 2; memory = 16384; supportsNVMe = false; }; - "r5.metal" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = false; }; - "r5.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = false; }; - "r5a.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 393216; supportsNVMe = false; }; - "r5a.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = false; }; - "r5a.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = false; }; - "r5a.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = false; }; - "r5a.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 131072; supportsNVMe = false; }; - "r5a.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 262144; supportsNVMe = false; }; - "r5a.large" = { allowsEbsOptimized = true; cores = 2; memory = 16384; supportsNVMe = false; }; - "r5a.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = false; }; + "r5.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 393216; supportsNVMe = true; }; + "r5.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = true; }; + "r5.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = true; }; + "r5.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = true; }; + "r5.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 131072; supportsNVMe = true; }; + "r5.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 262144; supportsNVMe = true; }; + "r5.large" = { allowsEbsOptimized = true; cores = 2; memory = 16384; supportsNVMe = true; }; + "r5.metal" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = true; }; + "r5.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = true; }; + "r5a.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 393216; supportsNVMe = true; }; + "r5a.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = true; }; + "r5a.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = true; }; + "r5a.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = true; }; + "r5a.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 131072; supportsNVMe = true; }; + "r5a.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 262144; supportsNVMe = true; }; + "r5a.large" = { allowsEbsOptimized = true; cores = 2; memory = 16384; supportsNVMe = true; }; + "r5a.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = true; }; "r5ad.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 393216; supportsNVMe = true; }; "r5ad.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = true; }; "r5ad.24xlarge" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = true; }; @@ -322,15 +324,15 @@ "r5n.large" = { allowsEbsOptimized = true; cores = 2; memory = 16384; supportsNVMe = true; }; "r5n.metal" = { allowsEbsOptimized = true; cores = 96; memory = 786432; supportsNVMe = true; }; "r5n.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = true; }; - "r6g.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 393216; supportsNVMe = false; }; - "r6g.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = false; }; - "r6g.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = false; }; - "r6g.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 131072; supportsNVMe = false; }; - "r6g.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 262144; supportsNVMe = false; }; - "r6g.large" = { allowsEbsOptimized = true; cores = 2; memory = 16384; supportsNVMe = false; }; - "r6g.medium" = { allowsEbsOptimized = true; cores = 1; memory = 8192; supportsNVMe = false; }; - "r6g.metal" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = false; }; - "r6g.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = false; }; + "r6g.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 393216; supportsNVMe = true; }; + "r6g.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = true; }; + "r6g.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = true; }; + "r6g.4xlarge" = { allowsEbsOptimized = true; cores = 16; memory = 131072; supportsNVMe = true; }; + "r6g.8xlarge" = { allowsEbsOptimized = true; cores = 32; memory = 262144; supportsNVMe = true; }; + "r6g.large" = { allowsEbsOptimized = true; cores = 2; memory = 16384; supportsNVMe = true; }; + "r6g.medium" = { allowsEbsOptimized = true; cores = 1; memory = 8192; supportsNVMe = true; }; + "r6g.metal" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = true; }; + "r6g.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 32768; supportsNVMe = true; }; "r6gd.12xlarge" = { allowsEbsOptimized = true; cores = 48; memory = 393216; supportsNVMe = true; }; "r6gd.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 524288; supportsNVMe = true; }; "r6gd.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 65536; supportsNVMe = true; }; @@ -348,27 +350,31 @@ "t2.nano" = { allowsEbsOptimized = false; cores = 1; memory = 512; supportsNVMe = false; }; "t2.small" = { allowsEbsOptimized = false; cores = 1; memory = 2048; supportsNVMe = false; }; "t2.xlarge" = { allowsEbsOptimized = false; cores = 4; memory = 16384; supportsNVMe = false; }; - "t3.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = false; }; - "t3.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = false; }; - "t3.medium" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = false; }; - "t3.micro" = { allowsEbsOptimized = true; cores = 2; memory = 1024; supportsNVMe = false; }; - "t3.nano" = { allowsEbsOptimized = true; cores = 2; memory = 512; supportsNVMe = false; }; - "t3.small" = { allowsEbsOptimized = true; cores = 2; memory = 2048; supportsNVMe = false; }; - "t3.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; - "t3a.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = false; }; - "t3a.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = false; }; - "t3a.medium" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = false; }; - "t3a.micro" = { allowsEbsOptimized = true; cores = 2; memory = 1024; supportsNVMe = false; }; - "t3a.nano" = { allowsEbsOptimized = true; cores = 2; memory = 512; supportsNVMe = false; }; - "t3a.small" = { allowsEbsOptimized = true; cores = 2; memory = 2048; supportsNVMe = false; }; - "t3a.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; - "t4g.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = false; }; - "t4g.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = false; }; - "t4g.medium" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = false; }; - "t4g.micro" = { allowsEbsOptimized = true; cores = 2; memory = 1024; supportsNVMe = false; }; - "t4g.nano" = { allowsEbsOptimized = true; cores = 2; memory = 512; supportsNVMe = false; }; - "t4g.small" = { allowsEbsOptimized = true; cores = 2; memory = 2048; supportsNVMe = false; }; - "t4g.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = false; }; + "t3.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; + "t3.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = true; }; + "t3.medium" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = true; }; + "t3.micro" = { allowsEbsOptimized = true; cores = 2; memory = 1024; supportsNVMe = true; }; + "t3.nano" = { allowsEbsOptimized = true; cores = 2; memory = 512; supportsNVMe = true; }; + "t3.small" = { allowsEbsOptimized = true; cores = 2; memory = 2048; supportsNVMe = true; }; + "t3.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; + "t3a.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; + "t3a.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = true; }; + "t3a.medium" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = true; }; + "t3a.micro" = { allowsEbsOptimized = true; cores = 2; memory = 1024; supportsNVMe = true; }; + "t3a.nano" = { allowsEbsOptimized = true; cores = 2; memory = 512; supportsNVMe = true; }; + "t3a.small" = { allowsEbsOptimized = true; cores = 2; memory = 2048; supportsNVMe = true; }; + "t3a.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; + "t4g.2xlarge" = { allowsEbsOptimized = true; cores = 8; memory = 32768; supportsNVMe = true; }; + "t4g.large" = { allowsEbsOptimized = true; cores = 2; memory = 8192; supportsNVMe = true; }; + "t4g.medium" = { allowsEbsOptimized = true; cores = 2; memory = 4096; supportsNVMe = true; }; + "t4g.micro" = { allowsEbsOptimized = true; cores = 2; memory = 1024; supportsNVMe = true; }; + "t4g.nano" = { allowsEbsOptimized = true; cores = 2; memory = 512; supportsNVMe = true; }; + "t4g.small" = { allowsEbsOptimized = true; cores = 2; memory = 2048; supportsNVMe = true; }; + "t4g.xlarge" = { allowsEbsOptimized = true; cores = 4; memory = 16384; supportsNVMe = true; }; + "u-12tb1.112xlarge" = { allowsEbsOptimized = true; cores = 448; memory = 12582912; supportsNVMe = true; }; + "u-6tb1.112xlarge" = { allowsEbsOptimized = true; cores = 448; memory = 6291456; supportsNVMe = true; }; + "u-6tb1.56xlarge" = { allowsEbsOptimized = true; cores = 224; memory = 6291456; supportsNVMe = true; }; + "u-9tb1.112xlarge" = { allowsEbsOptimized = true; cores = 448; memory = 9437184; supportsNVMe = true; }; "x1.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 999424; supportsNVMe = false; }; "x1.32xlarge" = { allowsEbsOptimized = true; cores = 128; memory = 1998848; supportsNVMe = false; }; "x1e.16xlarge" = { allowsEbsOptimized = true; cores = 64; memory = 1998848; supportsNVMe = false; }; diff --git a/nixops_aws/nix/ec2.nix b/nixops_aws/nix/ec2.nix index cf57453b..82c7af80 100644 --- a/nixops_aws/nix/ec2.nix +++ b/nixops_aws/nix/ec2.nix @@ -173,9 +173,9 @@ in ###### interface - options = { + options.deployment.ec2 = { - deployment.ec2.accessKeyId = mkOption { + accessKeyId = mkOption { default = ""; example = "AKIABOGUSACCESSKEY"; type = types.str; @@ -197,7 +197,7 @@ in ''; }; - deployment.ec2.region = mkOption { + region = mkOption { default = ""; example = "us-east-1"; type = types.str; @@ -208,28 +208,7 @@ in ''; }; - deployment.ec2.zone = mkOption { - default = ""; - example = "us-east-1c"; - type = types.str; - description = '' - The EC2 availability zone in which the instance should be - created. If not specified, a zone is selected automatically. - ''; - }; - - deployment.ec2.tenancy = mkOption { - default = "default"; - type = types.enum [ "default" "dedicated" "host" ]; - description = '' - The tenancy of the instance (if the instance is running in a VPC). - An instance with a tenancy of dedicated runs on single-tenant hardware. - An instance with host tenancy runs on a Dedicated Host, which is an - isolated server with configurations that you can control. - ''; - }; - - deployment.ec2.ebsBoot = mkOption { + ebsBoot = mkOption { default = true; type = types.bool; description = '' @@ -241,37 +220,7 @@ in ''; }; - deployment.ec2.ebsInitialRootDiskSize = mkOption { - default = 0; - type = types.int; - description = '' - Preferred size (G) of the root disk of the EBS-backed instance. By - default, EBS-backed images have a size determined by the - AMI. Only supported on creation of the instance. - ''; - }; - - deployment.ec2.ami = mkOption { - example = "ami-00000000"; - type = types.str; - description = '' - EC2 identifier of the AMI disk image used in the virtual - machine. This must be a NixOS image providing SSH access. - ''; - }; - - deployment.ec2.instanceType = mkOption { - default = "m1.small"; - example = "m1.large"; - type = types.str; - description = '' - EC2 instance type. See for a - list of valid Amazon EC2 instance types. - ''; - }; - - deployment.ec2.instanceId = mkOption { + instanceId = mkOption { default = ""; type = types.str; description = '' @@ -279,28 +228,7 @@ in ''; }; - deployment.ec2.instanceProfile = mkOption { - default = ""; - example = "rolename"; - type = types.str; - description = '' - The name of the IAM Instance Profile (IIP) to associate with - the instances. - ''; - }; - - deployment.ec2.keyPair = mkOption { - example = "my-keypair"; - type = types.either types.str (resource "ec2-keypair"); - apply = x: if builtins.isString x then x else x.name; - description = '' - Name of the SSH key pair to be used to communicate securely - with the instance. Key pairs can be created using the - ec2-add-keypair command. - ''; - }; - - deployment.ec2.privateKey = mkOption { + privateKey = mkOption { default = ""; example = "/home/alice/.ssh/id_rsa-my-keypair"; type = types.str; @@ -314,7 +242,7 @@ in ''; }; - deployment.ec2.securityGroups = mkOption { + securityGroups = mkOption { default = [ "default" ]; example = [ "my-group" "my-other-group" ]; type = types.listOf (types.either types.str (resource "ec2-security-group")); @@ -325,36 +253,7 @@ in ''; }; - deployment.ec2.securityGroupIds = mkOption { - default = [ "default" ]; - type = types.listOf types.str; - description = '' - Security Group IDs for the instance. Necessary if starting - an instance inside a VPC/subnet. In the non-default VPC, security - groups needs to be specified by ID and not name. - ''; - }; - - deployment.ec2.subnetId = mkOption { - default = ""; - example = "subnet-00000000"; - type = types.either types.str (resource "vpc-subnet"); - apply = x: if builtins.isString x then x else "res-" + x._name + "." + x._type; - description = '' - The subnet inside a VPC to launch the instance in. - ''; - }; - - deployment.ec2.associatePublicIpAddress = mkOption { - default = false; - type = types.bool; - description = '' - If instance in a subnet/VPC, whether to associate a public - IP address with the instance. - ''; - }; - - deployment.ec2.usePrivateIpAddress = mkOption { + usePrivateIpAddress = mkOption { default = defaultUsePrivateIpAddress; type = types.bool; description = '' @@ -365,7 +264,7 @@ in ''; }; - deployment.ec2.sourceDestCheck = mkOption { + sourceDestCheck = mkOption { default = true; type = types.bool; description = '' @@ -374,19 +273,9 @@ in ''; }; - deployment.ec2.placementGroup = mkOption { - default = ""; - example = "my-cluster"; - type = types.either types.str (resource "ec2-placement-group"); - apply = x: if builtins.isString x then x else x.name; - description = '' - Placement group for the instance. - ''; - }; - - deployment.ec2.tags = commonEC2Options.tags; + tags = commonEC2Options.tags; - deployment.ec2.blockDeviceMapping = mkOption { + blockDeviceMapping = mkOption { default = { }; example = { "/dev/xvdb".disk = "ephemeral0"; "/dev/xvdg".disk = "vol-00000000"; }; type = with types; attrsOf (submodule ec2DiskOptions); @@ -408,7 +297,7 @@ in ''; }; - deployment.ec2.elasticIPv4 = mkOption { + elasticIPv4 = mkOption { default = ""; example = "123.1.123.123"; type = types.either types.str (resource "elastic-ip"); @@ -418,7 +307,7 @@ in ''; }; - deployment.ec2.physicalProperties = mkOption { + physicalProperties = mkOption { default = {}; example = { cores = 4; memory = 14985; }; type = types.attrsOf (types.oneOf [ types.int types.str types.bool ]); @@ -428,44 +317,7 @@ in ''; }; - deployment.ec2.spotInstancePrice = mkOption { - default = 0; - type = types.int; - description = '' - Price (in dollar cents per hour) to use for spot instances request for the machine. - If the value is equal to 0 (default), then spot instances are not used. - ''; - }; - - deployment.ec2.spotInstanceRequestType = mkOption { - default = "one-time"; - type = types.enum [ "one-time" "persistent" ]; - description = '' - The type of the spot instance request. It can be either "one-time" or "persistent". - ''; - }; - - deployment.ec2.spotInstanceInterruptionBehavior = mkOption { - default = "terminate"; - type = types.enum [ "terminate" "stop" "hibernate" ]; - description = '' - Whether to terminate, stop or hibernate the instance when it gets interrupted. - For stop, spotInstanceRequestType must be set to "persistent". - ''; - }; - - deployment.ec2.spotInstanceTimeout = mkOption { - default = 0; - type = types.int; - description = '' - The duration (in seconds) that the spot instance request is - valid. If the request cannot be satisfied in this amount of - time, the request will be cancelled automatically, and NixOps - will fail with an error message. The default (0) is no timeout. - ''; - }; - - deployment.ec2.ebsOptimized = mkOption { + ebsOptimized = mkOption { default = defaultEbsOptimized; type = types.bool; description = '' @@ -473,10 +325,9 @@ in ''; }; - fileSystems = mkOption { + } // import ./common-ec2-instance-options.nix { inherit lib; }; + options.fileSystems = mkOption { type = with types; loaOf (submodule fileSystemsOptions); - }; - }; @@ -508,12 +359,12 @@ in # Workaround: the evaluation of blockDeviceMapping requires fileSystems to be defined. fileSystems = {}; - deployment.ec2.blockDeviceMapping = mkFixStrictness (listToAttrs + deployment.ec2.blockDeviceMapping = listToAttrs (map (fs: nameValuePair (dmToDevice fs.device) { inherit (fs.ec2) disk size deleteOnTermination encrypt cipher keySize passphrase iops volumeType encryptionType; fsType = if fs.fsType != "auto" then fs.fsType else fs.ec2.fsType; }) - (filter (fs: fs.ec2 != null) (attrValues config.fileSystems)))); + (filter (fs: fs.ec2 != null) (attrValues config.fileSystems))); deployment.autoLuks = let diff --git a/nixops_aws/resources/__init__.py b/nixops_aws/resources/__init__.py index 645977e4..79be2b02 100644 --- a/nixops_aws/resources/__init__.py +++ b/nixops_aws/resources/__init__.py @@ -1,4 +1,6 @@ __all__ = ( + "aws_ec2_launch_template", + "aws_spot_fleet_request", "aws_vpn_connection", "aws_vpn_connection_route", "aws_vpn_gateway", @@ -40,6 +42,8 @@ "aws_data_lifecycle_manager", ) +from . import aws_ec2_launch_template +from . import aws_spot_fleet_request from . import aws_vpn_connection from . import aws_vpn_connection_route from . import aws_vpn_gateway diff --git a/nixops_aws/resources/aws_ec2_launch_template.py b/nixops_aws/resources/aws_ec2_launch_template.py new file mode 100644 index 00000000..fbc0513a --- /dev/null +++ b/nixops_aws/resources/aws_ec2_launch_template.py @@ -0,0 +1,435 @@ +# -*- coding: utf-8 -*- +import base64 +import datetime +import nixops.util +import nixops_aws.ec2_utils +import nixops_aws.resources +from nixops_aws.resources.ec2_common import EC2CommonState +import botocore.exceptions +from typing import TYPE_CHECKING, Sequence + +from .types.aws_ec2_launch_template import Ec2LaunchTemplateOptions + +if TYPE_CHECKING: + from mypy_boto3_ec2.type_defs import ( + CreateLaunchTemplateRequestRequestTypeDef, + RequestLaunchTemplateDataTypeDef, + CreateLaunchTemplateResultTypeDef, + TagSpecificationTypeDef, + LaunchTemplateTagSpecificationRequestTypeDef, + TagTypeDef, + PrivateIpAddressSpecificationTypeDef, + DescribeImagesRequestRequestTypeDef, + LaunchTemplateBlockDeviceMappingRequestTypeDef, + LaunchTemplateEbsBlockDeviceRequestTypeDef, + ) +else: + CreateLaunchTemplateRequestRequestTypeDef = dict + RequestLaunchTemplateDataTypeDef = dict + CreateLaunchTemplateResultTypeDef = dict + TagSpecificationTypeDef = dict + LaunchTemplateTagSpecificationRequestTypeDef = dict + TagTypeDef = dict + PrivateIpAddressSpecificationTypeDef = dict + DescribeImagesRequestRequestTypeDef = dict + LaunchTemplateBlockDeviceMappingRequestTypeDef = dict + LaunchTemplateEbsBlockDeviceRequestTypeDef = dict + + +class awsEc2LaunchTemplateDefinition(nixops.resources.ResourceDefinition): + """Definition of an ec2 launch template""" + + config: Ec2LaunchTemplateOptions + + @classmethod + def get_type(cls): + return "aws-ec2-launch-template" + + @classmethod + def get_resource_type(cls): + return "awsEc2LaunchTemplate" + + def show_type(self): + return "{0}".format(self.get_type()) + + +class awsEc2LaunchTemplateState(nixops.resources.ResourceState, EC2CommonState): + """State of an ec2 launch template""" + + definition_type = awsEc2LaunchTemplateDefinition + + state = nixops.util.attr_property( + "state", nixops.resources.ResourceState.MISSING, int + ) + access_key_id = nixops.util.attr_property("accessKeyId", None) + region = nixops.util.attr_property("region", None) + templateName = nixops.util.attr_property("name", None) + templateId = nixops.util.attr_property("templateId", None) + templateVersion = nixops.util.attr_property("templateVersion", None) + versionDescription = nixops.util.attr_property("versionDescription", None) + ebsOptimized = nixops.util.attr_property("ebsOptimized", True, type=bool) + instanceProfile = nixops.util.attr_property("instanceProfile", None) + ami = nixops.util.attr_property("ami", None) + instanceType = nixops.util.attr_property("instanceType", None) + keyPair = nixops.util.attr_property("keyPair", None) + userData = nixops.util.attr_property("userData", None) + securityGroupIds = nixops.util.attr_property("securityGroupIds", None, "json") + disableApiTermination = nixops.util.attr_property( + "disableApiTermination", False, type=bool + ) + instanceInitiatedShutdownBehavior = nixops.util.attr_property( + "instanceInitiatedShutdownBehavior", None + ) + placementGroup = nixops.util.attr_property("placementGroup", None) + zone = nixops.util.attr_property("zone", None) + tenancy = nixops.util.attr_property("tenancy", None) + associatePublicIpAddress = nixops.util.attr_property( + "associatePublicIpAddress", True, type=bool + ) + networkInterfaceId = nixops.util.attr_property("networkInterfaceId", None) + subnetId = nixops.util.attr_property("subnetId", None) + privateIpAddresses = nixops.util.attr_property("privateIpAddresses", {}, "json") + secondaryPrivateIpAddressCount = nixops.util.attr_property( + "secondaryPrivateIpAddressCount", None + ) + monitoring = nixops.util.attr_property("LTMonitoring", False, type=bool) + spotInstancePrice = nixops.util.attr_property("ec2.spotInstancePrice", None) + spotInstanceRequestType = nixops.util.attr_property("spotInstanceRequestType", None) + spotInstanceInterruptionBehavior = nixops.util.attr_property( + "spotInstanceInterruptionBehavior", None + ) + spotInstanceTimeout = nixops.util.attr_property("spotInstanceTimeout", None) + clientToken = nixops.util.attr_property("clientToken", None) + ebsInitialRootDiskSize = nixops.util.attr_property("ebsInitialRootDiskSize", None) + + @classmethod + def get_type(cls): + return "aws-ec2-launch-template" + + def __init__(self, depl, name, id): + nixops.resources.ResourceState.__init__(self, depl, name, id) + self._conn_boto3 = None + self._conn_vpc = None + + def _exists(self): + return self.state != self.MISSING + + def show_type(self): + s = super(awsEc2LaunchTemplateState, self).show_type() + return s + + @property + def resource_id(self): + return self.templateId + + def connect_boto3(self, region): + if self._conn_boto3: + return self._conn_boto3 + self._conn_boto3 = nixops_aws.ec2_utils.connect_ec2_boto3( + region, self.access_key_id + ) + return self._conn_boto3 + + def connect_vpc(self): + if self._conn_vpc: + return self._conn_vpc + self._conn_vpc = nixops_aws.ec2_utils.connect_vpc( + self.region, self.access_key_id + ) + return self._conn_vpc + + # TODO: Work on how to update the template (create a new version and update default version to use or what) + # i think this is done automatically so i think i need to remove it right ? + def create_after(self, resources, defn): + # EC2 launch templates can require key pairs, IAM roles, security + # groups and placement groups + return { + r + for r in resources + if isinstance(r, nixops_aws.resources.ec2_keypair.EC2KeyPairState) + or isinstance(r, nixops_aws.resources.iam_role.IAMRoleState) + or isinstance( + r, nixops_aws.resources.ec2_security_group.EC2SecurityGroupState + ) + or isinstance( + r, nixops_aws.resources.ec2_placement_group.EC2PlacementGroupState + ) + or isinstance(r, nixops_aws.resources.vpc_subnet.VPCSubnetState) + } + + # fix security group stuff later + def security_groups_to_ids(self, subnetId, groups): + sg_names = filter(lambda g: not g.startswith("sg-"), groups) + if sg_names != [] and subnetId != "": + # Note: we can use ec2_utils.name_to_security_group but it only works with boto2 + group_ids = [] + for i in groups: + if i.startswith("sg-"): + group_ids.append(i) + else: + try: + group_ids.append( + self.connect_boto3(self.region).describe_security_groups( + Filters=[{"Name": "group-name", "Values": [i]}] + )["SecurityGroups"][0]["GroupId"] + ) + except botocore.exceptions.ClientError as error: + raise error + return group_ids + else: + return groups + + def create(self, defn, check, allow_reboot, allow_recreate): + if self.region is None: + self.region = defn.config.region + elif self.region != defn.config.region: + self.warn( + "cannot change region of a running instance (from ‘{}‘ to ‘{}‘)".format( + self.region, defn.config.region + ) + ) + + self.access_key_id = ( + defn.config.accessKeyId or nixops_aws.ec2_utils.get_access_key_id() + ) + + if self.state != self.UP: + # Use a client token to ensure that the template creation is + # idempotent; i.e., if we get interrupted before recording + # the fleet ID, we'll get the same fleet ID on the + # next run. + if not self.clientToken: + with self.depl._db: + self.clientToken = nixops.util.generate_random_string( + length=48 + ) # = 64 ASCII chars + self.state = self.STARTING + + self.log("creating launch template {} ...".format(defn.config.name)) + + tags = dict(defn.config.tags) + tags.update(self.get_common_tags()) + + self._create_launch_template( + CreateLaunchTemplateRequestRequestTypeDef( + LaunchTemplateName=defn.config.name, + VersionDescription=defn.config.versionDescription, + LaunchTemplateData=self._to_launch_template_data(defn.config), + ClientToken=self.clientToken, + TagSpecifications=[ + TagSpecificationTypeDef( + ResourceType="launch-template", + Tags=[TagTypeDef(Key=k, Value=tags[k]) for k in tags], + ) + ], + ) + ) + + def check(self): + conn = self.connect_boto3(self.region) + launch_template = conn.describe_launch_templates( + LaunchTemplateIds=[self.templateId] + )["LaunchTemplates"] + if launch_template is None: + self.state = self.MISSING + return + if str(launch_template[0]["DefaultVersionNumber"]) != self.templateVersion: + self.warn( + "default version on the launch template is different then nixops managed version..." + ) + + def _destroy(self): + conn = self.connect_boto3(self.region) + self.log("deleting ec2 launch template `{}`... ".format(self.templateName)) + try: + conn.delete_launch_template(LaunchTemplateId=self.templateId) + except botocore.exceptions.ClientError as error: + if error.response["Error"]["Code"] == "InvalidLaunchTemplateId.NotFound": + self.warn("Template `{}` already deleted...".format(self.templateName)) + else: + raise error + + def destroy(self, wipe=False): + if not self._exists(): + return True + + self._destroy() + return True + + # Boto3 helpers + def _block_device_mappings_from_ami( + self, image_id, + ) -> Sequence[LaunchTemplateBlockDeviceMappingRequestTypeDef]: + ami = self.connect_boto3(self.region).describe_images( + **DescribeImagesRequestRequestTypeDef(ImageIds=[image_id]) + )["Images"][0] + + block_device_mappings = [] + for block_device_mapping in ami["BlockDeviceMappings"]: + if block_device_mapping.get("Ebs"): + template_block_device_mapping = LaunchTemplateBlockDeviceMappingRequestTypeDef( + DeviceName=block_device_mapping["DeviceName"], + Ebs=LaunchTemplateEbsBlockDeviceRequestTypeDef(), + ) + if block_device_mapping.get("Encrypted") is not None: + template_block_device_mapping["Ebs"][ + "Encrypted" + ] = block_device_mapping["Ebs"]["Encrypted"] + if block_device_mapping["Ebs"].get("DeleteOnTermination") is not None: + template_block_device_mapping["Ebs"][ + "DeleteOnTermination" + ] = block_device_mapping["Ebs"]["DeleteOnTermination"] + if block_device_mapping["Ebs"].get("KmsKeyId") is not None: + template_block_device_mapping["Ebs"][ + "KmsKeyId" + ] = block_device_mapping["Ebs"]["KmsKeyId"] + if block_device_mapping["Ebs"].get("SnapshotId") is not None: + template_block_device_mapping["Ebs"][ + "SnapshotId" + ] = block_device_mapping["Ebs"]["SnapshotId"] + if block_device_mapping["Ebs"].get("VolumeSize") is not None: + template_block_device_mapping["Ebs"][ + "VolumeSize" + ] = block_device_mapping["Ebs"]["VolumeSize"] + if block_device_mapping["Ebs"].get("VolumeType") is not None: + template_block_device_mapping["Ebs"][ + "VolumeType" + ] = block_device_mapping["Ebs"]["VolumeType"] + if block_device_mapping.get("VirtualName") is not None: + template_block_device_mapping[ + "VirtualName" + ] = block_device_mapping.get("VirtualName") + block_device_mappings.append(template_block_device_mapping) + return block_device_mappings + + def _to_launch_template_data( + self, config: Ec2LaunchTemplateOptions + ) -> RequestLaunchTemplateDataTypeDef: + common_tags = self.get_common_tags() + instance_tags = dict(config.instanceTags) + volume_tags = dict(config.volumeTags) + + # Common tags don't necessarily make sense for resources launched using the template + # Instances launched using this template may override common tags + instance_tags["CharonTemplateNetworkUUID"] = common_tags["CharonNetworkUUID"] + instance_tags["CharonTemplateName"] = common_tags["CharonMachineName"] + instance_tags["CharonTemplateStateFile"] = common_tags["CharonStateFile"] + volume_tags["CharonTemplateNetworkUUID"] = common_tags["CharonNetworkUUID"] + volume_tags["CharonTemplateName"] = common_tags["CharonMachineName"] + volume_tags["CharonTemplateStateFile"] = common_tags["CharonStateFile"] + if common_tags.get("CharonNetworkName"): + instance_tags["CharonTemplateNetworkName"] = common_tags[ + "CharonNetworkName" + ] + volume_tags["CharonTemplateNetworkName"] = common_tags["CharonNetworkName"] + + data = RequestLaunchTemplateDataTypeDef( + EbsOptimized=config.ebsOptimized, + ImageId=config.ami, + Placement=dict(Tenancy=config.tenancy), + Monitoring=dict(Enabled=config.monitoring), + DisableApiTermination=config.disableApiTermination, + InstanceInitiatedShutdownBehavior=config.instanceInitiatedShutdownBehavior, + TagSpecifications=[ + LaunchTemplateTagSpecificationRequestTypeDef( + ResourceType="instance", + Tags=[ + TagTypeDef(Key=k, Value=instance_tags[k]) for k in instance_tags + ], + ), + LaunchTemplateTagSpecificationRequestTypeDef( + ResourceType="volume", + Tags=[TagTypeDef(Key=k, Value=volume_tags[k]) for k in volume_tags], + ), + ], + ) + if config.instanceProfile != "": + data["IamInstanceProfile"] = dict(Name=config.instanceProfile) + if config.userData: + data["UserData"] = str( + base64.b64encode(config.userData.encode("ascii")), "utf-8" + ) + if config.instanceType != "": + data["InstanceType"] = config.instanceType # type: ignore + if config.placementGroup != "": + data["Placement"]["GroupName"] = config.placementGroup + if config.zone: + data["Placement"]["AvailabilityZone"] = config.zone + + if config.spotInstancePrice != 0: + data["InstanceMarketOptions"] = dict( + MarketType="spot", + SpotOptions=dict( + MaxPrice=str(config.spotInstancePrice / 100.0), + SpotInstanceType=config.spotInstanceRequestType, + ValidUntil=( + datetime.datetime.utcnow() + + datetime.timedelta(0, config.spotInstanceTimeout) + ).isoformat(), + InstanceInterruptionBehavior=config.spotInstanceInterruptionBehavior, + ), + ) + if config.networkInterfaceId != "" or config.subnetId != "": + data["NetworkInterfaces"] = [ + dict( + DeviceIndex=0, + AssociatePublicIpAddress=config.associatePublicIpAddress, + ) + ] + if config.securityGroupIds != []: + data["NetworkInterfaces"][0]["Groups"] = self.security_groups_to_ids( + config.subnetId, config.securityGroupIds + ) + if config.networkInterfaceId != "": + if config.networkInterfaceId.startswith("res-"): + config.networkInterfaceId = self.depl.get_typed_resource( + config.networkInterfaceId[4:].split(".")[0], + "vpc-network-interface", + nixops_aws.resources.vpc_network_interface.VPCNetworkInterfaceState, + )._state["networkInterfaceId"] + data["NetworkInterfaces"][0][ + "NetworkInterfaceId" + ] = config.networkInterfaceId + if config.subnetId != "": + if config.subnetId.startswith("res-"): + config.subnetId = self.depl.get_typed_resource( + config.subnetId[4:].split(".")[0], + "vpc-subnet", + nixops_aws.resources.vpc_subnet.VPCSubnetState, + )._state["subnetId"] + data["NetworkInterfaces"][0]["SubnetId"] = config.subnetId + if config.secondaryPrivateIpAddressCount: + data["NetworkInterfaces"][0][ + "SecondaryPrivateIpAddressCount" + ] = config.secondaryPrivateIpAddressCount + if config.privateIpAddresses: + data["NetworkInterfaces"][0]["PrivateIpAddresses"] = [ + PrivateIpAddressSpecificationTypeDef( + # Primary= # TODO + PrivateIpAddress=ip_address, + ) + for ip_address in config.privateIpAddresses + ] + if config.keyPair != "": + data["KeyName"] = config.keyPair + + data["BlockDeviceMappings"] = self._block_device_mappings_from_ami(config.ami) + return data + + # Boto3 wrappers + def _create_launch_template( + self, request: CreateLaunchTemplateRequestRequestTypeDef + ) -> CreateLaunchTemplateResultTypeDef: + try: + response = self.connect_boto3(self.region).create_launch_template(**request) + except botocore.exceptions.ClientError as error: + raise error + # Not sure whether to use lambda retry or keep it like this + with self.depl._db: + self.state = self.UP + + self.templateId = response["LaunchTemplate"]["LaunchTemplateId"] + self.templateName = request["LaunchTemplateName"] + self.templateVersion = response["LaunchTemplate"]["LatestVersionNumber"] + self.versionDescription = request["VersionDescription"] + return response diff --git a/nixops_aws/resources/aws_spot_fleet_request.py b/nixops_aws/resources/aws_spot_fleet_request.py new file mode 100644 index 00000000..70e880a1 --- /dev/null +++ b/nixops_aws/resources/aws_spot_fleet_request.py @@ -0,0 +1,591 @@ +# -*- coding: utf-8 -*- +from typing import TYPE_CHECKING, Optional, List +import boto3 +import nixops.util +from nixops.resources import ResourceDefinition +from nixops.resources import ResourceState +import nixops_aws.ec2_utils +import botocore.exceptions +from . import ec2_common +from .iam_role import IAMRoleState + +from .types.aws_spot_fleet import SpotFleetRequestOptions + + +if TYPE_CHECKING: + from mypy_boto3_ec2.literals import BatchStateType + from mypy_boto3_ec2.type_defs import ( + LaunchTemplateConfigTypeDef, + FleetLaunchTemplateSpecificationTypeDef, + LaunchTemplateOverridesTypeDef, + TagSpecificationTypeDef, + SpotFleetRequestConfigDataTypeDef, + TagTypeDef, + DescribeSpotFleetRequestsRequestRequestTypeDef, + DescribeSpotFleetRequestsResponseTypeDef, + RequestSpotFleetRequestRequestTypeDef, + RequestSpotFleetResponseTypeDef, + ModifySpotFleetRequestRequestRequestTypeDef, + ModifySpotFleetRequestResponseTypeDef, + CancelSpotFleetRequestsRequestRequestTypeDef, + CancelSpotFleetRequestsResponseTypeDef, + ) +else: + BatchStateType = object + LaunchTemplateConfigTypeDef = dict + FleetLaunchTemplateSpecificationTypeDef = dict + LaunchTemplateOverridesTypeDef = dict + TagSpecificationTypeDef = dict + SpotFleetRequestConfigDataTypeDef = dict + TagTypeDef = dict + DescribeSpotFleetRequestsRequestRequestTypeDef = dict + DescribeSpotFleetRequestsResponseTypeDef = dict + RequestSpotFleetRequestRequestTypeDef = dict + RequestSpotFleetResponseTypeDef = dict + ModifySpotFleetRequestRequestRequestTypeDef = dict + ModifySpotFleetRequestResponseTypeDef = dict + CancelSpotFleetRequestsRequestRequestTypeDef = dict + CancelSpotFleetRequestsResponseTypeDef = dict + + +class awsSpotFleetRequestDefinition(ResourceDefinition): + """Definition of a spot fleet request""" + + config: SpotFleetRequestOptions + + @classmethod + def get_type(cls): + return "aws-spot-fleet-request" + + @classmethod + def get_resource_type(cls): + return "awsSpotFleetRequest" + + def show_type(self): + return "{0}".format(self.get_type()) + + +class awsSpotFleetRequestState(ResourceState, ec2_common.EC2CommonState): + """State of a spot fleet request""" + + definition_type = awsSpotFleetRequestDefinition + + state = nixops.util.attr_property( + "state", nixops.resources.ResourceState.MISSING, int + ) + access_key_id = nixops.util.attr_property("accessKeyId", None) + region = nixops.util.attr_property("region", None) + + spotFleetRequestId = nixops.util.attr_property("spotFleetRequestId", None) + allocationStrategy = nixops.util.attr_property("allocationStrategy", None) + # allocationStrategy: Optional[Union[ + # Literal["lowestPrice"], + # Literal["diversified"], + # Literal["capacityOptimized"], + # Literal["capacityOptimizedPrioritized"] + # ]], + # clientToken: Optional[str] + # excessCapacityTerminationPolicy: Optional[Union[ + # Literal["noTermination"], + # Literal["default"] + # ]], + # fulfilledCapacity: Optional[float] + + iamFleetRole = nixops.util.attr_property("iamFleetRole", None) + + # instanceInterruptionBehavior: Optional[Union[ + # Literal["hibernate"], + # Literal["top"], + # Literal["terminate"] + # ]], + # instancePoolsToUseCount: Optional[int] + # launchSpecifications = nixops.util.attr_property("launchSpecifications", [], "json") + launchTemplateConfigs = nixops.util.attr_property( + "launchTemplateConfigs", [], "json" + ) + # loadBalancersConfig: Optional[List[LoadBalancersConfigOptions]] + # onDemandAllocationStrategy: Optional[Union[ + # Literal["lowestPrice"], + # Literal["prioritized"] + # ]] + # onDemandFulfilledCapacity: Optional[float] + # onDemandMaxTotalPrice: Optional[str] # todo: price + # onDemandTargetCapacity: Optional[int] + # replaceUnhealthyInstances: Optional[bool] + # spotMaintenaneStrategies: Optional[SpotMaintenanceStrategiesOptions] + spotMaxTotalPrice = nixops.util.attr_property("spotMaxTotalPrice", None) + spotPrice = nixops.util.attr_property("spotPrice", None) + # # tagSpecifications / tags = Mapping[str, str] + targetCapacity = nixops.util.attr_property("targetCapacity", 0, int) + # terminateInstancesWithExpiration: Optional[bool] + type = nixops.util.attr_property("type", None) + # validFrom: Optional[Timestamp] + # validUntil: Optional[Timestamp] + + @classmethod + def get_type(cls): + return "aws-spot-fleet-request" + + def __init__(self, depl, name, id): + nixops.resources.ResourceState.__init__(self, depl, name, id) + + def _exists(self): + return self.state != self.MISSING + + def show_type(self): + s = super(awsSpotFleetRequestState, self).show_type() + return s + + @property + def resource_id(self): + return self.spotFleetRequestId + + def create_after(self, resources, defn): + return {r for r in resources if isinstance(r, IAMRoleState)} + + def get_client(self, service): + if hasattr(self, "_client"): + if self._client: + return self._client + + assert self.region + (access_key_id, secret_access_key) = nixops_aws.ec2_utils.fetch_aws_secret_key( + self.access_key_id + ) + client = boto3.session.Session().client( + service_name=service, + region_name=self.region, + aws_access_key_id=access_key_id, + aws_secret_access_key=secret_access_key, + ) + return client + + def create( + self, + defn: awsSpotFleetRequestDefinition, + check: bool, + allow_reboot: bool, + allow_recreate: bool, + ): + self.access_key_id = ( + defn.config.accessKeyId or nixops_aws.ec2_utils.get_access_key_id() + ) + if not self.access_key_id: + raise Exception( + "please set ‘accessKeyId’, $EC2_ACCESS_KEY or $AWS_ACCESS_KEY_ID" + ) + + if self._exists(): + immutable_values = { + "region": defn.config.region, + "type": defn.config.type, + "iamFleetRole": self._arn_from_role_name(defn.config.iamFleetRole), + } + immutable_diff = { + k for k in immutable_values if getattr(self, k) != immutable_values[k] + } # TODO dict diff + if immutable_diff: + raise Exception( + "changing keys ‘{0}’ (from ‘{1}’ to ‘{2}’) of an existing spot fleet request is not supported".format( + immutable_diff, + [getattr(self, k) for k in immutable_diff], + [getattr(defn.config, k) for k in immutable_diff], + ) + ) + + mutable_values = { + # "excessCapacityTerminationPolicy", + # "launchTemplateConfigs", + "targetCapacity": 0, # defn.config.targetCapacity + # "onDemandTargetCapacity", + } + mutable_diff = [ + k for k in mutable_values if getattr(self, k) != mutable_values[k] + ] # TODO dict diff + if True or mutable_diff: + request = ModifySpotFleetRequestRequestRequestTypeDef( + # ExcessCapacityTerminationPolicy= + # LaunchTemplateConfigs= + SpotFleetRequestId=self.spotFleetRequestId, + TargetCapacity=mutable_values["targetCapacity"] + # OnDemandTargetCapacity= + ) + + self.log( + "modifying spot fleet request `{}`... ".format( + self.spotFleetRequestId + ) + ) + self._modify_spot_fleet_request(request) + + # TODO update tags? + + if self.state == self.MISSING: + self.log( + "creating spot fleet request with target capacity of ‘{0}’...".format( + # self.targetCapacity + 0 + ) + ) + # The region may only be set once, when a new spot fleet is being requested + with self.depl._db: + self.region = defn.config.region + + self._request_spot_fleet(self._to_spot_fleet_request(defn.config)) + + def check(self): + if self.spotFleetRequestId is None: + self.state = self.MISSING + return + + self._describe_spot_fleet_requests( + DescribeSpotFleetRequestsRequestRequestTypeDef( + # DryRun=None, + # MaxResults=None, + # NextToken=None, + SpotFleetRequestIds=[self.spotFleetRequestId] + ) + ) + + # TODO handle state + # self.warn() + + return + + def destroy(self, wipe=False): + if not self._exists(): + return True + + self.log( + "canceling spot fleet request with id ‘{0}’...".format( + self.spotFleetRequestId + ) + ) + try: + self._cancel_spot_fleet_requests( + CancelSpotFleetRequestsRequestRequestTypeDef( + SpotFleetRequestIds=[self.spotFleetRequestId], + TerminateInstances=True, + ) + ) + except botocore.exceptions.ClientError as e: + if e.response["Error"]["Code"] == "ResourceNotFoundException": + self.warn( + "spot fleet request with id {0} was already deleted".format( + self.spotFleetRequestId + ) + ) + else: + raise e + + return True + + # Boto3 helpers + + def _to_resource_state(self, state: BatchStateType) -> int: + if state == "active": + return self.UP + elif state == "cancelled": + return self.MISSING + elif state == "cancelled_running": + return self.MISSING + elif state == "cancelled_terminating": + return self.MISSING + elif state == "failed": + return self.MISSING + elif state == "modifying": + return self.UP + elif state == "submitted": + return self.UP + else: + return self.UNKNOWN + + def _to_launch_template_overrides( + self, overrides + ) -> LaunchTemplateOverridesTypeDef: + result = LaunchTemplateOverridesTypeDef() + if overrides.instanceType: + result["InstanceType"] = overrides.instanceType + if overrides.spotPrice: + result["SpotPrice"] = overrides.spotPrice + if overrides.subnetId: + result["SubnetId"] = overrides.subnetId + if overrides.availabilityZone: + result["AvailabilityZone"] = overrides.availabilityZone + if overrides.weightedCapacity: + result["WeightedCapacity"] = overrides.weightedCapacity + if overrides.priority: + result["Priority"] = overrides.priority + return result + + def _to_spot_fleet_request(self, config): + tags = dict(config.tags) + tags.update(self.get_common_tags()) + + # # TODO instance tags + # instance_tags = dict(config.tags) + # instance_tags.update(self.get_common_tags()) + + launch_template_configs = [ + LaunchTemplateConfigTypeDef( + LaunchTemplateSpecification=FleetLaunchTemplateSpecificationTypeDef( + # LaunchTemplateId: str + LaunchTemplateName=template_config.launchTemplateSpecification.launchTemplateName, + Version=template_config.launchTemplateSpecification.version, + ), + Overrides=[ + self._to_launch_template_overrides(overrides) + for overrides in template_config.overrides + ], + ) + for template_config in config.launchTemplateConfigs + ] + + request = RequestSpotFleetRequestRequestTypeDef( + SpotFleetRequestConfig=SpotFleetRequestConfigDataTypeDef( + # AllocationStrategy= + # OnDemandAllocationStrategy= + # SpotMaintenanceStrategies= + # ClientToken= + # ExcessCapacityTerminationPolicy= + # FulfilledCapacity= + # OnDemandFulfilledCapacity= + IamFleetRole=self._arn_from_role_name(config.iamFleetRole), + # LaunchSpecifications= + LaunchTemplateConfigs=launch_template_configs, + TargetCapacity=1, # TODO + # OnDemandTargetCapacity= + # OnDemandMaxTotalPrice= + # TerminateInstancesWithExpiration= + Type=config.type, + # ValidFrom= + # ValidUntil= + # ReplaceUnhealthyInstances= + # InstanceInterruptionBehavior= + # LoadBalancersConfig= + # InstancePoolsToUseCount= + TagSpecifications=[ + TagSpecificationTypeDef( + ResourceType="spot-fleet-request", + Tags=[TagTypeDef(Key=k, Value=tags[k]) for k in tags], + ) + ], + ) + ) + if config.spotPrice: + request["SpotFleetRequestConfig"]["SpotPrice"] = config.spotPrice + if config.spotMaxTotalPrice: + request["SpotFleetRequestConfig"][ + "SpotMaxTotalPrice" + ] = config.spotMaxTotalPrice + return request + + def _arn_from_role_name(self, role_name): + if role_name.startswith("arn:aws:iam"): + return role_name + + role_arn = self.get_client("iam").get_role(RoleName=role_name) + return role_arn["Role"]["Arn"] + + def _save_config_data(self, config: SpotFleetRequestConfigDataTypeDef): + if config.get("AllocationStrategy") is not None: + self.allocationStrategy = config["AllocationStrategy"] + # if config["OnDemandAllocationStrategy"] is not None: + # self.onDemandAllocationStrategy = config["OnDemandAllocationStrategy"] + # if config["SpotMaintenanceStrategies"] is not None: + # self.spotMaintenanceStrategies = config["SpotMaintenanceStrategies"] + # if config["ClientToken"] is not None: + # self.clientToken = config["ClientToken"] + # if config["ExcessCapacityTerminationPolicy"] is not None: + # self.excessCapacityTerminationPolicy = ( + # config["ExcessCapacityTerminationPolicy"] + # ) + # if config["FulfilledCapacity"] is not None: + # self.fulfilledCapacity = config["FulfilledCapacity"] + # if config["OnDemandFulfilledCapacity"] is not None: + # self.onDemandFulfilledCapacity = config["OnDemandFulfilledCapacity"] + self.iamFleetRole = config["IamFleetRole"] + # if config["LaunchSpecifications"] is not None: + # self.launchSpecifications = config["LaunchSpecifications"] + if config["LaunchTemplateConfigs"] is not None: + self.launchTemplateConfigs = config["LaunchTemplateConfigs"] + if config["SpotPrice"] is not None: + self.spotPrice = config["SpotPrice"] + self.targetCapacity = config["TargetCapacity"] + # if config["OnDemandTargetCapacity"] is not None: + # self.onDemandTargetCapacity = config["OnDemandTargetCapacity"] + # if config["OnDemandMaxTotalPrice"] is not None: + # self.onDemandMaxTotalPrice = config["OnDemandMaxTotalPrice"] + if config["SpotMaxTotalPrice"] is not None: + self.spotMaxTotalPrice = config["SpotMaxTotalPrice"] + # if config["TerminateInstancesWithExpiration"] is not None: + # self.terminateInstancesWithExpiration = ( + # config["TerminateInstancesWithExpiration"] + # ) + if config["Type"] is not None: + self.type = config["Type"] + # if config["ValidFrom"] is not None: + # self.validFrom = config["ValidFrom"] + # if config["ValidUntil"] is not None: + # self.validUntil = config["ValidUntil"] + # if config["ReplaceUnhealthyInstances"] is not None: + # self.replaceUnhealthyInstances = config["ReplaceUnhealthyInstances"] + # if config["InstanceInterruptionBehavior"] is not None: + # self.instanceInterruptionBehavior = ( + # config["InstanceInterruptionBehavior"] + # ) + # if config["LoadBalancersConfig"] is not None: + # self.loadBalancersConfig = config["LoadBalancersConfig"] + # if config["InstancePoolsToUseCount"] is not None: + # self.instancePoolsToUseCount = config["InstancePoolsToUseCount"] + # if config["TagSpecifications"] is not None: + # self.tagSpecifications = config["TagSpecifications"] + + def _save_tags(self, tags: List[TagTypeDef]): + pass + + # Boto3 wrappers + + def _describe_spot_fleet_requests( + self, request: DescribeSpotFleetRequestsRequestRequestTypeDef + ) -> Optional[DescribeSpotFleetRequestsResponseTypeDef]: + def check_response_field(name, value, expected_value): + if value != expected_value: + raise Exception( + "Unexpected value ‘{0} = {1}’ in response, expected ‘{0} = {2}’".format( + name, value, expected_value + ) + ) + + try: + response = self.get_client("ec2").describe_spot_fleet_requests( + # **dataclasses.asdict(request) + **request + ) + for config in response["SpotFleetRequestConfigs"]: + check_response_field( + "SpotFleetRequestId", + config["SpotFleetRequestId"], + self.spotFleetRequestId, + ) + + # TODO: + # Why is activity status not always present? + # Is it due to spot fleet being canceled without any instances? + if response.get("ActivityStatus") == "error": + self.warn( + "spot fleet activity status is {}, please investigate...".format( + response["ActivityStatus"] + ) + ) + + if not request.get("DryRun"): + with self.depl._db: + # Update deployment state from response + self.state = self._to_resource_state( + config["SpotFleetRequestState"] + ) + self._save_config_data(config["SpotFleetRequestConfig"]) + self._save_tags(config["Tags"]) + + return response + except botocore.exceptions.ClientError as e: + if e.response["Error"]["Code"] == "ResourceNotFoundException": + self.state = self.MISSING + return None + else: + raise e + + def _request_spot_fleet( + self, request: RequestSpotFleetRequestRequestTypeDef + ) -> RequestSpotFleetResponseTypeDef: + response = self.get_client("ec2").request_spot_fleet( + # **dataclasses.asdict(request) + **request + ) + + if not request.get("DryRun"): + with self.depl._db: + self.state = self.UP + + # Save response to deployment state + self.spotFleetRequestId = response["SpotFleetRequestId"] + + # Save request to deployment state + self._save_config_data(request["SpotFleetRequestConfig"]) + + return response + + def _modify_spot_fleet_request( + self, request: ModifySpotFleetRequestRequestRequestTypeDef + ) -> Optional[ModifySpotFleetRequestResponseTypeDef]: + try: + response = self.get_client("ec2").modify_spot_fleet_request( + # **dataclasses.asdict(request) + **request + ) + + if response.Return: + with self.depl._db: + # Save request to deployment state + # if request.ExcessCapacityTerminationPolicy is not None: + # self.excessCapacityTerminationPolicy = ( + # request.ExcessCapacityTerminationPolicy + # ) + # if request.LaunchTemplateConfigs is not None: + # self.launchTemplateConfigs = request.LaunchTemplateConfigs + if request["TargetCapacity"] is not None: + self.targetCapacity = request["TargetCapacity"] + if request["OnDemandTargetCapacity"] is not None: + self.onDemandTargetCapacity = request["OnDemandTargetCapacity"] + + return response + + except botocore.exceptions.ClientError as e: + if e.response["Error"]["Code"] == "ResourceNotFoundException": + with self.depl._db: + self.state = self.MISSING + return None + else: + raise e + + def _cancel_spot_fleet_requests( + self, request: CancelSpotFleetRequestsRequestRequestTypeDef + ) -> CancelSpotFleetRequestsResponseTypeDef: + response = self.get_client("ec2").cancel_spot_fleet_requests( + # **dataclasses.asdict(request) + **request + ) + + def check_response_field(name, value, expected_value): + if value != expected_value: + raise Exception( + "Unexpected value ‘{0} = {1}’ in response, expected ‘{0} = {2}’".format( + name, value, expected_value + ) + ) + + for item in response["SuccessfulFleetRequests"]: + check_response_field( + "SpotFleetRequestId", + item["SpotFleetRequestId"], + self.spotFleetRequestId, + ) + self.state = self._to_resource_state(item["CurrentSpotFleetRequestState"]) + + for item in response["UnsuccessfulFleetRequests"]: + check_response_field( + "SpotFleetRequestId", + item["SpotFleetRequestId"], + self.spotFleetRequestId, + ) + self.warn( + "spot fleet request with id ‘{0}’ cancelation failed with error ‘{1}: {2}’".format( + self.spotFleetRequestId, + response["Error"]["Code"], + response["Error"]["Message"], + ) + ) + self.state = self.UNKNOWN + + return response diff --git a/nixops_aws/resources/ec2_rds_dbinstance.py b/nixops_aws/resources/ec2_rds_dbinstance.py index 1c364d69..5f21470e 100644 --- a/nixops_aws/resources/ec2_rds_dbinstance.py +++ b/nixops_aws/resources/ec2_rds_dbinstance.py @@ -146,7 +146,7 @@ def get_physical_spec(self): def resource_id(self): return self.rds_dbinstance_id - def create_after(self, resources, defn: EC2RDSDbInstanceDefinition): + def create_after(self, resources, defn): return { r for r in resources @@ -534,7 +534,7 @@ def get_vpc_options(self, defn: EC2RDSDbInstanceDefinition) -> VpcOptions: return opts - def after_activation(self, defn: EC2RDSDbInstanceDefinition): + def after_activation(self, defn): # TODO: Warn about old instances, but don't clean them up. pass diff --git a/nixops_aws/resources/types/aws_ec2_launch_template.py b/nixops_aws/resources/types/aws_ec2_launch_template.py new file mode 100644 index 00000000..aabf9408 --- /dev/null +++ b/nixops_aws/resources/types/aws_ec2_launch_template.py @@ -0,0 +1,54 @@ +from typing import Union +from typing import Optional +from typing import Sequence +from typing import Mapping +from typing_extensions import Literal +from nixops.resources import ResourceOptions + + +class Ec2LaunchTemplateOptions(ResourceOptions): + name: str + templateId: str + versionDescription: str + ebsOptimized: bool + userData: Optional[str] + disableApiTermination: bool + instanceInitiatedShutdownBehavior: Union[ + Literal["stop"], Literal["terminate"], + ] + networkInterfaceId: str + privateIpAddresses: Optional[Sequence[str]] + secondaryPrivateIpAddressCount: Optional[int] + instanceTags: Mapping[str, str] + volumeTags: Mapping[str, str] + + # Common EC2 auth options + accessKeyId: str + region: str + + # Common EC2 options + tags: Mapping[str, str] + + # Common EC2 instance options + monitoring: bool + ami: str + associatePublicIpAddress: bool + ebsInitialRootDiskSize: int + instanceProfile: str + instanceType: str + keyPair: str + placementGroup: str + securityGroupIds: Sequence[str] + spotInstanceInterruptionBehavior: Union[ + Literal["terminate"], Literal["stop"], Literal["hibernate"], + ] + spotInstancePrice: int + spotInstanceRequestType: Union[ + Literal["one-time"], Literal["persistent"], + ] + spotInstanceTimeout: int + subnetId: str + tenancy: Union[ + Literal["default"], Literal["dedicated"], Literal["host"], + ] + zone: str diff --git a/nixops_aws/resources/types/aws_spot_fleet.py b/nixops_aws/resources/types/aws_spot_fleet.py new file mode 100644 index 00000000..e12ca046 --- /dev/null +++ b/nixops_aws/resources/types/aws_spot_fleet.py @@ -0,0 +1,49 @@ +from typing import Mapping, Sequence, Optional, Union +from typing_extensions import Literal +from nixops.resources import ResourceOptions + + +class LaunchTemplateSpecificationOptions(ResourceOptions): + # launchTemplateId: str # Optional + launchTemplateName: str # Optional + version: str # Optional + + +class FleetLaunchTemplateSpecificationOptions(ResourceOptions): + # launchTemplateId: str # Optional + launchTemplateName: str # Optional # {"max":128,"min":3,"pattern":"[a-zA-Z0-9\\(\\)\\.\\-/_]+"} + version: str # Optional + + +class LaunchTemplateOverridesOptions(ResourceOptions): + instanceType: Optional[str] + spotPrice: Optional[str] + subnetId: Optional[str] + availabilityZone: Optional[str] + weightedCapacity: Optional[float] + priority: Optional[float] + + +class LaunchTemplateConfigOptions(ResourceOptions): + launchTemplateSpecification: FleetLaunchTemplateSpecificationOptions # Optional + overrides: Sequence[LaunchTemplateOverridesOptions] + + +class SpotFleetRequestOptions(ResourceOptions): + spotFleetRequestId: str + iamFleetRole: str + type: Union[ + Literal["request"], + Literal["maintain"] + # Literal["instant"] # instant is listed but is not used by Spot Fleet. + ] + launchTemplateConfigs: Sequence[LaunchTemplateConfigOptions] + spotPrice: Optional[str] + spotMaxTotalPrice: Optional[str] + + # Common EC2 auth options + accessKeyId: str + region: str + + # Common EC2 options + tags: Mapping[str, str] diff --git a/poetry.lock b/poetry.lock index 71a6e92d..24383ef3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,32 +1,32 @@ [[package]] -category = "dev" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = "*" -version = "1.4.4" [[package]] -category = "dev" -description = "Classes Without Boilerplate" name = "attrs" +version = "21.2.0" +description = "Classes Without Boilerplate" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.3.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] -dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] -docs = ["sphinx", "zope.interface"] -tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] [[package]] -category = "dev" -description = "The uncompromising code formatter." name = "black" +version = "19.10b0" +description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.6" -version = "19.10b0" [package.dependencies] appdirs = "*" @@ -41,373 +41,433 @@ typed-ast = ">=1.4.0" d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] -category = "main" -description = "Amazon Web Services Library" name = "boto" +version = "2.49.0" +description = "Amazon Web Services Library" +category = "main" optional = false python-versions = "*" -version = "2.49.0" [[package]] -category = "main" -description = "The AWS SDK for Python" name = "boto3" +version = "1.18.53" +description = "The AWS SDK for Python" +category = "main" optional = false -python-versions = "*" -version = "1.14.22" +python-versions = ">= 3.6" [package.dependencies] -botocore = ">=1.17.22,<1.18.0" +botocore = ">=1.21.53,<1.22.0" jmespath = ">=0.7.1,<1.0.0" -s3transfer = ">=0.3.0,<0.4.0" +s3transfer = ">=0.5.0,<0.6.0" + +[package.extras] +crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] -category = "dev" -description = "Type annotations for boto3 1.14.21, generated by mypy-boto3-buider 2.2.0" name = "boto3-stubs" +version = "1.18.52" +description = "Type annotations for boto3 1.18.52, generated by mypy-boto3-builder 5.5.0" +category = "main" optional = false python-versions = ">=3.6" -version = "1.14.21.0" [package.dependencies] -mypy-boto3 = "1.14.21.0" - -[package.dependencies.mypy-boto3-ec2] -optional = true -version = "1.14.21.0" - -[package.dependencies.mypy-boto3-efs] -optional = true -version = "1.14.21.0" - -[package.dependencies.mypy-boto3-rds] -optional = true -version = "1.14.21.0" - -[package.dependencies.mypy-boto3-sqs] -optional = true -version = "1.14.21.0" - -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" +botocore-stubs = "*" +mypy-boto3-ec2 = {version = ">=1.18.47", optional = true, markers = "extra == \"ec2\""} +mypy-boto3-efs = {version = ">=1.18.47", optional = true, markers = "extra == \"efs\""} +mypy-boto3-rds = {version = ">=1.18.47", optional = true, markers = "extra == \"rds\""} +mypy-boto3-sqs = {version = ">=1.18.47", optional = true, markers = "extra == \"sqs\""} +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -accessanalyzer = ["mypy-boto3-accessanalyzer (1.14.21.0)"] -acm = ["mypy-boto3-acm (1.14.21.0)"] -acm-pca = ["mypy-boto3-acm-pca (1.14.21.0)"] -alexaforbusiness = ["mypy-boto3-alexaforbusiness (1.14.21.0)"] -all = ["mypy-boto3-accessanalyzer (1.14.21.0)", "mypy-boto3-acm (1.14.21.0)", "mypy-boto3-acm-pca (1.14.21.0)", "mypy-boto3-alexaforbusiness (1.14.21.0)", "mypy-boto3-amplify (1.14.21.0)", "mypy-boto3-apigateway (1.14.21.0)", "mypy-boto3-apigatewaymanagementapi (1.14.21.0)", "mypy-boto3-apigatewayv2 (1.14.21.0)", "mypy-boto3-appconfig (1.14.21.0)", "mypy-boto3-application-autoscaling (1.14.21.0)", "mypy-boto3-application-insights (1.14.21.0)", "mypy-boto3-appmesh (1.14.21.0)", "mypy-boto3-appstream (1.14.21.0)", "mypy-boto3-appsync (1.14.21.0)", "mypy-boto3-athena (1.14.21.0)", "mypy-boto3-autoscaling (1.14.21.0)", "mypy-boto3-autoscaling-plans (1.14.21.0)", "mypy-boto3-backup (1.14.21.0)", "mypy-boto3-batch (1.14.21.0)", "mypy-boto3-budgets (1.14.21.0)", "mypy-boto3-ce (1.14.21.0)", "mypy-boto3-chime (1.14.21.0)", "mypy-boto3-cloud9 (1.14.21.0)", "mypy-boto3-clouddirectory (1.14.21.0)", "mypy-boto3-cloudformation (1.14.21.0)", "mypy-boto3-cloudfront (1.14.21.0)", "mypy-boto3-cloudhsm (1.14.21.0)", "mypy-boto3-cloudhsmv2 (1.14.21.0)", "mypy-boto3-cloudsearch (1.14.21.0)", "mypy-boto3-cloudsearchdomain (1.14.21.0)", "mypy-boto3-cloudtrail (1.14.21.0)", "mypy-boto3-cloudwatch (1.14.21.0)", "mypy-boto3-codeartifact (1.14.21.0)", "mypy-boto3-codebuild (1.14.21.0)", "mypy-boto3-codecommit (1.14.21.0)", "mypy-boto3-codedeploy (1.14.21.0)", "mypy-boto3-codeguru-reviewer (1.14.21.0)", "mypy-boto3-codeguruprofiler (1.14.21.0)", "mypy-boto3-codepipeline (1.14.21.0)", "mypy-boto3-codestar (1.14.21.0)", "mypy-boto3-codestar-connections (1.14.21.0)", "mypy-boto3-codestar-notifications (1.14.21.0)", "mypy-boto3-cognito-identity (1.14.21.0)", "mypy-boto3-cognito-idp (1.14.21.0)", "mypy-boto3-cognito-sync (1.14.21.0)", "mypy-boto3-comprehend (1.14.21.0)", "mypy-boto3-comprehendmedical (1.14.21.0)", "mypy-boto3-compute-optimizer (1.14.21.0)", "mypy-boto3-config (1.14.21.0)", "mypy-boto3-connect (1.14.21.0)", "mypy-boto3-connectparticipant (1.14.21.0)", "mypy-boto3-cur (1.14.21.0)", "mypy-boto3-dataexchange (1.14.21.0)", "mypy-boto3-datapipeline (1.14.21.0)", "mypy-boto3-datasync (1.14.21.0)", "mypy-boto3-dax (1.14.21.0)", "mypy-boto3-detective (1.14.21.0)", "mypy-boto3-devicefarm (1.14.21.0)", "mypy-boto3-directconnect (1.14.21.0)", "mypy-boto3-discovery (1.14.21.0)", "mypy-boto3-dlm (1.14.21.0)", "mypy-boto3-dms (1.14.21.0)", "mypy-boto3-docdb (1.14.21.0)", "mypy-boto3-ds (1.14.21.0)", "mypy-boto3-dynamodb (1.14.21.0)", "mypy-boto3-dynamodbstreams (1.14.21.0)", "mypy-boto3-ebs (1.14.21.0)", "mypy-boto3-ec2 (1.14.21.0)", "mypy-boto3-ec2-instance-connect (1.14.21.0)", "mypy-boto3-ecr (1.14.21.0)", "mypy-boto3-ecs (1.14.21.0)", "mypy-boto3-efs (1.14.21.0)", "mypy-boto3-eks (1.14.21.0)", "mypy-boto3-elastic-inference (1.14.21.0)", "mypy-boto3-elasticache (1.14.21.0)", "mypy-boto3-elasticbeanstalk (1.14.21.0)", "mypy-boto3-elastictranscoder (1.14.21.0)", "mypy-boto3-elb (1.14.21.0)", "mypy-boto3-elbv2 (1.14.21.0)", "mypy-boto3-emr (1.14.21.0)", "mypy-boto3-es (1.14.21.0)", "mypy-boto3-events (1.14.21.0)", "mypy-boto3-firehose (1.14.21.0)", "mypy-boto3-fms (1.14.21.0)", "mypy-boto3-forecast (1.14.21.0)", "mypy-boto3-forecastquery (1.14.21.0)", "mypy-boto3-frauddetector (1.14.21.0)", "mypy-boto3-fsx (1.14.21.0)", "mypy-boto3-gamelift (1.14.21.0)", "mypy-boto3-glacier (1.14.21.0)", "mypy-boto3-globalaccelerator (1.14.21.0)", "mypy-boto3-glue (1.14.21.0)", "mypy-boto3-greengrass (1.14.21.0)", "mypy-boto3-groundstation (1.14.21.0)", "mypy-boto3-guardduty (1.14.21.0)", "mypy-boto3-health (1.14.21.0)", "mypy-boto3-iam (1.14.21.0)", "mypy-boto3-imagebuilder (1.14.21.0)", "mypy-boto3-importexport (1.14.21.0)", "mypy-boto3-inspector (1.14.21.0)", "mypy-boto3-iot (1.14.21.0)", "mypy-boto3-iot-data (1.14.21.0)", "mypy-boto3-iot-jobs-data (1.14.21.0)", "mypy-boto3-iot1click-devices (1.14.21.0)", "mypy-boto3-iot1click-projects (1.14.21.0)", "mypy-boto3-iotanalytics (1.14.21.0)", "mypy-boto3-iotevents (1.14.21.0)", "mypy-boto3-iotevents-data (1.14.21.0)", "mypy-boto3-iotsecuretunneling (1.14.21.0)", "mypy-boto3-iotsitewise (1.14.21.0)", "mypy-boto3-iotthingsgraph (1.14.21.0)", "mypy-boto3-kafka (1.14.21.0)", "mypy-boto3-kendra (1.14.21.0)", "mypy-boto3-kinesis (1.14.21.0)", "mypy-boto3-kinesis-video-archived-media (1.14.21.0)", "mypy-boto3-kinesis-video-media (1.14.21.0)", "mypy-boto3-kinesis-video-signaling (1.14.21.0)", "mypy-boto3-kinesisanalytics (1.14.21.0)", "mypy-boto3-kinesisanalyticsv2 (1.14.21.0)", "mypy-boto3-kinesisvideo (1.14.21.0)", "mypy-boto3-kms (1.14.21.0)", "mypy-boto3-lakeformation (1.14.21.0)", "mypy-boto3-lambda (1.14.21.0)", "mypy-boto3-lex-models (1.14.21.0)", "mypy-boto3-lex-runtime (1.14.21.0)", "mypy-boto3-license-manager (1.14.21.0)", "mypy-boto3-lightsail (1.14.21.0)", "mypy-boto3-logs (1.14.21.0)", "mypy-boto3-machinelearning (1.14.21.0)", "mypy-boto3-macie (1.14.21.0)", "mypy-boto3-macie2 (1.14.21.0)", "mypy-boto3-managedblockchain (1.14.21.0)", "mypy-boto3-marketplace-catalog (1.14.21.0)", "mypy-boto3-marketplace-entitlement (1.14.21.0)", "mypy-boto3-marketplacecommerceanalytics (1.14.21.0)", "mypy-boto3-mediaconnect (1.14.21.0)", "mypy-boto3-mediaconvert (1.14.21.0)", "mypy-boto3-medialive (1.14.21.0)", "mypy-boto3-mediapackage (1.14.21.0)", "mypy-boto3-mediapackage-vod (1.14.21.0)", "mypy-boto3-mediastore (1.14.21.0)", "mypy-boto3-mediastore-data (1.14.21.0)", "mypy-boto3-mediatailor (1.14.21.0)", "mypy-boto3-meteringmarketplace (1.14.21.0)", "mypy-boto3-mgh (1.14.21.0)", "mypy-boto3-migrationhub-config (1.14.21.0)", "mypy-boto3-mobile (1.14.21.0)", "mypy-boto3-mq (1.14.21.0)", "mypy-boto3-mturk (1.14.21.0)", "mypy-boto3-neptune (1.14.21.0)", "mypy-boto3-networkmanager (1.14.21.0)", "mypy-boto3-opsworks (1.14.21.0)", "mypy-boto3-opsworkscm (1.14.21.0)", "mypy-boto3-organizations (1.14.21.0)", "mypy-boto3-outposts (1.14.21.0)", "mypy-boto3-personalize (1.14.21.0)", "mypy-boto3-personalize-events (1.14.21.0)", "mypy-boto3-personalize-runtime (1.14.21.0)", "mypy-boto3-pi (1.14.21.0)", "mypy-boto3-pinpoint (1.14.21.0)", "mypy-boto3-pinpoint-email (1.14.21.0)", "mypy-boto3-pinpoint-sms-voice (1.14.21.0)", "mypy-boto3-polly (1.14.21.0)", "mypy-boto3-pricing (1.14.21.0)", "mypy-boto3-qldb (1.14.21.0)", "mypy-boto3-qldb-session (1.14.21.0)", "mypy-boto3-quicksight (1.14.21.0)", "mypy-boto3-ram (1.14.21.0)", "mypy-boto3-rds (1.14.21.0)", "mypy-boto3-rds-data (1.14.21.0)", "mypy-boto3-redshift (1.14.21.0)", "mypy-boto3-rekognition (1.14.21.0)", "mypy-boto3-resource-groups (1.14.21.0)", "mypy-boto3-resourcegroupstaggingapi (1.14.21.0)", "mypy-boto3-robomaker (1.14.21.0)", "mypy-boto3-route53 (1.14.21.0)", "mypy-boto3-route53domains (1.14.21.0)", "mypy-boto3-route53resolver (1.14.21.0)", "mypy-boto3-s3 (1.14.21.0)", "mypy-boto3-s3control (1.14.21.0)", "mypy-boto3-sagemaker (1.14.21.0)", "mypy-boto3-sagemaker-a2i-runtime (1.14.21.0)", "mypy-boto3-sagemaker-runtime (1.14.21.0)", "mypy-boto3-savingsplans (1.14.21.0)", "mypy-boto3-schemas (1.14.21.0)", "mypy-boto3-sdb (1.14.21.0)", "mypy-boto3-secretsmanager (1.14.21.0)", "mypy-boto3-securityhub (1.14.21.0)", "mypy-boto3-serverlessrepo (1.14.21.0)", "mypy-boto3-service-quotas (1.14.21.0)", "mypy-boto3-servicecatalog (1.14.21.0)", "mypy-boto3-servicediscovery (1.14.21.0)", "mypy-boto3-ses (1.14.21.0)", "mypy-boto3-sesv2 (1.14.21.0)", "mypy-boto3-shield (1.14.21.0)", "mypy-boto3-signer (1.14.21.0)", "mypy-boto3-sms (1.14.21.0)", "mypy-boto3-sms-voice (1.14.21.0)", "mypy-boto3-snowball (1.14.21.0)", "mypy-boto3-sns (1.14.21.0)", "mypy-boto3-sqs (1.14.21.0)", "mypy-boto3-ssm (1.14.21.0)", "mypy-boto3-sso (1.14.21.0)", "mypy-boto3-sso-oidc (1.14.21.0)", "mypy-boto3-stepfunctions (1.14.21.0)", "mypy-boto3-storagegateway (1.14.21.0)", "mypy-boto3-sts (1.14.21.0)", "mypy-boto3-support (1.14.21.0)", "mypy-boto3-swf (1.14.21.0)", "mypy-boto3-synthetics (1.14.21.0)", "mypy-boto3-textract (1.14.21.0)", "mypy-boto3-transcribe (1.14.21.0)", "mypy-boto3-transfer (1.14.21.0)", "mypy-boto3-translate (1.14.21.0)", "mypy-boto3-waf (1.14.21.0)", "mypy-boto3-waf-regional (1.14.21.0)", "mypy-boto3-wafv2 (1.14.21.0)", "mypy-boto3-workdocs (1.14.21.0)", "mypy-boto3-worklink (1.14.21.0)", "mypy-boto3-workmail (1.14.21.0)", "mypy-boto3-workmailmessageflow (1.14.21.0)", "mypy-boto3-workspaces (1.14.21.0)", "mypy-boto3-xray (1.14.21.0)"] -amplify = ["mypy-boto3-amplify (1.14.21.0)"] -apigateway = ["mypy-boto3-apigateway (1.14.21.0)"] -apigatewaymanagementapi = ["mypy-boto3-apigatewaymanagementapi (1.14.21.0)"] -apigatewayv2 = ["mypy-boto3-apigatewayv2 (1.14.21.0)"] -appconfig = ["mypy-boto3-appconfig (1.14.21.0)"] -application-autoscaling = ["mypy-boto3-application-autoscaling (1.14.21.0)"] -application-insights = ["mypy-boto3-application-insights (1.14.21.0)"] -appmesh = ["mypy-boto3-appmesh (1.14.21.0)"] -appstream = ["mypy-boto3-appstream (1.14.21.0)"] -appsync = ["mypy-boto3-appsync (1.14.21.0)"] -athena = ["mypy-boto3-athena (1.14.21.0)"] -autoscaling = ["mypy-boto3-autoscaling (1.14.21.0)"] -autoscaling-plans = ["mypy-boto3-autoscaling-plans (1.14.21.0)"] -backup = ["mypy-boto3-backup (1.14.21.0)"] -batch = ["mypy-boto3-batch (1.14.21.0)"] -budgets = ["mypy-boto3-budgets (1.14.21.0)"] -ce = ["mypy-boto3-ce (1.14.21.0)"] -chime = ["mypy-boto3-chime (1.14.21.0)"] -cloud9 = ["mypy-boto3-cloud9 (1.14.21.0)"] -clouddirectory = ["mypy-boto3-clouddirectory (1.14.21.0)"] -cloudformation = ["mypy-boto3-cloudformation (1.14.21.0)"] -cloudfront = ["mypy-boto3-cloudfront (1.14.21.0)"] -cloudhsm = ["mypy-boto3-cloudhsm (1.14.21.0)"] -cloudhsmv2 = ["mypy-boto3-cloudhsmv2 (1.14.21.0)"] -cloudsearch = ["mypy-boto3-cloudsearch (1.14.21.0)"] -cloudsearchdomain = ["mypy-boto3-cloudsearchdomain (1.14.21.0)"] -cloudtrail = ["mypy-boto3-cloudtrail (1.14.21.0)"] -cloudwatch = ["mypy-boto3-cloudwatch (1.14.21.0)"] -codeartifact = ["mypy-boto3-codeartifact (1.14.21.0)"] -codebuild = ["mypy-boto3-codebuild (1.14.21.0)"] -codecommit = ["mypy-boto3-codecommit (1.14.21.0)"] -codedeploy = ["mypy-boto3-codedeploy (1.14.21.0)"] -codeguru-reviewer = ["mypy-boto3-codeguru-reviewer (1.14.21.0)"] -codeguruprofiler = ["mypy-boto3-codeguruprofiler (1.14.21.0)"] -codepipeline = ["mypy-boto3-codepipeline (1.14.21.0)"] -codestar = ["mypy-boto3-codestar (1.14.21.0)"] -codestar-connections = ["mypy-boto3-codestar-connections (1.14.21.0)"] -codestar-notifications = ["mypy-boto3-codestar-notifications (1.14.21.0)"] -cognito-identity = ["mypy-boto3-cognito-identity (1.14.21.0)"] -cognito-idp = ["mypy-boto3-cognito-idp (1.14.21.0)"] -cognito-sync = ["mypy-boto3-cognito-sync (1.14.21.0)"] -comprehend = ["mypy-boto3-comprehend (1.14.21.0)"] -comprehendmedical = ["mypy-boto3-comprehendmedical (1.14.21.0)"] -compute-optimizer = ["mypy-boto3-compute-optimizer (1.14.21.0)"] -config = ["mypy-boto3-config (1.14.21.0)"] -connect = ["mypy-boto3-connect (1.14.21.0)"] -connectparticipant = ["mypy-boto3-connectparticipant (1.14.21.0)"] -cur = ["mypy-boto3-cur (1.14.21.0)"] -dataexchange = ["mypy-boto3-dataexchange (1.14.21.0)"] -datapipeline = ["mypy-boto3-datapipeline (1.14.21.0)"] -datasync = ["mypy-boto3-datasync (1.14.21.0)"] -dax = ["mypy-boto3-dax (1.14.21.0)"] -detective = ["mypy-boto3-detective (1.14.21.0)"] -devicefarm = ["mypy-boto3-devicefarm (1.14.21.0)"] -directconnect = ["mypy-boto3-directconnect (1.14.21.0)"] -discovery = ["mypy-boto3-discovery (1.14.21.0)"] -dlm = ["mypy-boto3-dlm (1.14.21.0)"] -dms = ["mypy-boto3-dms (1.14.21.0)"] -docdb = ["mypy-boto3-docdb (1.14.21.0)"] -ds = ["mypy-boto3-ds (1.14.21.0)"] -dynamodb = ["mypy-boto3-dynamodb (1.14.21.0)"] -dynamodbstreams = ["mypy-boto3-dynamodbstreams (1.14.21.0)"] -ebs = ["mypy-boto3-ebs (1.14.21.0)"] -ec2 = ["mypy-boto3-ec2 (1.14.21.0)"] -ec2-instance-connect = ["mypy-boto3-ec2-instance-connect (1.14.21.0)"] -ecr = ["mypy-boto3-ecr (1.14.21.0)"] -ecs = ["mypy-boto3-ecs (1.14.21.0)"] -efs = ["mypy-boto3-efs (1.14.21.0)"] -eks = ["mypy-boto3-eks (1.14.21.0)"] -elastic-inference = ["mypy-boto3-elastic-inference (1.14.21.0)"] -elasticache = ["mypy-boto3-elasticache (1.14.21.0)"] -elasticbeanstalk = ["mypy-boto3-elasticbeanstalk (1.14.21.0)"] -elastictranscoder = ["mypy-boto3-elastictranscoder (1.14.21.0)"] -elb = ["mypy-boto3-elb (1.14.21.0)"] -elbv2 = ["mypy-boto3-elbv2 (1.14.21.0)"] -emr = ["mypy-boto3-emr (1.14.21.0)"] -es = ["mypy-boto3-es (1.14.21.0)"] -essential = ["mypy-boto3-cloudformation (1.14.21.0)", "mypy-boto3-dynamodb (1.14.21.0)", "mypy-boto3-ec2 (1.14.21.0)", "mypy-boto3-lambda (1.14.21.0)", "mypy-boto3-rds (1.14.21.0)", "mypy-boto3-s3 (1.14.21.0)", "mypy-boto3-sqs (1.14.21.0)"] -events = ["mypy-boto3-events (1.14.21.0)"] -firehose = ["mypy-boto3-firehose (1.14.21.0)"] -fms = ["mypy-boto3-fms (1.14.21.0)"] -forecast = ["mypy-boto3-forecast (1.14.21.0)"] -forecastquery = ["mypy-boto3-forecastquery (1.14.21.0)"] -frauddetector = ["mypy-boto3-frauddetector (1.14.21.0)"] -fsx = ["mypy-boto3-fsx (1.14.21.0)"] -gamelift = ["mypy-boto3-gamelift (1.14.21.0)"] -glacier = ["mypy-boto3-glacier (1.14.21.0)"] -globalaccelerator = ["mypy-boto3-globalaccelerator (1.14.21.0)"] -glue = ["mypy-boto3-glue (1.14.21.0)"] -greengrass = ["mypy-boto3-greengrass (1.14.21.0)"] -groundstation = ["mypy-boto3-groundstation (1.14.21.0)"] -guardduty = ["mypy-boto3-guardduty (1.14.21.0)"] -health = ["mypy-boto3-health (1.14.21.0)"] -iam = ["mypy-boto3-iam (1.14.21.0)"] -imagebuilder = ["mypy-boto3-imagebuilder (1.14.21.0)"] -importexport = ["mypy-boto3-importexport (1.14.21.0)"] -inspector = ["mypy-boto3-inspector (1.14.21.0)"] -iot = ["mypy-boto3-iot (1.14.21.0)"] -iot-data = ["mypy-boto3-iot-data (1.14.21.0)"] -iot-jobs-data = ["mypy-boto3-iot-jobs-data (1.14.21.0)"] -iot1click-devices = ["mypy-boto3-iot1click-devices (1.14.21.0)"] -iot1click-projects = ["mypy-boto3-iot1click-projects (1.14.21.0)"] -iotanalytics = ["mypy-boto3-iotanalytics (1.14.21.0)"] -iotevents = ["mypy-boto3-iotevents (1.14.21.0)"] -iotevents-data = ["mypy-boto3-iotevents-data (1.14.21.0)"] -iotsecuretunneling = ["mypy-boto3-iotsecuretunneling (1.14.21.0)"] -iotsitewise = ["mypy-boto3-iotsitewise (1.14.21.0)"] -iotthingsgraph = ["mypy-boto3-iotthingsgraph (1.14.21.0)"] -kafka = ["mypy-boto3-kafka (1.14.21.0)"] -kendra = ["mypy-boto3-kendra (1.14.21.0)"] -kinesis = ["mypy-boto3-kinesis (1.14.21.0)"] -kinesis-video-archived-media = ["mypy-boto3-kinesis-video-archived-media (1.14.21.0)"] -kinesis-video-media = ["mypy-boto3-kinesis-video-media (1.14.21.0)"] -kinesis-video-signaling = ["mypy-boto3-kinesis-video-signaling (1.14.21.0)"] -kinesisanalytics = ["mypy-boto3-kinesisanalytics (1.14.21.0)"] -kinesisanalyticsv2 = ["mypy-boto3-kinesisanalyticsv2 (1.14.21.0)"] -kinesisvideo = ["mypy-boto3-kinesisvideo (1.14.21.0)"] -kms = ["mypy-boto3-kms (1.14.21.0)"] -lakeformation = ["mypy-boto3-lakeformation (1.14.21.0)"] -lambda = ["mypy-boto3-lambda (1.14.21.0)"] -lex-models = ["mypy-boto3-lex-models (1.14.21.0)"] -lex-runtime = ["mypy-boto3-lex-runtime (1.14.21.0)"] -license-manager = ["mypy-boto3-license-manager (1.14.21.0)"] -lightsail = ["mypy-boto3-lightsail (1.14.21.0)"] -logs = ["mypy-boto3-logs (1.14.21.0)"] -machinelearning = ["mypy-boto3-machinelearning (1.14.21.0)"] -macie = ["mypy-boto3-macie (1.14.21.0)"] -macie2 = ["mypy-boto3-macie2 (1.14.21.0)"] -managedblockchain = ["mypy-boto3-managedblockchain (1.14.21.0)"] -marketplace-catalog = ["mypy-boto3-marketplace-catalog (1.14.21.0)"] -marketplace-entitlement = ["mypy-boto3-marketplace-entitlement (1.14.21.0)"] -marketplacecommerceanalytics = ["mypy-boto3-marketplacecommerceanalytics (1.14.21.0)"] -mediaconnect = ["mypy-boto3-mediaconnect (1.14.21.0)"] -mediaconvert = ["mypy-boto3-mediaconvert (1.14.21.0)"] -medialive = ["mypy-boto3-medialive (1.14.21.0)"] -mediapackage = ["mypy-boto3-mediapackage (1.14.21.0)"] -mediapackage-vod = ["mypy-boto3-mediapackage-vod (1.14.21.0)"] -mediastore = ["mypy-boto3-mediastore (1.14.21.0)"] -mediastore-data = ["mypy-boto3-mediastore-data (1.14.21.0)"] -mediatailor = ["mypy-boto3-mediatailor (1.14.21.0)"] -meteringmarketplace = ["mypy-boto3-meteringmarketplace (1.14.21.0)"] -mgh = ["mypy-boto3-mgh (1.14.21.0)"] -migrationhub-config = ["mypy-boto3-migrationhub-config (1.14.21.0)"] -mobile = ["mypy-boto3-mobile (1.14.21.0)"] -mq = ["mypy-boto3-mq (1.14.21.0)"] -mturk = ["mypy-boto3-mturk (1.14.21.0)"] -neptune = ["mypy-boto3-neptune (1.14.21.0)"] -networkmanager = ["mypy-boto3-networkmanager (1.14.21.0)"] -opsworks = ["mypy-boto3-opsworks (1.14.21.0)"] -opsworkscm = ["mypy-boto3-opsworkscm (1.14.21.0)"] -organizations = ["mypy-boto3-organizations (1.14.21.0)"] -outposts = ["mypy-boto3-outposts (1.14.21.0)"] -personalize = ["mypy-boto3-personalize (1.14.21.0)"] -personalize-events = ["mypy-boto3-personalize-events (1.14.21.0)"] -personalize-runtime = ["mypy-boto3-personalize-runtime (1.14.21.0)"] -pi = ["mypy-boto3-pi (1.14.21.0)"] -pinpoint = ["mypy-boto3-pinpoint (1.14.21.0)"] -pinpoint-email = ["mypy-boto3-pinpoint-email (1.14.21.0)"] -pinpoint-sms-voice = ["mypy-boto3-pinpoint-sms-voice (1.14.21.0)"] -polly = ["mypy-boto3-polly (1.14.21.0)"] -pricing = ["mypy-boto3-pricing (1.14.21.0)"] -qldb = ["mypy-boto3-qldb (1.14.21.0)"] -qldb-session = ["mypy-boto3-qldb-session (1.14.21.0)"] -quicksight = ["mypy-boto3-quicksight (1.14.21.0)"] -ram = ["mypy-boto3-ram (1.14.21.0)"] -rds = ["mypy-boto3-rds (1.14.21.0)"] -rds-data = ["mypy-boto3-rds-data (1.14.21.0)"] -redshift = ["mypy-boto3-redshift (1.14.21.0)"] -rekognition = ["mypy-boto3-rekognition (1.14.21.0)"] -resource-groups = ["mypy-boto3-resource-groups (1.14.21.0)"] -resourcegroupstaggingapi = ["mypy-boto3-resourcegroupstaggingapi (1.14.21.0)"] -robomaker = ["mypy-boto3-robomaker (1.14.21.0)"] -route53 = ["mypy-boto3-route53 (1.14.21.0)"] -route53domains = ["mypy-boto3-route53domains (1.14.21.0)"] -route53resolver = ["mypy-boto3-route53resolver (1.14.21.0)"] -s3 = ["mypy-boto3-s3 (1.14.21.0)"] -s3control = ["mypy-boto3-s3control (1.14.21.0)"] -sagemaker = ["mypy-boto3-sagemaker (1.14.21.0)"] -sagemaker-a2i-runtime = ["mypy-boto3-sagemaker-a2i-runtime (1.14.21.0)"] -sagemaker-runtime = ["mypy-boto3-sagemaker-runtime (1.14.21.0)"] -savingsplans = ["mypy-boto3-savingsplans (1.14.21.0)"] -schemas = ["mypy-boto3-schemas (1.14.21.0)"] -sdb = ["mypy-boto3-sdb (1.14.21.0)"] -secretsmanager = ["mypy-boto3-secretsmanager (1.14.21.0)"] -securityhub = ["mypy-boto3-securityhub (1.14.21.0)"] -serverlessrepo = ["mypy-boto3-serverlessrepo (1.14.21.0)"] -service-quotas = ["mypy-boto3-service-quotas (1.14.21.0)"] -servicecatalog = ["mypy-boto3-servicecatalog (1.14.21.0)"] -servicediscovery = ["mypy-boto3-servicediscovery (1.14.21.0)"] -ses = ["mypy-boto3-ses (1.14.21.0)"] -sesv2 = ["mypy-boto3-sesv2 (1.14.21.0)"] -shield = ["mypy-boto3-shield (1.14.21.0)"] -signer = ["mypy-boto3-signer (1.14.21.0)"] -sms = ["mypy-boto3-sms (1.14.21.0)"] -sms-voice = ["mypy-boto3-sms-voice (1.14.21.0)"] -snowball = ["mypy-boto3-snowball (1.14.21.0)"] -sns = ["mypy-boto3-sns (1.14.21.0)"] -sqs = ["mypy-boto3-sqs (1.14.21.0)"] -ssm = ["mypy-boto3-ssm (1.14.21.0)"] -sso = ["mypy-boto3-sso (1.14.21.0)"] -sso-oidc = ["mypy-boto3-sso-oidc (1.14.21.0)"] -stepfunctions = ["mypy-boto3-stepfunctions (1.14.21.0)"] -storagegateway = ["mypy-boto3-storagegateway (1.14.21.0)"] -sts = ["mypy-boto3-sts (1.14.21.0)"] -support = ["mypy-boto3-support (1.14.21.0)"] -swf = ["mypy-boto3-swf (1.14.21.0)"] -synthetics = ["mypy-boto3-synthetics (1.14.21.0)"] -textract = ["mypy-boto3-textract (1.14.21.0)"] -transcribe = ["mypy-boto3-transcribe (1.14.21.0)"] -transfer = ["mypy-boto3-transfer (1.14.21.0)"] -translate = ["mypy-boto3-translate (1.14.21.0)"] -waf = ["mypy-boto3-waf (1.14.21.0)"] -waf-regional = ["mypy-boto3-waf-regional (1.14.21.0)"] -wafv2 = ["mypy-boto3-wafv2 (1.14.21.0)"] -workdocs = ["mypy-boto3-workdocs (1.14.21.0)"] -worklink = ["mypy-boto3-worklink (1.14.21.0)"] -workmail = ["mypy-boto3-workmail (1.14.21.0)"] -workmailmessageflow = ["mypy-boto3-workmailmessageflow (1.14.21.0)"] -workspaces = ["mypy-boto3-workspaces (1.14.21.0)"] -xray = ["mypy-boto3-xray (1.14.21.0)"] +accessanalyzer = ["mypy-boto3-accessanalyzer (>=1.18.47)"] +account = ["mypy-boto3-account (>=1.18.47)"] +acm = ["mypy-boto3-acm (>=1.18.47)"] +acm-pca = ["mypy-boto3-acm-pca (>=1.18.47)"] +alexaforbusiness = ["mypy-boto3-alexaforbusiness (>=1.18.47)"] +all = ["mypy-boto3-accessanalyzer (>=1.18.47)", "mypy-boto3-account (>=1.18.47)", "mypy-boto3-acm (>=1.18.47)", "mypy-boto3-acm-pca (>=1.18.47)", "mypy-boto3-alexaforbusiness (>=1.18.47)", "mypy-boto3-amp (>=1.18.47)", "mypy-boto3-amplify (>=1.18.47)", "mypy-boto3-amplifybackend (>=1.18.47)", "mypy-boto3-apigateway (>=1.18.47)", "mypy-boto3-apigatewaymanagementapi (>=1.18.47)", "mypy-boto3-apigatewayv2 (>=1.18.47)", "mypy-boto3-appconfig (>=1.18.47)", "mypy-boto3-appflow (>=1.18.47)", "mypy-boto3-appintegrations (>=1.18.47)", "mypy-boto3-application-autoscaling (>=1.18.47)", "mypy-boto3-application-insights (>=1.18.47)", "mypy-boto3-applicationcostprofiler (>=1.18.47)", "mypy-boto3-appmesh (>=1.18.47)", "mypy-boto3-apprunner (>=1.18.47)", "mypy-boto3-appstream (>=1.18.47)", "mypy-boto3-appsync (>=1.18.47)", "mypy-boto3-athena (>=1.18.47)", "mypy-boto3-auditmanager (>=1.18.47)", "mypy-boto3-autoscaling (>=1.18.47)", "mypy-boto3-autoscaling-plans (>=1.18.47)", "mypy-boto3-backup (>=1.18.47)", "mypy-boto3-batch (>=1.18.47)", "mypy-boto3-braket (>=1.18.47)", "mypy-boto3-budgets (>=1.18.47)", "mypy-boto3-ce (>=1.18.47)", "mypy-boto3-chime (>=1.18.47)", "mypy-boto3-chime-sdk-identity (>=1.18.47)", "mypy-boto3-chime-sdk-messaging (>=1.18.47)", "mypy-boto3-cloud9 (>=1.18.47)", "mypy-boto3-cloudcontrol (>=1.18.47)", "mypy-boto3-clouddirectory (>=1.18.47)", "mypy-boto3-cloudformation (>=1.18.47)", "mypy-boto3-cloudfront (>=1.18.47)", "mypy-boto3-cloudhsm (>=1.18.47)", "mypy-boto3-cloudhsmv2 (>=1.18.47)", "mypy-boto3-cloudsearch (>=1.18.47)", "mypy-boto3-cloudsearchdomain (>=1.18.47)", "mypy-boto3-cloudtrail (>=1.18.47)", "mypy-boto3-cloudwatch (>=1.18.47)", "mypy-boto3-codeartifact (>=1.18.47)", "mypy-boto3-codebuild (>=1.18.47)", "mypy-boto3-codecommit (>=1.18.47)", "mypy-boto3-codedeploy (>=1.18.47)", "mypy-boto3-codeguru-reviewer (>=1.18.47)", "mypy-boto3-codeguruprofiler (>=1.18.47)", "mypy-boto3-codepipeline (>=1.18.47)", "mypy-boto3-codestar (>=1.18.47)", "mypy-boto3-codestar-connections (>=1.18.47)", "mypy-boto3-codestar-notifications (>=1.18.47)", "mypy-boto3-cognito-identity (>=1.18.47)", "mypy-boto3-cognito-idp (>=1.18.47)", "mypy-boto3-cognito-sync (>=1.18.47)", "mypy-boto3-comprehend (>=1.18.47)", "mypy-boto3-comprehendmedical (>=1.18.47)", "mypy-boto3-compute-optimizer (>=1.18.47)", "mypy-boto3-config (>=1.18.47)", "mypy-boto3-connect (>=1.18.47)", "mypy-boto3-connect-contact-lens (>=1.18.47)", "mypy-boto3-connectparticipant (>=1.18.47)", "mypy-boto3-cur (>=1.18.47)", "mypy-boto3-customer-profiles (>=1.18.47)", "mypy-boto3-databrew (>=1.18.47)", "mypy-boto3-dataexchange (>=1.18.47)", "mypy-boto3-datapipeline (>=1.18.47)", "mypy-boto3-datasync (>=1.18.47)", "mypy-boto3-dax (>=1.18.47)", "mypy-boto3-detective (>=1.18.47)", "mypy-boto3-devicefarm (>=1.18.47)", "mypy-boto3-devops-guru (>=1.18.47)", "mypy-boto3-directconnect (>=1.18.47)", "mypy-boto3-discovery (>=1.18.47)", "mypy-boto3-dlm (>=1.18.47)", "mypy-boto3-dms (>=1.18.47)", "mypy-boto3-docdb (>=1.18.47)", "mypy-boto3-ds (>=1.18.47)", "mypy-boto3-dynamodb (>=1.18.47)", "mypy-boto3-dynamodbstreams (>=1.18.47)", "mypy-boto3-ebs (>=1.18.47)", "mypy-boto3-ec2 (>=1.18.47)", "mypy-boto3-ec2-instance-connect (>=1.18.47)", "mypy-boto3-ecr (>=1.18.47)", "mypy-boto3-ecr-public (>=1.18.47)", "mypy-boto3-ecs (>=1.18.47)", "mypy-boto3-efs (>=1.18.47)", "mypy-boto3-eks (>=1.18.47)", "mypy-boto3-elastic-inference (>=1.18.47)", "mypy-boto3-elasticache (>=1.18.47)", "mypy-boto3-elasticbeanstalk (>=1.18.47)", "mypy-boto3-elastictranscoder (>=1.18.47)", "mypy-boto3-elb (>=1.18.47)", "mypy-boto3-elbv2 (>=1.18.47)", "mypy-boto3-emr (>=1.18.47)", "mypy-boto3-emr-containers (>=1.18.47)", "mypy-boto3-es (>=1.18.47)", "mypy-boto3-events (>=1.18.47)", "mypy-boto3-finspace (>=1.18.47)", "mypy-boto3-finspace-data (>=1.18.47)", "mypy-boto3-firehose (>=1.18.47)", "mypy-boto3-fis (>=1.18.47)", "mypy-boto3-fms (>=1.18.47)", "mypy-boto3-forecast (>=1.18.47)", "mypy-boto3-forecastquery (>=1.18.47)", "mypy-boto3-frauddetector (>=1.18.47)", "mypy-boto3-fsx (>=1.18.47)", "mypy-boto3-gamelift (>=1.18.47)", "mypy-boto3-glacier (>=1.18.47)", "mypy-boto3-globalaccelerator (>=1.18.47)", "mypy-boto3-glue (>=1.18.47)", "mypy-boto3-greengrass (>=1.18.47)", "mypy-boto3-greengrassv2 (>=1.18.47)", "mypy-boto3-groundstation (>=1.18.47)", "mypy-boto3-guardduty (>=1.18.47)", "mypy-boto3-health (>=1.18.47)", "mypy-boto3-healthlake (>=1.18.47)", "mypy-boto3-honeycode (>=1.18.47)", "mypy-boto3-iam (>=1.18.47)", "mypy-boto3-identitystore (>=1.18.47)", "mypy-boto3-imagebuilder (>=1.18.47)", "mypy-boto3-importexport (>=1.18.47)", "mypy-boto3-inspector (>=1.18.47)", "mypy-boto3-iot (>=1.18.47)", "mypy-boto3-iot-data (>=1.18.47)", "mypy-boto3-iot-jobs-data (>=1.18.47)", "mypy-boto3-iot1click-devices (>=1.18.47)", "mypy-boto3-iot1click-projects (>=1.18.47)", "mypy-boto3-iotanalytics (>=1.18.47)", "mypy-boto3-iotdeviceadvisor (>=1.18.47)", "mypy-boto3-iotevents (>=1.18.47)", "mypy-boto3-iotevents-data (>=1.18.47)", "mypy-boto3-iotfleethub (>=1.18.47)", "mypy-boto3-iotsecuretunneling (>=1.18.47)", "mypy-boto3-iotsitewise (>=1.18.47)", "mypy-boto3-iotthingsgraph (>=1.18.47)", "mypy-boto3-iotwireless (>=1.18.47)", "mypy-boto3-ivs (>=1.18.47)", "mypy-boto3-kafka (>=1.18.47)", "mypy-boto3-kafkaconnect (>=1.18.47)", "mypy-boto3-kendra (>=1.18.47)", "mypy-boto3-kinesis (>=1.18.47)", "mypy-boto3-kinesis-video-archived-media (>=1.18.47)", "mypy-boto3-kinesis-video-media (>=1.18.47)", "mypy-boto3-kinesis-video-signaling (>=1.18.47)", "mypy-boto3-kinesisanalytics (>=1.18.47)", "mypy-boto3-kinesisanalyticsv2 (>=1.18.47)", "mypy-boto3-kinesisvideo (>=1.18.47)", "mypy-boto3-kms (>=1.18.47)", "mypy-boto3-lakeformation (>=1.18.47)", "mypy-boto3-lambda (>=1.18.47)", "mypy-boto3-lex-models (>=1.18.47)", "mypy-boto3-lex-runtime (>=1.18.47)", "mypy-boto3-lexv2-models (>=1.18.47)", "mypy-boto3-lexv2-runtime (>=1.18.47)", "mypy-boto3-license-manager (>=1.18.47)", "mypy-boto3-lightsail (>=1.18.47)", "mypy-boto3-location (>=1.18.47)", "mypy-boto3-logs (>=1.18.47)", "mypy-boto3-lookoutequipment (>=1.18.47)", "mypy-boto3-lookoutmetrics (>=1.18.47)", "mypy-boto3-lookoutvision (>=1.18.47)", "mypy-boto3-machinelearning (>=1.18.47)", "mypy-boto3-macie (>=1.18.47)", "mypy-boto3-macie2 (>=1.18.47)", "mypy-boto3-managedblockchain (>=1.18.47)", "mypy-boto3-marketplace-catalog (>=1.18.47)", "mypy-boto3-marketplace-entitlement (>=1.18.47)", "mypy-boto3-marketplacecommerceanalytics (>=1.18.47)", "mypy-boto3-mediaconnect (>=1.18.47)", "mypy-boto3-mediaconvert (>=1.18.47)", "mypy-boto3-medialive (>=1.18.47)", "mypy-boto3-mediapackage (>=1.18.47)", "mypy-boto3-mediapackage-vod (>=1.18.47)", "mypy-boto3-mediastore (>=1.18.47)", "mypy-boto3-mediastore-data (>=1.18.47)", "mypy-boto3-mediatailor (>=1.18.47)", "mypy-boto3-memorydb (>=1.18.47)", "mypy-boto3-meteringmarketplace (>=1.18.47)", "mypy-boto3-mgh (>=1.18.47)", "mypy-boto3-mgn (>=1.18.47)", "mypy-boto3-migrationhub-config (>=1.18.47)", "mypy-boto3-mobile (>=1.18.47)", "mypy-boto3-mq (>=1.18.47)", "mypy-boto3-mturk (>=1.18.47)", "mypy-boto3-mwaa (>=1.18.47)", "mypy-boto3-neptune (>=1.18.47)", "mypy-boto3-network-firewall (>=1.18.47)", "mypy-boto3-networkmanager (>=1.18.47)", "mypy-boto3-nimble (>=1.18.47)", "mypy-boto3-opensearch (>=1.18.47)", "mypy-boto3-opsworks (>=1.18.47)", "mypy-boto3-opsworkscm (>=1.18.47)", "mypy-boto3-organizations (>=1.18.47)", "mypy-boto3-outposts (>=1.18.47)", "mypy-boto3-personalize (>=1.18.47)", "mypy-boto3-personalize-events (>=1.18.47)", "mypy-boto3-personalize-runtime (>=1.18.47)", "mypy-boto3-pi (>=1.18.47)", "mypy-boto3-pinpoint (>=1.18.47)", "mypy-boto3-pinpoint-email (>=1.18.47)", "mypy-boto3-pinpoint-sms-voice (>=1.18.47)", "mypy-boto3-polly (>=1.18.47)", "mypy-boto3-pricing (>=1.18.47)", "mypy-boto3-proton (>=1.18.47)", "mypy-boto3-qldb (>=1.18.47)", "mypy-boto3-qldb-session (>=1.18.47)", "mypy-boto3-quicksight (>=1.18.47)", "mypy-boto3-ram (>=1.18.47)", "mypy-boto3-rds (>=1.18.47)", "mypy-boto3-rds-data (>=1.18.47)", "mypy-boto3-redshift (>=1.18.47)", "mypy-boto3-redshift-data (>=1.18.47)", "mypy-boto3-rekognition (>=1.18.47)", "mypy-boto3-resource-groups (>=1.18.47)", "mypy-boto3-resourcegroupstaggingapi (>=1.18.47)", "mypy-boto3-robomaker (>=1.18.47)", "mypy-boto3-route53 (>=1.18.47)", "mypy-boto3-route53-recovery-cluster (>=1.18.47)", "mypy-boto3-route53-recovery-control-config (>=1.18.47)", "mypy-boto3-route53-recovery-readiness (>=1.18.47)", "mypy-boto3-route53domains (>=1.18.47)", "mypy-boto3-route53resolver (>=1.18.47)", "mypy-boto3-s3 (>=1.18.47)", "mypy-boto3-s3control (>=1.18.47)", "mypy-boto3-s3outposts (>=1.18.47)", "mypy-boto3-sagemaker (>=1.18.47)", "mypy-boto3-sagemaker-a2i-runtime (>=1.18.47)", "mypy-boto3-sagemaker-edge (>=1.18.47)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.18.47)", "mypy-boto3-sagemaker-runtime (>=1.18.47)", "mypy-boto3-savingsplans (>=1.18.47)", "mypy-boto3-schemas (>=1.18.47)", "mypy-boto3-sdb (>=1.18.47)", "mypy-boto3-secretsmanager (>=1.18.47)", "mypy-boto3-securityhub (>=1.18.47)", "mypy-boto3-serverlessrepo (>=1.18.47)", "mypy-boto3-service-quotas (>=1.18.47)", "mypy-boto3-servicecatalog (>=1.18.47)", "mypy-boto3-servicecatalog-appregistry (>=1.18.47)", "mypy-boto3-servicediscovery (>=1.18.47)", "mypy-boto3-ses (>=1.18.47)", "mypy-boto3-sesv2 (>=1.18.47)", "mypy-boto3-shield (>=1.18.47)", "mypy-boto3-signer (>=1.18.47)", "mypy-boto3-sms (>=1.18.47)", "mypy-boto3-sms-voice (>=1.18.47)", "mypy-boto3-snow-device-management (>=1.18.47)", "mypy-boto3-snowball (>=1.18.47)", "mypy-boto3-sns (>=1.18.47)", "mypy-boto3-sqs (>=1.18.47)", "mypy-boto3-ssm (>=1.18.47)", "mypy-boto3-ssm-contacts (>=1.18.47)", "mypy-boto3-ssm-incidents (>=1.18.47)", "mypy-boto3-sso (>=1.18.47)", "mypy-boto3-sso-admin (>=1.18.47)", "mypy-boto3-sso-oidc (>=1.18.47)", "mypy-boto3-stepfunctions (>=1.18.47)", "mypy-boto3-storagegateway (>=1.18.47)", "mypy-boto3-sts (>=1.18.47)", "mypy-boto3-support (>=1.18.47)", "mypy-boto3-swf (>=1.18.47)", "mypy-boto3-synthetics (>=1.18.47)", "mypy-boto3-textract (>=1.18.47)", "mypy-boto3-timestream-query (>=1.18.47)", "mypy-boto3-timestream-write (>=1.18.47)", "mypy-boto3-transcribe (>=1.18.47)", "mypy-boto3-transfer (>=1.18.47)", "mypy-boto3-translate (>=1.18.47)", "mypy-boto3-voice-id (>=1.18.47)", "mypy-boto3-waf (>=1.18.47)", "mypy-boto3-waf-regional (>=1.18.47)", "mypy-boto3-wafv2 (>=1.18.47)", "mypy-boto3-wellarchitected (>=1.18.47)", "mypy-boto3-wisdom (>=1.18.47)", "mypy-boto3-workdocs (>=1.18.47)", "mypy-boto3-worklink (>=1.18.47)", "mypy-boto3-workmail (>=1.18.47)", "mypy-boto3-workmailmessageflow (>=1.18.47)", "mypy-boto3-workspaces (>=1.18.47)", "mypy-boto3-xray (>=1.18.47)"] +amp = ["mypy-boto3-amp (>=1.18.47)"] +amplify = ["mypy-boto3-amplify (>=1.18.47)"] +amplifybackend = ["mypy-boto3-amplifybackend (>=1.18.47)"] +apigateway = ["mypy-boto3-apigateway (>=1.18.47)"] +apigatewaymanagementapi = ["mypy-boto3-apigatewaymanagementapi (>=1.18.47)"] +apigatewayv2 = ["mypy-boto3-apigatewayv2 (>=1.18.47)"] +appconfig = ["mypy-boto3-appconfig (>=1.18.47)"] +appflow = ["mypy-boto3-appflow (>=1.18.47)"] +appintegrations = ["mypy-boto3-appintegrations (>=1.18.47)"] +application-autoscaling = ["mypy-boto3-application-autoscaling (>=1.18.47)"] +application-insights = ["mypy-boto3-application-insights (>=1.18.47)"] +applicationcostprofiler = ["mypy-boto3-applicationcostprofiler (>=1.18.47)"] +appmesh = ["mypy-boto3-appmesh (>=1.18.47)"] +apprunner = ["mypy-boto3-apprunner (>=1.18.47)"] +appstream = ["mypy-boto3-appstream (>=1.18.47)"] +appsync = ["mypy-boto3-appsync (>=1.18.47)"] +athena = ["mypy-boto3-athena (>=1.18.47)"] +auditmanager = ["mypy-boto3-auditmanager (>=1.18.47)"] +autoscaling = ["mypy-boto3-autoscaling (>=1.18.47)"] +autoscaling-plans = ["mypy-boto3-autoscaling-plans (>=1.18.47)"] +backup = ["mypy-boto3-backup (>=1.18.47)"] +batch = ["mypy-boto3-batch (>=1.18.47)"] +braket = ["mypy-boto3-braket (>=1.18.47)"] +budgets = ["mypy-boto3-budgets (>=1.18.47)"] +ce = ["mypy-boto3-ce (>=1.18.47)"] +chime = ["mypy-boto3-chime (>=1.18.47)"] +chime-sdk-identity = ["mypy-boto3-chime-sdk-identity (>=1.18.47)"] +chime-sdk-messaging = ["mypy-boto3-chime-sdk-messaging (>=1.18.47)"] +cloud9 = ["mypy-boto3-cloud9 (>=1.18.47)"] +cloudcontrol = ["mypy-boto3-cloudcontrol (>=1.18.47)"] +clouddirectory = ["mypy-boto3-clouddirectory (>=1.18.47)"] +cloudformation = ["mypy-boto3-cloudformation (>=1.18.47)"] +cloudfront = ["mypy-boto3-cloudfront (>=1.18.47)"] +cloudhsm = ["mypy-boto3-cloudhsm (>=1.18.47)"] +cloudhsmv2 = ["mypy-boto3-cloudhsmv2 (>=1.18.47)"] +cloudsearch = ["mypy-boto3-cloudsearch (>=1.18.47)"] +cloudsearchdomain = ["mypy-boto3-cloudsearchdomain (>=1.18.47)"] +cloudtrail = ["mypy-boto3-cloudtrail (>=1.18.47)"] +cloudwatch = ["mypy-boto3-cloudwatch (>=1.18.47)"] +codeartifact = ["mypy-boto3-codeartifact (>=1.18.47)"] +codebuild = ["mypy-boto3-codebuild (>=1.18.47)"] +codecommit = ["mypy-boto3-codecommit (>=1.18.47)"] +codedeploy = ["mypy-boto3-codedeploy (>=1.18.47)"] +codeguru-reviewer = ["mypy-boto3-codeguru-reviewer (>=1.18.47)"] +frauddetector = ["mypy-boto3-frauddetector (>=1.18.47)"] +codeguruprofiler = ["mypy-boto3-codeguruprofiler (>=1.18.47)"] +codepipeline = ["mypy-boto3-codepipeline (>=1.18.47)"] +codestar = ["mypy-boto3-codestar (>=1.18.47)"] +codestar-connections = ["mypy-boto3-codestar-connections (>=1.18.47)"] +codestar-notifications = ["mypy-boto3-codestar-notifications (>=1.18.47)"] +cognito-identity = ["mypy-boto3-cognito-identity (>=1.18.47)"] +cognito-idp = ["mypy-boto3-cognito-idp (>=1.18.47)"] +cognito-sync = ["mypy-boto3-cognito-sync (>=1.18.47)"] +comprehend = ["mypy-boto3-comprehend (>=1.18.47)"] +comprehendmedical = ["mypy-boto3-comprehendmedical (>=1.18.47)"] +compute-optimizer = ["mypy-boto3-compute-optimizer (>=1.18.47)"] +config = ["mypy-boto3-config (>=1.18.47)"] +connect = ["mypy-boto3-connect (>=1.18.47)"] +connect-contact-lens = ["mypy-boto3-connect-contact-lens (>=1.18.47)"] +connectparticipant = ["mypy-boto3-connectparticipant (>=1.18.47)"] +cur = ["mypy-boto3-cur (>=1.18.47)"] +customer-profiles = ["mypy-boto3-customer-profiles (>=1.18.47)"] +databrew = ["mypy-boto3-databrew (>=1.18.47)"] +dataexchange = ["mypy-boto3-dataexchange (>=1.18.47)"] +datapipeline = ["mypy-boto3-datapipeline (>=1.18.47)"] +datasync = ["mypy-boto3-datasync (>=1.18.47)"] +dax = ["mypy-boto3-dax (>=1.18.47)"] +detective = ["mypy-boto3-detective (>=1.18.47)"] +devicefarm = ["mypy-boto3-devicefarm (>=1.18.47)"] +devops-guru = ["mypy-boto3-devops-guru (>=1.18.47)"] +directconnect = ["mypy-boto3-directconnect (>=1.18.47)"] +discovery = ["mypy-boto3-discovery (>=1.18.47)"] +dlm = ["mypy-boto3-dlm (>=1.18.47)"] +dms = ["mypy-boto3-dms (>=1.18.47)"] +docdb = ["mypy-boto3-docdb (>=1.18.47)"] +ds = ["mypy-boto3-ds (>=1.18.47)"] +dynamodb = ["mypy-boto3-dynamodb (>=1.18.47)"] +dynamodbstreams = ["mypy-boto3-dynamodbstreams (>=1.18.47)"] +ebs = ["mypy-boto3-ebs (>=1.18.47)"] +ec2 = ["mypy-boto3-ec2 (>=1.18.47)"] +ec2-instance-connect = ["mypy-boto3-ec2-instance-connect (>=1.18.47)"] +ecr = ["mypy-boto3-ecr (>=1.18.47)"] +ecr-public = ["mypy-boto3-ecr-public (>=1.18.47)"] +ecs = ["mypy-boto3-ecs (>=1.18.47)"] +efs = ["mypy-boto3-efs (>=1.18.47)"] +eks = ["mypy-boto3-eks (>=1.18.47)"] +elastic-inference = ["mypy-boto3-elastic-inference (>=1.18.47)"] +elasticache = ["mypy-boto3-elasticache (>=1.18.47)"] +elasticbeanstalk = ["mypy-boto3-elasticbeanstalk (>=1.18.47)"] +elastictranscoder = ["mypy-boto3-elastictranscoder (>=1.18.47)"] +elb = ["mypy-boto3-elb (>=1.18.47)"] +elbv2 = ["mypy-boto3-elbv2 (>=1.18.47)"] +emr = ["mypy-boto3-emr (>=1.18.47)"] +emr-containers = ["mypy-boto3-emr-containers (>=1.18.47)"] +es = ["mypy-boto3-es (>=1.18.47)"] +essential = ["mypy-boto3-cloudformation (>=1.18.47)", "mypy-boto3-dynamodb (>=1.18.47)", "mypy-boto3-ec2 (>=1.18.47)", "mypy-boto3-lambda (>=1.18.47)", "mypy-boto3-rds (>=1.18.47)", "mypy-boto3-s3 (>=1.18.47)", "mypy-boto3-sqs (>=1.18.47)"] +events = ["mypy-boto3-events (>=1.18.47)"] +finspace = ["mypy-boto3-finspace (>=1.18.47)"] +finspace-data = ["mypy-boto3-finspace-data (>=1.18.47)"] +firehose = ["mypy-boto3-firehose (>=1.18.47)"] +fis = ["mypy-boto3-fis (>=1.18.47)"] +fms = ["mypy-boto3-fms (>=1.18.47)"] +forecast = ["mypy-boto3-forecast (>=1.18.47)"] +forecastquery = ["mypy-boto3-forecastquery (>=1.18.47)"] +fsx = ["mypy-boto3-fsx (>=1.18.47)"] +gamelift = ["mypy-boto3-gamelift (>=1.18.47)"] +glacier = ["mypy-boto3-glacier (>=1.18.47)"] +globalaccelerator = ["mypy-boto3-globalaccelerator (>=1.18.47)"] +glue = ["mypy-boto3-glue (>=1.18.47)"] +greengrass = ["mypy-boto3-greengrass (>=1.18.47)"] +greengrassv2 = ["mypy-boto3-greengrassv2 (>=1.18.47)"] +groundstation = ["mypy-boto3-groundstation (>=1.18.47)"] +guardduty = ["mypy-boto3-guardduty (>=1.18.47)"] +health = ["mypy-boto3-health (>=1.18.47)"] +healthlake = ["mypy-boto3-healthlake (>=1.18.47)"] +honeycode = ["mypy-boto3-honeycode (>=1.18.47)"] +iam = ["mypy-boto3-iam (>=1.18.47)"] +identitystore = ["mypy-boto3-identitystore (>=1.18.47)"] +imagebuilder = ["mypy-boto3-imagebuilder (>=1.18.47)"] +importexport = ["mypy-boto3-importexport (>=1.18.47)"] +inspector = ["mypy-boto3-inspector (>=1.18.47)"] +iot = ["mypy-boto3-iot (>=1.18.47)"] +iot-data = ["mypy-boto3-iot-data (>=1.18.47)"] +iot-jobs-data = ["mypy-boto3-iot-jobs-data (>=1.18.47)"] +iot1click-devices = ["mypy-boto3-iot1click-devices (>=1.18.47)"] +iot1click-projects = ["mypy-boto3-iot1click-projects (>=1.18.47)"] +iotanalytics = ["mypy-boto3-iotanalytics (>=1.18.47)"] +iotdeviceadvisor = ["mypy-boto3-iotdeviceadvisor (>=1.18.47)"] +iotevents = ["mypy-boto3-iotevents (>=1.18.47)"] +iotevents-data = ["mypy-boto3-iotevents-data (>=1.18.47)"] +iotfleethub = ["mypy-boto3-iotfleethub (>=1.18.47)"] +iotsecuretunneling = ["mypy-boto3-iotsecuretunneling (>=1.18.47)"] +iotsitewise = ["mypy-boto3-iotsitewise (>=1.18.47)"] +iotthingsgraph = ["mypy-boto3-iotthingsgraph (>=1.18.47)"] +iotwireless = ["mypy-boto3-iotwireless (>=1.18.47)"] +ivs = ["mypy-boto3-ivs (>=1.18.47)"] +kafka = ["mypy-boto3-kafka (>=1.18.47)"] +kafkaconnect = ["mypy-boto3-kafkaconnect (>=1.18.47)"] +kendra = ["mypy-boto3-kendra (>=1.18.47)"] +kinesis = ["mypy-boto3-kinesis (>=1.18.47)"] +kinesis-video-archived-media = ["mypy-boto3-kinesis-video-archived-media (>=1.18.47)"] +kinesis-video-media = ["mypy-boto3-kinesis-video-media (>=1.18.47)"] +kinesis-video-signaling = ["mypy-boto3-kinesis-video-signaling (>=1.18.47)"] +kinesisanalytics = ["mypy-boto3-kinesisanalytics (>=1.18.47)"] +kinesisanalyticsv2 = ["mypy-boto3-kinesisanalyticsv2 (>=1.18.47)"] +kinesisvideo = ["mypy-boto3-kinesisvideo (>=1.18.47)"] +kms = ["mypy-boto3-kms (>=1.18.47)"] +lakeformation = ["mypy-boto3-lakeformation (>=1.18.47)"] +lambda = ["mypy-boto3-lambda (>=1.18.47)"] +lex-models = ["mypy-boto3-lex-models (>=1.18.47)"] +lex-runtime = ["mypy-boto3-lex-runtime (>=1.18.47)"] +lexv2-models = ["mypy-boto3-lexv2-models (>=1.18.47)"] +lexv2-runtime = ["mypy-boto3-lexv2-runtime (>=1.18.47)"] +license-manager = ["mypy-boto3-license-manager (>=1.18.47)"] +lightsail = ["mypy-boto3-lightsail (>=1.18.47)"] +location = ["mypy-boto3-location (>=1.18.47)"] +logs = ["mypy-boto3-logs (>=1.18.47)"] +lookoutequipment = ["mypy-boto3-lookoutequipment (>=1.18.47)"] +lookoutmetrics = ["mypy-boto3-lookoutmetrics (>=1.18.47)"] +lookoutvision = ["mypy-boto3-lookoutvision (>=1.18.47)"] +machinelearning = ["mypy-boto3-machinelearning (>=1.18.47)"] +macie = ["mypy-boto3-macie (>=1.18.47)"] +macie2 = ["mypy-boto3-macie2 (>=1.18.47)"] +managedblockchain = ["mypy-boto3-managedblockchain (>=1.18.47)"] +marketplace-catalog = ["mypy-boto3-marketplace-catalog (>=1.18.47)"] +marketplace-entitlement = ["mypy-boto3-marketplace-entitlement (>=1.18.47)"] +marketplacecommerceanalytics = ["mypy-boto3-marketplacecommerceanalytics (>=1.18.47)"] +mediaconnect = ["mypy-boto3-mediaconnect (>=1.18.47)"] +mediaconvert = ["mypy-boto3-mediaconvert (>=1.18.47)"] +medialive = ["mypy-boto3-medialive (>=1.18.47)"] +mediapackage = ["mypy-boto3-mediapackage (>=1.18.47)"] +mediapackage-vod = ["mypy-boto3-mediapackage-vod (>=1.18.47)"] +mediastore = ["mypy-boto3-mediastore (>=1.18.47)"] +mediastore-data = ["mypy-boto3-mediastore-data (>=1.18.47)"] +mediatailor = ["mypy-boto3-mediatailor (>=1.18.47)"] +memorydb = ["mypy-boto3-memorydb (>=1.18.47)"] +meteringmarketplace = ["mypy-boto3-meteringmarketplace (>=1.18.47)"] +mgh = ["mypy-boto3-mgh (>=1.18.47)"] +mgn = ["mypy-boto3-mgn (>=1.18.47)"] +migrationhub-config = ["mypy-boto3-migrationhub-config (>=1.18.47)"] +mobile = ["mypy-boto3-mobile (>=1.18.47)"] +mq = ["mypy-boto3-mq (>=1.18.47)"] +mturk = ["mypy-boto3-mturk (>=1.18.47)"] +mwaa = ["mypy-boto3-mwaa (>=1.18.47)"] +neptune = ["mypy-boto3-neptune (>=1.18.47)"] +network-firewall = ["mypy-boto3-network-firewall (>=1.18.47)"] +networkmanager = ["mypy-boto3-networkmanager (>=1.18.47)"] +nimble = ["mypy-boto3-nimble (>=1.18.47)"] +opensearch = ["mypy-boto3-opensearch (>=1.18.47)"] +opsworks = ["mypy-boto3-opsworks (>=1.18.47)"] +opsworkscm = ["mypy-boto3-opsworkscm (>=1.18.47)"] +organizations = ["mypy-boto3-organizations (>=1.18.47)"] +outposts = ["mypy-boto3-outposts (>=1.18.47)"] +personalize = ["mypy-boto3-personalize (>=1.18.47)"] +personalize-events = ["mypy-boto3-personalize-events (>=1.18.47)"] +personalize-runtime = ["mypy-boto3-personalize-runtime (>=1.18.47)"] +pi = ["mypy-boto3-pi (>=1.18.47)"] +pinpoint = ["mypy-boto3-pinpoint (>=1.18.47)"] +pinpoint-email = ["mypy-boto3-pinpoint-email (>=1.18.47)"] +pinpoint-sms-voice = ["mypy-boto3-pinpoint-sms-voice (>=1.18.47)"] +polly = ["mypy-boto3-polly (>=1.18.47)"] +pricing = ["mypy-boto3-pricing (>=1.18.47)"] +proton = ["mypy-boto3-proton (>=1.18.47)"] +qldb = ["mypy-boto3-qldb (>=1.18.47)"] +qldb-session = ["mypy-boto3-qldb-session (>=1.18.47)"] +quicksight = ["mypy-boto3-quicksight (>=1.18.47)"] +ram = ["mypy-boto3-ram (>=1.18.47)"] +rds = ["mypy-boto3-rds (>=1.18.47)"] +rds-data = ["mypy-boto3-rds-data (>=1.18.47)"] +redshift = ["mypy-boto3-redshift (>=1.18.47)"] +redshift-data = ["mypy-boto3-redshift-data (>=1.18.47)"] +rekognition = ["mypy-boto3-rekognition (>=1.18.47)"] +resource-groups = ["mypy-boto3-resource-groups (>=1.18.47)"] +resourcegroupstaggingapi = ["mypy-boto3-resourcegroupstaggingapi (>=1.18.47)"] +robomaker = ["mypy-boto3-robomaker (>=1.18.47)"] +route53 = ["mypy-boto3-route53 (>=1.18.47)"] +route53-recovery-cluster = ["mypy-boto3-route53-recovery-cluster (>=1.18.47)"] +route53-recovery-control-config = ["mypy-boto3-route53-recovery-control-config (>=1.18.47)"] +route53-recovery-readiness = ["mypy-boto3-route53-recovery-readiness (>=1.18.47)"] +route53domains = ["mypy-boto3-route53domains (>=1.18.47)"] +route53resolver = ["mypy-boto3-route53resolver (>=1.18.47)"] +s3 = ["mypy-boto3-s3 (>=1.18.47)"] +s3control = ["mypy-boto3-s3control (>=1.18.47)"] +s3outposts = ["mypy-boto3-s3outposts (>=1.18.47)"] +sagemaker = ["mypy-boto3-sagemaker (>=1.18.47)"] +sagemaker-a2i-runtime = ["mypy-boto3-sagemaker-a2i-runtime (>=1.18.47)"] +sagemaker-edge = ["mypy-boto3-sagemaker-edge (>=1.18.47)"] +sagemaker-featurestore-runtime = ["mypy-boto3-sagemaker-featurestore-runtime (>=1.18.47)"] +sagemaker-runtime = ["mypy-boto3-sagemaker-runtime (>=1.18.47)"] +savingsplans = ["mypy-boto3-savingsplans (>=1.18.47)"] +schemas = ["mypy-boto3-schemas (>=1.18.47)"] +sdb = ["mypy-boto3-sdb (>=1.18.47)"] +secretsmanager = ["mypy-boto3-secretsmanager (>=1.18.47)"] +securityhub = ["mypy-boto3-securityhub (>=1.18.47)"] +serverlessrepo = ["mypy-boto3-serverlessrepo (>=1.18.47)"] +service-quotas = ["mypy-boto3-service-quotas (>=1.18.47)"] +servicecatalog = ["mypy-boto3-servicecatalog (>=1.18.47)"] +servicecatalog-appregistry = ["mypy-boto3-servicecatalog-appregistry (>=1.18.47)"] +servicediscovery = ["mypy-boto3-servicediscovery (>=1.18.47)"] +ses = ["mypy-boto3-ses (>=1.18.47)"] +sesv2 = ["mypy-boto3-sesv2 (>=1.18.47)"] +shield = ["mypy-boto3-shield (>=1.18.47)"] +signer = ["mypy-boto3-signer (>=1.18.47)"] +sms = ["mypy-boto3-sms (>=1.18.47)"] +sms-voice = ["mypy-boto3-sms-voice (>=1.18.47)"] +snow-device-management = ["mypy-boto3-snow-device-management (>=1.18.47)"] +snowball = ["mypy-boto3-snowball (>=1.18.47)"] +sns = ["mypy-boto3-sns (>=1.18.47)"] +sqs = ["mypy-boto3-sqs (>=1.18.47)"] +ssm = ["mypy-boto3-ssm (>=1.18.47)"] +ssm-contacts = ["mypy-boto3-ssm-contacts (>=1.18.47)"] +ssm-incidents = ["mypy-boto3-ssm-incidents (>=1.18.47)"] +sso = ["mypy-boto3-sso (>=1.18.47)"] +sso-admin = ["mypy-boto3-sso-admin (>=1.18.47)"] +sso-oidc = ["mypy-boto3-sso-oidc (>=1.18.47)"] +stepfunctions = ["mypy-boto3-stepfunctions (>=1.18.47)"] +storagegateway = ["mypy-boto3-storagegateway (>=1.18.47)"] +sts = ["mypy-boto3-sts (>=1.18.47)"] +support = ["mypy-boto3-support (>=1.18.47)"] +swf = ["mypy-boto3-swf (>=1.18.47)"] +synthetics = ["mypy-boto3-synthetics (>=1.18.47)"] +textract = ["mypy-boto3-textract (>=1.18.47)"] +timestream-query = ["mypy-boto3-timestream-query (>=1.18.47)"] +timestream-write = ["mypy-boto3-timestream-write (>=1.18.47)"] +transcribe = ["mypy-boto3-transcribe (>=1.18.47)"] +transfer = ["mypy-boto3-transfer (>=1.18.47)"] +translate = ["mypy-boto3-translate (>=1.18.47)"] +voice-id = ["mypy-boto3-voice-id (>=1.18.47)"] +waf = ["mypy-boto3-waf (>=1.18.47)"] +waf-regional = ["mypy-boto3-waf-regional (>=1.18.47)"] +wafv2 = ["mypy-boto3-wafv2 (>=1.18.47)"] +wellarchitected = ["mypy-boto3-wellarchitected (>=1.18.47)"] +wisdom = ["mypy-boto3-wisdom (>=1.18.47)"] +workdocs = ["mypy-boto3-workdocs (>=1.18.47)"] +worklink = ["mypy-boto3-worklink (>=1.18.47)"] +workmail = ["mypy-boto3-workmail (>=1.18.47)"] +workmailmessageflow = ["mypy-boto3-workmailmessageflow (>=1.18.47)"] +workspaces = ["mypy-boto3-workspaces (>=1.18.47)"] +xray = ["mypy-boto3-xray (>=1.18.47)"] [[package]] -category = "main" -description = "Low-level, data-driven core of boto 3." name = "botocore" +version = "1.21.53" +description = "Low-level, data-driven core of boto 3." +category = "main" optional = false -python-versions = "*" -version = "1.17.22" +python-versions = ">= 3.6" [package.dependencies] -docutils = ">=0.10,<0.16" jmespath = ">=0.7.1,<1.0.0" python-dateutil = ">=2.1,<3.0.0" +urllib3 = ">=1.25.4,<1.27" -[package.dependencies.urllib3] -python = "<3.4.0 || >=3.5.0" -version = ">=1.20,<1.26" +[package.extras] +crt = ["awscrt (==0.11.24)"] [[package]] -category = "dev" -description = "Composable command line interface toolkit" -name = "click" +name = "botocore-stubs" +version = "1.21.52" +description = "Type annotations for botocore 1.21.52, generated by mypy-boto3-builder 5.5.0" +category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "7.1.2" +python-versions = ">=3.6" + +[package.dependencies] +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] -category = "main" -description = "Docutils -- Python Documentation Utilities" -name = "docutils" +name = "click" +version = "8.0.1" +description = "Composable command line interface toolkit" +category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.15.2" +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." category = "dev" -description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] name = "flake8" +version = "3.9.2" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "3.8.3" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.6.0a1,<2.7.0" -pyflakes = ">=2.2.0,<2.3.0" - -[package.dependencies.importlib-metadata] -python = "<3.8" -version = "*" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" [[package]] -category = "main" -description = "Read metadata from Python packages" -marker = "python_version < \"3.8\"" name = "importlib-metadata" +version = "4.8.1" +description = "Read metadata from Python packages" +category = "main" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.7.0" +python-versions = ">=3.6" [package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "rst.linker"] -testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] -category = "main" -description = "JSON Matching Expressions" name = "jmespath" +version = "0.10.0" +description = "JSON Matching Expressions" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.10.0" [[package]] -category = "dev" -description = "McCabe checker, plugin for flake8" name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = "*" -version = "0.6.1" [[package]] -category = "dev" -description = "Optional static typing for Python" name = "mypy" +version = "0.770" +description = "Optional static typing for Python" +category = "dev" optional = false python-versions = ">=3.5" -version = "0.770" [package.dependencies] mypy-extensions = ">=0.4.3,<0.5.0" @@ -418,273 +478,256 @@ typing-extensions = ">=3.7.4" dmypy = ["psutil (>=4.0)"] [[package]] -category = "dev" -description = "Type annotations for boto3 1.14.21 master module, generated by mypy-boto3-buider 2.2.0" -name = "mypy-boto3" -optional = false -python-versions = ">=3.6" -version = "1.14.21.0" - -[package.dependencies] -boto3 = "*" - -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" - -[[package]] -category = "dev" -description = "Type annotations for boto3.EC2 1.14.21 service, generated by mypy-boto3-buider 2.2.0" name = "mypy-boto3-ec2" +version = "1.18.52" +description = "Type annotations for boto3.EC2 1.18.52 service, generated by mypy-boto3-builder 5.5.0" +category = "main" optional = false python-versions = ">=3.6" -version = "1.14.21.0" [package.dependencies] -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] -category = "dev" -description = "Type annotations for boto3.EFS 1.14.21 service, generated by mypy-boto3-buider 2.2.0" name = "mypy-boto3-efs" +version = "1.18.52" +description = "Type annotations for boto3.EFS 1.18.52 service, generated by mypy-boto3-builder 5.5.0" +category = "main" optional = false python-versions = ">=3.6" -version = "1.14.21.0" [package.dependencies] -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] -category = "dev" -description = "Type annotations for boto3.RDS 1.14.21 service, generated by mypy-boto3-buider 2.2.0" name = "mypy-boto3-rds" +version = "1.18.52" +description = "Type annotations for boto3.RDS 1.18.52 service, generated by mypy-boto3-builder 5.5.0" +category = "main" optional = false python-versions = ">=3.6" -version = "1.14.21.0" [package.dependencies] -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] -category = "dev" -description = "Type annotations for boto3.SQS 1.14.21 service, generated by mypy-boto3-buider 2.2.0" name = "mypy-boto3-sqs" +version = "1.18.52" +description = "Type annotations for boto3.SQS 1.18.52 service, generated by mypy-boto3-builder 5.5.0" +category = "main" optional = false python-versions = ">=3.6" -version = "1.14.21.0" [package.dependencies] -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] -category = "dev" -description = "Experimental type system extensions for programs checked with the mypy typechecker." name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" optional = false python-versions = "*" -version = "0.4.3" [[package]] -category = "main" -description = "" name = "nixops" +version = "2.0.0" +description = "NixOS cloud provisioning and deployment tool" +category = "main" optional = false python-versions = "^3.7" -version = "2.0.0" +develop = false [package.dependencies] -PrettyTable = "^0.7.2" pluggy = "^0.13.1" +PrettyTable = "^0.7.2" typeguard = "^2.7.1" typing-extensions = "^3.7.4" [package.source] -reference = "0330ead36be75c0b0f80cf84c227f13380daf414" type = "git" url = "https://github.com/NixOS/nixops.git" +reference = "master" +resolved_reference = "35ac02085169bc2372834d6be6cf4c1bdf820d09" + [[package]] -category = "main" -description = "" name = "nixos-modules-contrib" +version = "0.1.0" +description = "NixOS modules that don't quite belong in NixOS." +category = "main" optional = false python-versions = "^3.7" -version = "0.1.0" +develop = false [package.dependencies] nixops = "rev master" [package.source] -reference = "6e4d21f47f0c40023a56a9861886bde146476198" type = "git" url = "https://github.com/nix-community/nixos-modules-contrib.git" +reference = "master" +resolved_reference = "81a1c2ef424dcf596a97b2e46a58ca73a1dd1ff8" + [[package]] -category = "dev" -description = "nose extends unittest to make testing easier" name = "nose" +version = "1.3.7" +description = "nose extends unittest to make testing easier" +category = "dev" optional = false python-versions = "*" -version = "1.3.7" [[package]] -category = "dev" -description = "Utility library for gitignore style pattern matching of file paths." name = "pathspec" +version = "0.9.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.8.0" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] -category = "main" -description = "plugin and hook calling mechanisms for python" name = "pluggy" +version = "0.13.1" +description = "plugin and hook calling mechanisms for python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.13.1" [package.dependencies] -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] [[package]] -category = "main" -description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format." name = "prettytable" +version = "0.7.2" +description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format." +category = "main" optional = false python-versions = "*" -version = "0.7.2" [[package]] -category = "dev" -description = "Python style guide checker" name = "pycodestyle" +version = "2.7.0" +description = "Python style guide checker" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.6.0" [[package]] -category = "dev" -description = "passive checker of Python programs" name = "pyflakes" +version = "2.3.1" +description = "passive checker of Python programs" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.2.0" [[package]] -category = "main" -description = "Extensions to the standard Python datetime module" name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -version = "2.8.1" [package.dependencies] six = ">=1.5" [[package]] -category = "dev" -description = "Alternative regular expression module, to replace re." name = "regex" +version = "2021.9.30" +description = "Alternative regular expression module, to replace re." +category = "dev" optional = false python-versions = "*" -version = "2020.7.14" [[package]] -category = "main" -description = "An Amazon S3 Transfer Manager" name = "s3transfer" +version = "0.5.0" +description = "An Amazon S3 Transfer Manager" +category = "main" optional = false -python-versions = "*" -version = "0.3.3" +python-versions = ">= 3.6" [package.dependencies] botocore = ">=1.12.36,<2.0a.0" +[package.extras] +crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] + [[package]] -category = "main" -description = "Python 2 and 3 compatibility utilities" name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.15.0" [[package]] -category = "dev" -description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" optional = false -python-versions = "*" -version = "0.10.1" +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] -category = "dev" -description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" +version = "1.4.3" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" optional = false python-versions = "*" -version = "1.4.1" [[package]] -category = "main" -description = "Run-time type checker for Python" name = "typeguard" +version = "2.12.1" +description = "Run-time type checker for Python" +category = "main" optional = false python-versions = ">=3.5.3" -version = "2.9.1" [package.extras] doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] -test = ["pytest", "typing-extensions"] +test = ["pytest", "typing-extensions", "mypy"] [[package]] -category = "main" -description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "main" optional = false python-versions = "*" -version = "3.7.4.2" [[package]] -category = "main" -description = "HTTP library with thread-safe connection pooling, file post, and more." -marker = "python_version != \"3.4\"" name = "urllib3" +version = "1.26.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.9" [package.extras] brotli = ["brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] -category = "main" -description = "Backport of pathlib-compatible object wrapper for zip files" -marker = "python_version < \"3.8\"" name = "zipp" +version = "3.6.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" optional = false python-versions = ">=3.6" -version = "3.1.0" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["jaraco.itertools", "func-timeout"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -content-hash = "a847e7d626b25500cb00e55812ad1198651dd648629979a68de37fea43913842" +lock-version = "1.1" python-versions = "^3.7" +content-hash = "9cd11f8e64bda8543acdf84bddd12c89a7473391fe6dfba48ecf7a45e1e07b1d" [metadata.files] appdirs = [ @@ -692,8 +735,8 @@ appdirs = [ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] attrs = [ - {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, - {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] black = [ {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, @@ -704,33 +747,36 @@ boto = [ {file = "boto-2.49.0.tar.gz", hash = "sha256:ea0d3b40a2d852767be77ca343b58a9e3a4b00d9db440efb8da74b4e58025e5a"}, ] boto3 = [ - {file = "boto3-1.14.22-py2.py3-none-any.whl", hash = "sha256:0272d3e76010ce3452cac8b1d23786533a9526da9c211540df0b712e2040027e"}, - {file = "boto3-1.14.22.tar.gz", hash = "sha256:07bd0872e9178b637baefb82aff8abb76197770c9fc60c4d6575564ba878e3e4"}, + {file = "boto3-1.18.53-py3-none-any.whl", hash = "sha256:9dea5a820282bcd752bba118e38e44d683024e7cd8792ea89e72e3df7c61978e"}, + {file = "boto3-1.18.53.tar.gz", hash = "sha256:4c20f183b680f6b02f70fb32b03df8b52ab9e0fc7a48dc309c159babaf5c9497"}, ] boto3-stubs = [ - {file = "boto3-stubs-1.14.21.0.tar.gz", hash = "sha256:b99b44f46e9c7447c14a4865eee0aa6ead1f38a725b94301cb1062fc7bd6ae62"}, - {file = "boto3_stubs-1.14.21.0-py3-none-any.whl", hash = "sha256:2c70e617b39aba7c5ab5aa4774d6f7a1ff15e72225f3d2f173803b604cc36d25"}, + {file = "boto3-stubs-1.18.52.tar.gz", hash = "sha256:60f54146d506e71c8a3bf52d4bda7e38f9a387c34bc20cb8a03abe8ceea293c6"}, + {file = "boto3_stubs-1.18.52-py3-none-any.whl", hash = "sha256:a30138e087903a4a52e322d4236ddda0c296a3d2e53173b1551a30e6d85a9ba9"}, ] botocore = [ - {file = "botocore-1.17.22-py2.py3-none-any.whl", hash = "sha256:f491d3c29d7dda8c8907c520bc96d77a67a8953dfed7f55c250799849e213640"}, - {file = "botocore-1.17.22.tar.gz", hash = "sha256:4d084dfcfcdf21ac2df17d017607ca53d53ac6c2fa17484cdd87ef78daba06b8"}, + {file = "botocore-1.21.53-py3-none-any.whl", hash = "sha256:09f82a17a352f8b694ac6542eae34fe39169b049c4ca55e17040a0796b8f399b"}, + {file = "botocore-1.21.53.tar.gz", hash = "sha256:650604ca5231b819d64430c6b2d1748646bab1095a02fb81bad99cd59f6f6cf5"}, +] +botocore-stubs = [ + {file = "botocore-stubs-1.21.52.tar.gz", hash = "sha256:ff8b9121f24034e3cc31381c233674a695a69b76bdad4eac1a3debabaadf8bca"}, + {file = "botocore_stubs-1.21.52-py3-none-any.whl", hash = "sha256:9e97224b8b3db0c12027a0f9ffa5e4ea2bc959a1b4c344fc1e96f7dac81b5784"}, ] click = [ - {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, - {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, + {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, + {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, ] -docutils = [ - {file = "docutils-0.15.2-py2-none-any.whl", hash = "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827"}, - {file = "docutils-0.15.2-py3-none-any.whl", hash = "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0"}, - {file = "docutils-0.15.2.tar.gz", hash = "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"}, +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] flake8 = [ - {file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"}, - {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, + {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, + {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, - {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, + {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, + {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, ] jmespath = [ {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, @@ -756,25 +802,21 @@ mypy = [ {file = "mypy-0.770-py3-none-any.whl", hash = "sha256:3b1fc683fb204c6b4403a1ef23f0b1fac8e4477091585e0c8c54cbdf7d7bb164"}, {file = "mypy-0.770.tar.gz", hash = "sha256:8a627507ef9b307b46a1fea9513d5c98680ba09591253082b4c48697ba05a4ae"}, ] -mypy-boto3 = [ - {file = "mypy-boto3-1.14.21.0.tar.gz", hash = "sha256:f05d150c53ab0c5eec108e464771c37bdc2c3d94fd1652cc56c5a63d069066a9"}, - {file = "mypy_boto3-1.14.21.0-py3-none-any.whl", hash = "sha256:6595bbde24b728624b3a5d00b6fa34353a267276e1d980b1158ec7b5a0f37bd6"}, -] mypy-boto3-ec2 = [ - {file = "mypy-boto3-ec2-1.14.21.0.tar.gz", hash = "sha256:a27240f8e8ec62557ead18c45938d15874028adf9cf7d3ddb8e5afcd55d95064"}, - {file = "mypy_boto3_ec2-1.14.21.0-py3-none-any.whl", hash = "sha256:599a4e4c8c634839e947d9c39109dd3fec059a3f32933e73402bc43f6de153a8"}, + {file = "mypy-boto3-ec2-1.18.52.tar.gz", hash = "sha256:d048bf7946ff62c9c0e768f8424da67aaf1fa3e1f8f05b64fc0bf17647c6b5ce"}, + {file = "mypy_boto3_ec2-1.18.52-py3-none-any.whl", hash = "sha256:e83cd9886a9b487e146baae7b2777625818893ccd08e94b37a407d491c97cdee"}, ] mypy-boto3-efs = [ - {file = "mypy-boto3-efs-1.14.21.0.tar.gz", hash = "sha256:6c3b32dc6b4efffb8e1f85acdb627269649d08fd51c921420d30e931faddc5e1"}, - {file = "mypy_boto3_efs-1.14.21.0-py3-none-any.whl", hash = "sha256:a6dae9753dde06fe9716d0fecbd8102e4e33b8595cc114c4fc18a8822a4e6e25"}, + {file = "mypy-boto3-efs-1.18.52.tar.gz", hash = "sha256:c775b1c914c4bafb1050afdf44e529bfca77aa24065cee7285ca00dd0806f1b4"}, + {file = "mypy_boto3_efs-1.18.52-py3-none-any.whl", hash = "sha256:5a2bcf16e503fb707796fa6c0b3684ed50fbc60815b6f54c42cd80b2c6bddc46"}, ] mypy-boto3-rds = [ - {file = "mypy-boto3-rds-1.14.21.0.tar.gz", hash = "sha256:18be963910b04df544acd709ab46b726960086c7a25b474d520c6c6bc43f8db9"}, - {file = "mypy_boto3_rds-1.14.21.0-py3-none-any.whl", hash = "sha256:6ac2abb211ba7aef14cf6b8409b65af013a82f3b549e0ea65484ff09a4180972"}, + {file = "mypy-boto3-rds-1.18.52.tar.gz", hash = "sha256:530dfb7e03dc2e61894656ba4f4c174285b7bc40af1748efedda5338e850987c"}, + {file = "mypy_boto3_rds-1.18.52-py3-none-any.whl", hash = "sha256:d265ce323ea83a01ed3033aa7eccc50edf05d5927b4c3ffffc596686b2d2f18a"}, ] mypy-boto3-sqs = [ - {file = "mypy-boto3-sqs-1.14.21.0.tar.gz", hash = "sha256:3d818f050e913b87744b0bfc892b96594822a041beb8c1d8331c1f0be56a1c25"}, - {file = "mypy_boto3_sqs-1.14.21.0-py3-none-any.whl", hash = "sha256:402162fc22f1d1947991c9c5bf673b4001b1e9e91850a62bda2249316c4b3b85"}, + {file = "mypy-boto3-sqs-1.18.52.tar.gz", hash = "sha256:65e67465d1f0a4c39204da1c446d898ca9c2011b1bd449c9e95c02a6ef51bd2f"}, + {file = "mypy_boto3_sqs-1.18.52-py3-none-any.whl", hash = "sha256:23b0f9009e21e21b44718b27a3649075a10af785c6e2d5c83cb14b1503cc4633"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -788,8 +830,8 @@ nose = [ {file = "nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"}, ] pathspec = [ - {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, - {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, ] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, @@ -801,89 +843,118 @@ prettytable = [ {file = "prettytable-0.7.2.zip", hash = "sha256:a53da3b43d7a5c229b5e3ca2892ef982c46b7923b51e98f0db49956531211c4f"}, ] pycodestyle = [ - {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, - {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, ] pyflakes = [ - {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, - {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, + {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, + {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] python-dateutil = [ - {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, - {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] regex = [ - {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, - {file = "regex-2020.7.14-cp27-cp27m-win_amd64.whl", hash = "sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644"}, - {file = "regex-2020.7.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c50a724d136ec10d920661f1442e4a8b010a4fe5aebd65e0c2241ea41dbe93dc"}, - {file = "regex-2020.7.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8a51f2c6d1f884e98846a0a9021ff6861bdb98457879f412fdc2b42d14494067"}, - {file = "regex-2020.7.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9c568495e35599625f7b999774e29e8d6b01a6fb684d77dee1f56d41b11b40cd"}, - {file = "regex-2020.7.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:51178c738d559a2d1071ce0b0f56e57eb315bcf8f7d4cf127674b533e3101f88"}, - {file = "regex-2020.7.14-cp36-cp36m-win32.whl", hash = "sha256:9eddaafb3c48e0900690c1727fba226c4804b8e6127ea409689c3bb492d06de4"}, - {file = "regex-2020.7.14-cp36-cp36m-win_amd64.whl", hash = "sha256:14a53646369157baa0499513f96091eb70382eb50b2c82393d17d7ec81b7b85f"}, - {file = "regex-2020.7.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1269fef3167bb52631ad4fa7dd27bf635d5a0790b8e6222065d42e91bede4162"}, - {file = "regex-2020.7.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d0a5095d52b90ff38592bbdc2644f17c6d495762edf47d876049cfd2968fbccf"}, - {file = "regex-2020.7.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4c037fd14c5f4e308b8370b447b469ca10e69427966527edcab07f52d88388f7"}, - {file = "regex-2020.7.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bc3d98f621898b4a9bc7fecc00513eec8f40b5b83913d74ccb445f037d58cd89"}, - {file = "regex-2020.7.14-cp37-cp37m-win32.whl", hash = "sha256:46bac5ca10fb748d6c55843a931855e2727a7a22584f302dd9bb1506e69f83f6"}, - {file = "regex-2020.7.14-cp37-cp37m-win_amd64.whl", hash = "sha256:0dc64ee3f33cd7899f79a8d788abfbec168410be356ed9bd30bbd3f0a23a7204"}, - {file = "regex-2020.7.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5ea81ea3dbd6767873c611687141ec7b06ed8bab43f68fad5b7be184a920dc99"}, - {file = "regex-2020.7.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bbb332d45b32df41200380fff14712cb6093b61bd142272a10b16778c418e98e"}, - {file = "regex-2020.7.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c11d6033115dc4887c456565303f540c44197f4fc1a2bfb192224a301534888e"}, - {file = "regex-2020.7.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:75aaa27aa521a182824d89e5ab0a1d16ca207318a6b65042b046053cfc8ed07a"}, - {file = "regex-2020.7.14-cp38-cp38-win32.whl", hash = "sha256:d6cff2276e502b86a25fd10c2a96973fdb45c7a977dca2138d661417f3728341"}, - {file = "regex-2020.7.14-cp38-cp38-win_amd64.whl", hash = "sha256:7a2dd66d2d4df34fa82c9dc85657c5e019b87932019947faece7983f2089a840"}, - {file = "regex-2020.7.14.tar.gz", hash = "sha256:3a3af27a8d23143c49a3420efe5b3f8cf1a48c6fc8bc6856b03f638abc1833bb"}, + {file = "regex-2021.9.30-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:66696c8336a1b5d1182464f3af3427cc760118f26d0b09a2ddc16a976a4d2637"}, + {file = "regex-2021.9.30-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d87459ad3ab40cd8493774f8a454b2e490d8e729e7e402a0625867a983e4e02"}, + {file = "regex-2021.9.30-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78cf6a1e023caf5e9a982f5377414e1aeac55198831b852835732cfd0a0ca5ff"}, + {file = "regex-2021.9.30-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:255791523f80ea8e48e79af7120b4697ef3b74f6886995dcdb08c41f8e516be0"}, + {file = "regex-2021.9.30-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e502f8d4e5ef714bcc2c94d499684890c94239526d61fdf1096547db91ca6aa6"}, + {file = "regex-2021.9.30-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4907fb0f9b9309a5bded72343e675a252c2589a41871874feace9a05a540241e"}, + {file = "regex-2021.9.30-cp310-cp310-win32.whl", hash = "sha256:3be40f720af170a6b20ddd2ad7904c58b13d2b56f6734ee5d09bbdeed2fa4816"}, + {file = "regex-2021.9.30-cp310-cp310-win_amd64.whl", hash = "sha256:c2b180ed30856dfa70cfe927b0fd38e6b68198a03039abdbeb1f2029758d87e7"}, + {file = "regex-2021.9.30-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6f2d2f93001801296fe3ca86515eb04915472b5380d4d8752f09f25f0b9b0ed"}, + {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fa7ba9ab2eba7284e0d7d94f61df7af86015b0398e123331362270d71fab0b9"}, + {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28040e89a04b60d579c69095c509a4f6a1a5379cd865258e3a186b7105de72c6"}, + {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f588209d3e4797882cd238195c175290dbc501973b10a581086b5c6bcd095ffb"}, + {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42952d325439ef223e4e9db7ee6d9087b5c68c5c15b1f9de68e990837682fc7b"}, + {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cae4099031d80703954c39680323dabd87a69b21262303160776aa0e55970ca0"}, + {file = "regex-2021.9.30-cp36-cp36m-win32.whl", hash = "sha256:0de8ad66b08c3e673b61981b9e3626f8784d5564f8c3928e2ad408c0eb5ac38c"}, + {file = "regex-2021.9.30-cp36-cp36m-win_amd64.whl", hash = "sha256:b345ecde37c86dd7084c62954468a4a655fd2d24fd9b237949dd07a4d0dd6f4c"}, + {file = "regex-2021.9.30-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6f08187136f11e430638c2c66e1db091105d7c2e9902489f0dbc69b44c222b4"}, + {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b55442650f541d195a535ccec33078c78a9521973fb960923da7515e9ed78fa6"}, + {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87e9c489aa98f50f367fb26cc9c8908d668e9228d327644d7aa568d47e456f47"}, + {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2cb7d4909ed16ed35729d38af585673f1f0833e73dfdf0c18e5be0061107b99"}, + {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0861e7f6325e821d5c40514c551fd538b292f8cc3960086e73491b9c5d8291d"}, + {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:81fdc90f999b2147fc62e303440c424c47e5573a9b615ed5d43a5b832efcca9e"}, + {file = "regex-2021.9.30-cp37-cp37m-win32.whl", hash = "sha256:8c1ad61fa024195136a6b7b89538030bd00df15f90ac177ca278df9b2386c96f"}, + {file = "regex-2021.9.30-cp37-cp37m-win_amd64.whl", hash = "sha256:e3770781353a4886b68ef10cec31c1f61e8e3a0be5f213c2bb15a86efd999bc4"}, + {file = "regex-2021.9.30-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9c065d95a514a06b92a5026766d72ac91bfabf581adb5b29bc5c91d4b3ee9b83"}, + {file = "regex-2021.9.30-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9925985be05d54b3d25fd6c1ea8e50ff1f7c2744c75bdc4d3b45c790afa2bcb3"}, + {file = "regex-2021.9.30-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470f2c882f2672d8eeda8ab27992aec277c067d280b52541357e1acd7e606dae"}, + {file = "regex-2021.9.30-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ad0517df22a97f1da20d8f1c8cb71a5d1997fa383326b81f9cf22c9dadfbdf34"}, + {file = "regex-2021.9.30-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e30838df7bfd20db6466fd309d9b580d32855f8e2c2e6d74cf9da27dcd9b63"}, + {file = "regex-2021.9.30-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b34d2335d6aedec7dcadd3f8283b9682fadad8b9b008da8788d2fce76125ebe"}, + {file = "regex-2021.9.30-cp38-cp38-win32.whl", hash = "sha256:e07049cece3462c626d650e8bf42ddbca3abf4aa08155002c28cb6d9a5a281e2"}, + {file = "regex-2021.9.30-cp38-cp38-win_amd64.whl", hash = "sha256:37868075eda024470bd0feab872c692ac4ee29db1e14baec103257bf6cc64346"}, + {file = "regex-2021.9.30-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d331f238a7accfbbe1c4cd1ba610d4c087b206353539331e32a8f05345c74aec"}, + {file = "regex-2021.9.30-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6348a7ab2a502cbdd0b7fd0496d614007489adb7361956b38044d1d588e66e04"}, + {file = "regex-2021.9.30-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b1cca6c23f19bee8dc40228d9c314d86d1e51996b86f924aca302fc8f8bf9"}, + {file = "regex-2021.9.30-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1f1125bc5172ab3a049bc6f4b9c0aae95a2a2001a77e6d6e4239fa3653e202b5"}, + {file = "regex-2021.9.30-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:638e98d069b14113e8afba6a54d1ca123f712c0d105e67c1f9211b2a825ef926"}, + {file = "regex-2021.9.30-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a0b0db6b49da7fa37ca8eddf9f40a8dbc599bad43e64f452284f37b6c34d91c"}, + {file = "regex-2021.9.30-cp39-cp39-win32.whl", hash = "sha256:9910869c472e5a6728680ca357b5846546cbbd2ab3ad5bef986ef0bc438d0aa6"}, + {file = "regex-2021.9.30-cp39-cp39-win_amd64.whl", hash = "sha256:3b71213ec3bad9a5a02e049f2ec86b3d7c3e350129ae0f4e2f99c12b5da919ed"}, + {file = "regex-2021.9.30.tar.gz", hash = "sha256:81e125d9ba54c34579e4539a967e976a3c56150796674aec318b1b2f49251be7"}, ] s3transfer = [ - {file = "s3transfer-0.3.3-py2.py3-none-any.whl", hash = "sha256:2482b4259524933a022d59da830f51bd746db62f047d6eb213f2f8855dcb8a13"}, - {file = "s3transfer-0.3.3.tar.gz", hash = "sha256:921a37e2aefc64145e7b73d50c71bb4f26f46e4c9f414dc648c6245ff92cf7db"}, + {file = "s3transfer-0.5.0-py3-none-any.whl", hash = "sha256:9c1dc369814391a6bda20ebbf4b70a0f34630592c9aa520856bf384916af2803"}, + {file = "s3transfer-0.5.0.tar.gz", hash = "sha256:50ed823e1dc5868ad40c8dc92072f757aa0e653a192845c94a3b676f4a62da4c"}, ] six = [ - {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, - {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] toml = [ - {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, - {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] typed-ast = [ - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, - {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, - {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, - {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, - {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, - {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, - {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, - {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, + {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, + {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, + {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, + {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, + {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, + {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, + {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, + {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, + {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typeguard = [ - {file = "typeguard-2.9.1-py3-none-any.whl", hash = "sha256:e258567e62d28f9a51d4f7c71f491154e9ef0889286ad2f37e3e22e4f668b21b"}, - {file = "typeguard-2.9.1.tar.gz", hash = "sha256:529ef3d88189cc457f4340388028412f71be8091c2c943465146d4170fb67288"}, + {file = "typeguard-2.12.1-py3-none-any.whl", hash = "sha256:cc15ef2704c9909ef9c80e19c62fb8468c01f75aad12f651922acf4dbe822e02"}, + {file = "typeguard-2.12.1.tar.gz", hash = "sha256:c2af8b9bdd7657f4bd27b45336e7930171aead796711bc4cfc99b4731bb9d051"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"}, - {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, - {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] urllib3 = [ - {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, - {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, ] zipp = [ - {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, - {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, + {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, + {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, ] diff --git a/pyproject.toml b/pyproject.toml index 10e1ae24..745aa056 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,8 @@ include = [ "nixops_aws/nix/*.nix" ] [tool.poetry.dependencies] python = "^3.7" boto = "^2.49.0" -boto3 = "^1.13.7" +boto3 = "^1.18.50" +boto3-stubs = {extras = ["ec2", "sqs", "efs", "rds"], version = "^1.18.50"} nixops = {git = "https://github.com/NixOS/nixops.git", rev = "master"} typing-extensions = "^3.7.4" nixos-modules-contrib = {git = "https://github.com/nix-community/nixos-modules-contrib.git", rev = "master"} @@ -19,7 +20,6 @@ nose = "^1.3.7" mypy = "^0.770" black = "^19.10b0" flake8 = "^3.8.2" -boto3-stubs = {extras = ["ec2", "sqs", "efs", "rds"], version = "^1.13.8"} [tool.poetry.plugins."nixops"] aws = "nixops_aws.plugin" diff --git a/tests.py b/tests.py index 3b2c9f43..15f671ba 100644 --- a/tests.py +++ b/tests.py @@ -3,7 +3,7 @@ if __name__ == "__main__": config = nose.config.Config(plugins=nose.plugins.manager.DefaultPluginManager()) - config.configure(argv=[sys.argv[0], "-e", "^coverage-tests\.py$"] + sys.argv[1:]) + config.configure(argv=[sys.argv[0], "-e", "^coverage-tests\\.py$"] + sys.argv[1:]) count = ( nose.loader.defaultTestLoader(config=config) .loadTestsFromNames(["."]) @@ -13,9 +13,9 @@ argv=[ sys.argv[0], "--process-timeout=inf", - "--processes=%d".format(count), + "--processes={}".format(count), "-e", - "^coverage-tests\.py$", + "^coverage-tests\\.py$", ] + sys.argv[1:] )