diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6a577519..eacdee6d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,40 +9,43 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.4 - name: Nix - uses: cachix/install-nix-action@v8 + uses: cachix/install-nix-action@v12 - name: Build - run: 'nix-build -I nixpkgs=channel:nixos-unstable --quiet release.nix -A nixops-aws.x86_64-linux --show-trace' - # Run black v19.10b0 and ensure no diff, using a pinned channel to ensure the - # build doesn't break when the version of black on the release channel - # upgrades. The specific commit is not special; just a commit from the - # nixpkgs-unstable channel that deterministically provides the Black v19.10b0, - # which as of this writing is the latest version. + run: 'nix-build -I nixpkgs=channel:nixos-20.09 --quiet release.nix -A nixops-aws.x86_64-linux --show-trace' + env: + NIX_PATH: "nixpkgs=channel:nixos-20.09" black: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.4 - name: Nix - uses: cachix/install-nix-action@v8 + uses: cachix/install-nix-action@v12 - name: Black run: 'nix-shell ./shell.nix --run "black --check ."' + env: + NIX_PATH: "nixpkgs=channel:nixos-20.09" flake8: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.4 - name: Nix - uses: cachix/install-nix-action@v8 + uses: cachix/install-nix-action@v12 - name: Flake8 run: 'nix-shell ./shell.nix --run "flake8 nixops_aws"' + env: + NIX_PATH: "nixpkgs=channel:nixos-20.09" mypy: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.4 - name: Nix - uses: cachix/install-nix-action@v8 + uses: cachix/install-nix-action@v12 - name: Mypy run: 'nix-shell ./shell.nix --run "mypy nixops_aws"' + env: + NIX_PATH: "nixpkgs=channel:nixos-20.09" diff --git a/examples/ec2-rds-vpc-dbinstance.nix b/examples/ec2-rds-vpc-dbinstance.nix new file mode 100644 index 00000000..d8538018 --- /dev/null +++ b/examples/ec2-rds-vpc-dbinstance.nix @@ -0,0 +1,50 @@ +{ + region ? "us-east-1" +, accessKeyId ? "AKIA..." +, vpcId ? "vpc-.." +, subnetId1 ? "subnet-.." +, subnetId2 ? "subnet-.." +, ... +}: +{ + network.description = "NixOps RDS Testing"; + + resources.ec2SecurityGroups.test-rds-sg = + { + inherit region accessKeyId; + vpcId = vpcId; + name = "nixops-sg"; + description = "testing vpc sg for rds"; + rules = [ + { + fromPort = 3306; + toPort = 3306; + sourceIp = "0.0.0.0/0"; + } + ]; + }; + + resources.rdsSubnetGroups.test-rds-subnet-group = + { + inherit region accessKeyId; + subnetIds = [ subnetId1 subnetId2 ]; + }; + + resources.rdsDbInstances.test-rds-vpc-instance = + { resources, ... }: + { + inherit region accessKeyId; + id = "test-rds-vpc"; + instanceClass = "db.m3.large"; + snapshot = "test-rds-vpc-final-snapshot-372cd7f1ecbe4bb7a59e3026a15d7535"; + allocatedStorage = 30; + masterUsername = "administrator"; + masterPassword = "testing123"; + port = 3306; + engine = "mysql"; + dbName = "testNixOps"; + multiAZ = true; + subnetGroup = resources.rdsSubnetGroups.test-rds-subnet-group; + vpcSecurityGroups = [ resources.ec2SecurityGroups.test-rds-sg ]; + }; +} diff --git a/nixops_aws/backends/options.py b/nixops_aws/backends/options.py index a1ed7607..6856edd0 100644 --- a/nixops_aws/backends/options.py +++ b/nixops_aws/backends/options.py @@ -30,7 +30,8 @@ class DiskOptions(ResourceOptions): deleteOnTermination: bool encrypt: bool encryptionType: Union[ - Literal["luks"], Literal["ebs"], + Literal["luks"], + Literal["ebs"], ] cipher: str keySize: int diff --git a/nixops_aws/ec2_utils.py b/nixops_aws/ec2_utils.py index 294f4133..88f03a2d 100644 --- a/nixops_aws/ec2_utils.py +++ b/nixops_aws/ec2_utils.py @@ -20,8 +20,8 @@ def fetch_aws_secret_key(access_key_id) -> Tuple[str, str]: """ - Fetch the secret access key corresponding to the given access key ID from ~/.ec2-keys, - or from ~/.aws/credentials, or from the environment (in that priority). + Fetch the secret access key corresponding to the given access key ID from ~/.ec2-keys, + or from ~/.aws/credentials, or from the environment (in that priority). """ def parse_ec2_keys(): @@ -141,8 +141,8 @@ def retry( f, error_codes: Optional[Iterable[Any]] = None, logger=None, num_retries: int = 7 ): """ - Retry function f up to 7 times. If error_codes argument is empty list, retry on all EC2 response errors, - otherwise, only on the specified error codes. + Retry function f up to 7 times. If error_codes argument is empty list, retry on all EC2 response errors, + otherwise, only on the specified error codes. """ if error_codes is None: diff --git a/nixops_aws/nix/ec2-rds-dbinstance.nix b/nixops_aws/nix/ec2-rds-dbinstance.nix index 44a61765..348ac718 100644 --- a/nixops_aws/nix/ec2-rds-dbinstance.nix +++ b/nixops_aws/nix/ec2-rds-dbinstance.nix @@ -90,6 +90,15 @@ with import ./lib.nix lib; ''; }; + snapshot = mkOption { + default = null; + type = types.nullOr types.str; + example = "rds:super-database-2020-11-23-03-47"; + description = '' + A DB snapshot name from which the RDS DB will be restored + ''; + }; + securityGroups = mkOption { default = [ "default" ]; type = types.listOf (types.either types.str (resource "ec2-rds-security-group")); diff --git a/nixops_aws/resources/cloudwatch_log_group.py b/nixops_aws/resources/cloudwatch_log_group.py index 76779d44..cb24c4e0 100644 --- a/nixops_aws/resources/cloudwatch_log_group.py +++ b/nixops_aws/resources/cloudwatch_log_group.py @@ -115,7 +115,8 @@ def lookup_cloudwatch_log_group(self, log_group_name, next_token=None): return True, log["arn"] if "nextToken" in response: self.lookup_cloudwatch_log_group( - log_group_name=log_group_name, next_token=response["nextToken"], + log_group_name=log_group_name, + next_token=response["nextToken"], ) return False, None diff --git a/nixops_aws/resources/ec2_rds_dbinstance.py b/nixops_aws/resources/ec2_rds_dbinstance.py index 1c364d69..41a6e0ee 100644 --- a/nixops_aws/resources/ec2_rds_dbinstance.py +++ b/nixops_aws/resources/ec2_rds_dbinstance.py @@ -2,7 +2,6 @@ # Automatic provisioning of AWS RDS Database Instances. -import boto.rds import nixops.resources import nixops.util import nixops_aws.ec2_utils @@ -13,9 +12,12 @@ from .ec2_security_group import EC2SecurityGroupState from .rds_db_subnet_group import RDSDbSubnetGroupState from .types.ec2_rds_dbinstance import Ec2RdsDbinstanceOptions -from typing import Optional, Sequence +from typing import Optional, Sequence, TYPE_CHECKING from typing_extensions import TypedDict +if TYPE_CHECKING: + import mypy_boto3_rds + class VpcOptions(TypedDict): db_subnet_group_name: Optional[str] @@ -28,8 +30,8 @@ class EC2RDSDbInstanceDefinition(nixops.resources.ResourceDefinition): config: Ec2RdsDbinstanceOptions subnet_group: Optional[str] - vpc_security_groups: Optional[Sequence[str]] = None - rds_dbinstance_security_groups: Optional[Sequence[str]] = None + vpc_security_groups: Optional[Sequence[str]] = [] + rds_dbinstance_security_groups: Optional[Sequence[str]] = [] @classmethod def get_type(cls): @@ -52,6 +54,7 @@ def __init__(self, name: str, config: nixops.resources.ResourceEval): self.rds_dbinstance_engine: str = self.config.engine self.rds_dbinstance_db_name: str = self.config.dbName self.rds_dbinstance_multi_az: bool = self.config.multiAZ + self.rds_dbinstance_snap: Optional[str] = self.config.snapshot self.subnet_group: Optional[str] = self.config.subnetGroup if self.subnet_group is not None: @@ -88,32 +91,27 @@ class EC2RDSDbInstanceState(nixops.resources.ResourceState[EC2RDSDbInstanceDefin definition_type = EC2RDSDbInstanceDefinition - _conn: Optional[boto.rds.RDSConnection] - region = nixops.util.attr_property("ec2.region", None) - access_key_id = nixops.util.attr_property("ec2.accessKeyId", None) - rds_dbinstance_id = nixops.util.attr_property("ec2.rdsDbInstanceID", None) + _conn: Optional["mypy_boto3_rds.RDSClient"] + region = nixops.util.attr_property("region", None) + access_key_id = nixops.util.attr_property("accessKeyId", None) + rds_dbinstance_id = nixops.util.attr_property("id", None) rds_dbinstance_allocated_storage = nixops.util.attr_property( - "ec2.rdsAllocatedStorage", None, int - ) - rds_dbinstance_instance_class = nixops.util.attr_property( - "ec2.rdsInstanceClass", None - ) - rds_dbinstance_master_username = nixops.util.attr_property( - "ec2.rdsMasterUsername", None + "allocatedStorage", None, int ) - rds_dbinstance_master_password = nixops.util.attr_property( - "ec2.rdsMasterPassword", None - ) - rds_dbinstance_port = nixops.util.attr_property("ec2.rdsPort", None, int) - rds_dbinstance_engine = nixops.util.attr_property("ec2.rdsEngine", None) - rds_dbinstance_db_name = nixops.util.attr_property("ec2.rdsDbName", None) - rds_dbinstance_endpoint = nixops.util.attr_property("ec2.rdsEndpoint", None) - rds_dbinstance_multi_az = nixops.util.attr_property("ec2.multiAZ", False) + rds_dbinstance_instance_class = nixops.util.attr_property("instanceClass", None) + rds_dbinstance_master_username = nixops.util.attr_property("masterUsername", None) + rds_dbinstance_master_password = nixops.util.attr_property("masterPassword", None) + rds_dbinstance_port = nixops.util.attr_property("port", None, int) + rds_dbinstance_engine = nixops.util.attr_property("engine", None) + rds_dbinstance_db_name = nixops.util.attr_property("dbName", None) + rds_dbinstance_endpoint = nixops.util.attr_property("endpoint", None) + rds_dbinstance_multi_az = nixops.util.attr_property("multiAZ", False) + rds_dbinstance_snap = nixops.util.attr_property("snapshot", None) subnet_group = nixops.util.attr_property("subnetGroup", None) rds_dbinstance_security_groups = nixops.util.attr_property( - "ec2.securityGroups", [], "json" + "securityGroups", [], "json" ) - vpc_security_groups = nixops.util.attr_property("ec2.vpcSecurityGroups", [], "json") + vpc_security_groups = nixops.util.attr_property("vpcSecurityGroups", [], "json") requires_reboot_attrs = ( "rds_dbinstance_id", @@ -157,16 +155,10 @@ def create_after(self, resources, defn: EC2RDSDbInstanceDefinition): ) } - def _connect(self) -> boto.rds.RDSConnection: - if self._conn is None: - ( - access_key_id, - secret_access_key, - ) = nixops_aws.ec2_utils.fetch_aws_secret_key(self.access_key_id) - self._conn = boto.rds.connect_to_region( - region_name=self.region, - aws_access_key_id=access_key_id, - aws_secret_access_key=secret_access_key, + def _connect(self) -> "mypy_boto3_rds.RDSClient": + if not self._conn: + self._conn = nixops_aws.ec2_utils.connect_rds_boto3( + region=self.region, access_key_id=self.access_key_id ) return self._conn @@ -177,7 +169,7 @@ def _assert_invariants(self, defn: EC2RDSDbInstanceDefinition): # NOTE: it is possible to change region, master_username, port, or db_name # by creating a snapshot of the database and recreating the instance, # then restoring the snapshot. Not sure if this is in the scope of what - # nixops intends to manager for the user, or if it violates the principle + # nixops intends to manage for the user, or if it violates the principle # of least surprise. diff = self._diff_defn(defn) @@ -205,13 +197,15 @@ def _assert_invariants(self, defn: EC2RDSDbInstanceDefinition): def _try_fetch_dbinstance(self, instance_id): dbinstance = None + rds_client = self._connect() try: - dbinstance = self._connect().get_all_dbinstances(instance_id=instance_id)[0] - except boto.exception.BotoServerError as bse: - if bse.error_code == "DBInstanceNotFound": - dbinstance = None - else: - raise + dbinstance = rds_client.describe_db_instances( + DBInstanceIdentifier=instance_id + )["DBInstances"][0] + except rds_client.exceptions.DBInstanceNotFoundFault: + dbinstance = None + except: + raise return dbinstance @@ -258,12 +252,12 @@ def _requires_reboot(self, defn: EC2RDSDbInstanceDefinition): diff = self._diff_defn(defn) return set(self.requires_reboot_attrs) & set(diff.keys()) - def _wait_for_dbinstance(self, dbinstance, state="available"): + def _wait_for_dbinstance(self, dbinstance_id, state="available"): self.log_start("waiting for database instance state=`{0}` ".format(state)) while True: - dbinstance.update() - self.log_continue("[{0}] ".format(dbinstance.status)) - if dbinstance.status not in { + dbinstance = self._try_fetch_dbinstance(dbinstance_id) + self.log_continue("[{0}] ".format(dbinstance["DBInstanceStatus"])) + if dbinstance["DBInstanceStatus"] not in { "creating", "backing-up", "available", @@ -272,39 +266,41 @@ def _wait_for_dbinstance(self, dbinstance, state="available"): }: raise Exception( "RDS database instance ‘{0}’ in an error state (state is ‘{1}’)".format( - dbinstance.id, dbinstance.status + dbinstance["DBInstanceIdentifier"], + dbinstance["DBInstanceStatus"], ) ) - if dbinstance.status == state: - break + if dbinstance["DBInstanceStatus"] == state: + return dbinstance time.sleep(6) def _copy_dbinstance_attrs( self, dbinstance, rds_security_groups, vpc_security_groups ): with self.depl._db: - self.rds_dbinstance_id = dbinstance.id - self.rds_dbinstance_allocated_storage = int(dbinstance.allocated_storage) - self.rds_dbinstance_instance_class = dbinstance.instance_class - self.rds_dbinstance_master_username = dbinstance.master_username - self.rds_dbinstance_engine = dbinstance.engine - self.rds_dbinstance_multi_az = dbinstance.multi_az - if dbinstance.subnet_group: - self.subnet_group = dbinstance.subnet_group.name - - self.rds_dbinstance_port = int(dbinstance.endpoint[1]) - self.rds_dbinstance_endpoint = "%s:%d" % dbinstance.endpoint + self.rds_dbinstance_id = dbinstance["DBInstanceIdentifier"] + self.rds_dbinstance_allocated_storage = int(dbinstance["AllocatedStorage"]) + self.rds_dbinstance_instance_class = dbinstance["DBInstanceClass"] + self.rds_dbinstance_master_username = dbinstance["MasterUsername"] + self.rds_dbinstance_engine = dbinstance["Engine"] + self.rds_dbinstance_multi_az = dbinstance["MultiAZ"] + if dbinstance["DBSubnetGroup"]: + self.subnet_group = dbinstance["DBSubnetGroup"]["DBSubnetGroupName"] + + if dbinstance["Endpoint"]: + self.rds_dbinstance_port = int(dbinstance["Endpoint"]["Port"]) + self.rds_dbinstance_endpoint = dbinstance["Endpoint"]["Address"] self.rds_dbinstance_security_groups = rds_security_groups self.vpc_security_groups = vpc_security_groups def _to_boto_kwargs(self, attrs): attr_to_kwarg = { - "rds_dbinstance_allocated_storage": "allocated_storage", - "rds_dbinstance_master_password": "master_password", - "rds_dbinstance_instance_class": "instance_class", - "rds_dbinstance_multi_az": "multi_az", - "rds_dbinstance_security_groups": "security_groups", - "vpc_security_groups": "vpc_security_groups", + "rds_dbinstance_allocated_storage": "AllocatedStorage", + "rds_dbinstance_master_password": "MasterUserPassword", + "rds_dbinstance_instance_class": "DBInstanceClass", + "rds_dbinstance_multi_az": "MultiAZ", + "rds_dbinstance_security_groups": "DBSecurityGroups", + "vpc_security_groups": "VpcSecurityGroupIds", } result = {attr_to_kwarg[attr]: attrs[attr] for attr in attrs.keys()} @@ -313,12 +309,12 @@ def _to_boto_kwargs(self, attrs): # they probably don't use the default security group -- # and it is incompatible with VPC security groups anyway. if ( - "vpc_security_groups" in result - and "security_groups" in result - and len(result["vpc_security_groups"]) > 0 - and tuple(result["security_groups"]) == ("default",) + "VpcSecurityGroupIds" in result + and "DBSecurityGroups" in result + and len(result["VpcSecurityGroupIds"]) > 0 + and tuple(result["DBSecurityGroups"]) == ("default",) ): - del result["security_groups"] + del result["DBSecurityGroups"] return result @@ -353,7 +349,9 @@ def fetch_vpc_security_group_resources( for sg in config: if sg.startswith("res-"): res: EC2SecurityGroupState = self.depl.get_typed_resource( - sg[4:].split(".")[0], "ec2-security-group", EC2SecurityGroupState, + sg[4:].split(".")[0], + "ec2-security-group", + EC2SecurityGroupState, ) security_groups.append(res.security_group_id) else: @@ -378,7 +376,6 @@ def create( self.region = defn.region # fetch our target instance identifier regardless to fail early if needed - self._connect() dbinstance = self._try_fetch_dbinstance(defn.rds_dbinstance_id) if self.state == self.UP: @@ -393,27 +390,33 @@ def create( dbinstance = self._try_fetch_dbinstance(self.rds_dbinstance_id) with self.depl._db: + dbinstance = self._try_fetch_dbinstance(defn.rds_dbinstance_id) if check or self.state == self.MISSING or self.state == self.UNKNOWN: if dbinstance and ( self.state == self.MISSING or self.state == self.UNKNOWN ): - if dbinstance.status == "deleting": + if dbinstance["DBInstanceStatus"] == "deleting": self.logger.log( "RDS instance `{0}` is being deleted, waiting...".format( - dbinstance.id + dbinstance["DBInstanceIdentifier"] ) ) while True: - if dbinstance.status == "deleting": + if dbinstance["DBInstanceStatus"] == "deleting": + dbinstance = self._try_fetch_dbinstance( + dbinstance["DBInstanceIdentifier"] + ) continue else: break - self.log_continue("[{0}] ".format(dbinstance.status)) + self.log_continue( + "[{0}] ".format(dbinstance["DBInstanceStatus"]) + ) time.sleep(6) self.logger.log( "RDS instance `{0}` is MISSING but already exists, synchronizing state".format( - dbinstance.id + dbinstance["DBInstanceIdentifier"] ) ) self.state = self.UP @@ -436,23 +439,64 @@ def create( defn.rds_dbinstance_id ) ) + rds_client = self._connect() + vpc_opts = self.get_vpc_options(defn) - # create a new dbinstance with desired config - dbinstance = self._connect().create_dbinstance( - defn.rds_dbinstance_id, - defn.rds_dbinstance_allocated_storage, - defn.rds_dbinstance_instance_class, - defn.rds_dbinstance_master_username, - defn.rds_dbinstance_master_password, - port=defn.rds_dbinstance_port, - engine=defn.rds_dbinstance_engine, - db_name=defn.rds_dbinstance_db_name, - multi_az=defn.rds_dbinstance_multi_az, - **self.get_vpc_options(defn), - ) + if defn.rds_dbinstance_snap: + self.logger.log( + "restoring from RDS DB snapshot ‘{0}’..".format( + defn.rds_dbinstance_snap + ) + ) + try: + dbinstance = ( + rds_client.restore_db_instance_from_db_snapshot( + DBInstanceIdentifier=defn.rds_dbinstance_id, + DBSnapshotIdentifier=defn.rds_dbinstance_snap, + DBInstanceClass=defn.rds_dbinstance_instance_class, + Port=defn.rds_dbinstance_port, + DBSubnetGroupName=vpc_opts["db_subnet_group_name"], + MultiAZ=defn.rds_dbinstance_multi_az, + Engine=defn.rds_dbinstance_engine, + )["DBInstance"] + ) + except rds_client.exceptions.DBSnapshotNotFoundFault: + self.logger.error( + "The RDS DB snapshot ‘{0}’ does not exist".format( + defn.rds_dbinstance_snap + ) + ) + raise + else: + # create a new dbinstance with desired config + dbinstance = rds_client.create_db_instance( + DBName=defn.rds_dbinstance_db_name, + DBInstanceIdentifier=defn.rds_dbinstance_id, + AllocatedStorage=defn.rds_dbinstance_allocated_storage, + DBInstanceClass=defn.rds_dbinstance_instance_class, + Engine=defn.rds_dbinstance_engine, + MasterUsername=defn.rds_dbinstance_master_username, + MasterUserPassword=defn.rds_dbinstance_master_password, + Port=defn.rds_dbinstance_port, + MultiAZ=defn.rds_dbinstance_multi_az, + DBSubnetGroupName=vpc_opts["db_subnet_group_name"], + VpcSecurityGroupIds=vpc_opts["vpc_security_groups"], + DBSecurityGroups=vpc_opts["security_groups"], + )["DBInstance"] self.state = self.STARTING - self._wait_for_dbinstance(dbinstance) + dbinstance = self._wait_for_dbinstance(defn.rds_dbinstance_id) + # VPC SG are not applied when we restore from snap + if defn.rds_dbinstance_snap and vpc_opts["vpc_security_groups"]: + self.logger.log( + "applying the vpc security groups on the DB created from snapshot" + ) + dbinstance = rds_client.modify_db_instance( + DBInstanceIdentifier=defn.rds_dbinstance_id, + VpcSecurityGroupIds=vpc_opts["vpc_security_groups"], + ApplyImmediately=True, + ) + dbinstance = self._wait_for_dbinstance(defn.rds_dbinstance_id) self.region = defn.region self.access_key_id = ( @@ -489,18 +533,26 @@ def create( diff = self._diff_defn(defn) boto_kwargs = self._to_boto_kwargs(diff) if not self._compare_instance_id(defn.rds_dbinstance_id): - boto_kwargs["new_instance_id"] = defn.rds_dbinstance_id - boto_kwargs["apply_immediately"] = True + boto_kwargs["DBInstanceIdentifier"] = defn.rds_dbinstance_id + else: + boto_kwargs["DBInstanceIdentifier"] = self.rds_dbinstance_id + boto_kwargs["ApplyImmediately"] = True # first check is for the unlikely event we attempt to modify the db during its maintenance window - self._wait_for_dbinstance(dbinstance) - dbinstance = dbinstance.modify(**boto_kwargs) + self._wait_for_dbinstance(defn.rds_dbinstance_id) + dbinstance = self._connect().modify_db_instance(**boto_kwargs)[ + "DBInstance" + ] # Ugly hack to prevent from waiting on state # 'modifying' on sg change as that looks like it's an # immediate change in RDS. if not (len(boto_kwargs) == 2 and "security_groups" in boto_kwargs): - self._wait_for_dbinstance(dbinstance, state="modifying") - self._wait_for_dbinstance(dbinstance) + dbinstance = self._wait_for_dbinstance( + dbinstance["DBInstanceIdentifier"], state="modifying" + ) + dbinstance = self._wait_for_dbinstance( + dbinstance["DBInstanceIdentifier"] + ) self._copy_dbinstance_attrs( dbinstance, defn.rds_dbinstance_security_groups, @@ -510,11 +562,11 @@ def create( def get_vpc_options(self, defn: EC2RDSDbInstanceDefinition) -> VpcOptions: opts: VpcOptions = { "db_subnet_group_name": None, - "vpc_security_groups": None, - "security_groups": None, + "vpc_security_groups": [], + "security_groups": [], } - if defn.subnet_group is not None: + if defn.subnet_group: if defn.subnet_group.startswith("res-"): opts["db_subnet_group_name"] = self.depl.get_typed_resource( defn.subnet_group[4:].split(".")[0], @@ -546,13 +598,12 @@ def destroy(self, wipe=False): ) ): return False - self._connect() dbinstance = None if self.rds_dbinstance_id: dbinstance = self._try_fetch_dbinstance(self.rds_dbinstance_id) - if dbinstance and dbinstance.status != "deleting": + if dbinstance and dbinstance["DBInstanceStatus"] != "deleting": self.logger.log( "deleting RDS instance `{0}'...".format(self.rds_dbinstance_id) ) @@ -561,16 +612,18 @@ def destroy(self, wipe=False): uuid4().hex, ) self.logger.log("saving final snapshot as %s" % final_snapshot_id) - self._connect().delete_dbinstance( - self.rds_dbinstance_id, final_snapshot_id=final_snapshot_id + self._connect().delete_db_instance( + DBInstanceIdentifier=self.rds_dbinstance_id, + FinalDBSnapshotIdentifier=final_snapshot_id, ) while True: - if dbinstance.status == "deleting": + if dbinstance["DBInstanceStatus"] == "deleting": + dbinstance = self._try_fetch_dbinstance(self.rds_dbinstance_id) continue else: break - self.log_continue("[{0}] ".format(dbinstance.status)) + self.log_continue("[{0}] ".format(dbinstance["DBInstanceStatus"])) time.sleep(6) else: diff --git a/nixops_aws/resources/rds_db_subnet_group.py b/nixops_aws/resources/rds_db_subnet_group.py index 5dbc3e02..6cf96d26 100644 --- a/nixops_aws/resources/rds_db_subnet_group.py +++ b/nixops_aws/resources/rds_db_subnet_group.py @@ -26,6 +26,20 @@ def get_type(cls): def get_resource_type(cls): return "rdsSubnetGroups" + def __init__(self, name: str, config: nixops.resources.ResourceEval): + super(RDSDbSubnetGroupDefinition, self).__init__(name, config) + + self.group_name: str = self.config.name + self.description: Optional[str] = self.config.description + self.subnet_ids: List[str] = self.config.subnetIds + + # common params + self.region: str = self.config.region + self.access_key_id: str = self.config.accessKeyId + + def show_type(self): + return "{0} [{1}]".format(self.get_type(), self.region) + class RDSDbSubnetGroupState(nixops.resources.ResourceState[RDSDbSubnetGroupDefinition]): """State of an EC2 security group.""" @@ -35,8 +49,8 @@ class RDSDbSubnetGroupState(nixops.resources.ResourceState[RDSDbSubnetGroupDefin region = nixops.util.attr_property("region", None) description = nixops.util.attr_property("description", None) subnet_ids = nixops.util.attr_property("subnet_ids", [], "json") + access_key_id = nixops.util.attr_property("accessKeyId", None) - access_key_id: Optional[str] = None _rds_conn: Optional["mypy_boto3_rds.RDSClient"] = None @classmethod @@ -51,12 +65,11 @@ def create_after(self, resources, defn): return {r for r in resources if isinstance(r, VPCSubnetState)} def _connect_rds(self) -> "mypy_boto3_rds.RDSClient": - if self._rds_conn: - return self._rds_conn - self._conn = nixops_aws.ec2_utils.connect_rds_boto3( - self.region, self.access_key_id - ) - return self._conn + if not self._rds_conn: + self._rds_conn = nixops_aws.ec2_utils.connect_rds_boto3( + self.region, self.access_key_id + ) + return self._rds_conn def create( self, @@ -67,7 +80,7 @@ def create( ): self.region = defn.config.region self.access_key_id = ( - defn.config.accessKeyId or nixops_aws.ec2_utils.get_access_key_id() + defn.access_key_id or nixops_aws.ec2_utils.get_access_key_id() ) if not self.access_key_id: @@ -95,16 +108,24 @@ def create( else: subnets.append(s) + rds_client = self._connect_rds() if self.state != self.UP: - self.logger.log(f"Creating RDS Subnet Group {self.group_name}") - self._connect_rds().create_db_subnet_group( - DBSubnetGroupName=self.group_name, - DBSubnetGroupDescription=self.description, - SubnetIds=subnets, - ) + self.logger.log("creating RDS Subnet Group ‘{0}’..".format(self.group_name)) + try: + + rds_client.create_db_subnet_group( + DBSubnetGroupName=self.group_name, + DBSubnetGroupDescription=self.description, + SubnetIds=subnets, + ) + except rds_client.exceptions.DBSubnetGroupAlreadyExistsFault: + self.logger.error( + "The DB subnet group ‘{0}’ already exists.".format(self.group_name) + ) + raise self.state = self.UP else: - self._connect_rds().modify_db_subnet_group( + rds_client.modify_db_subnet_group( DBSubnetGroupName=self.group_name, DBSubnetGroupDescription=self.description, SubnetIds=subnets, @@ -112,17 +133,38 @@ def create( def destroy(self, wipe=False): - self.access_key_id = nixops_aws.ec2_utils.get_access_key_id() - client = self._connect_rds() - try: - nixops_aws.ec2_utils.retry( - lambda: client.delete_db_subnet_group( - DBSubnetGroupName=self.group_name - ), - error_codes=["DependencyViolation"], - logger=self.logger, - ) - except client.exceptions.DBSubnetGroupNotFoundFault: - pass - self.state = self.MISSING + if self.state == self.UP: + if not self.depl.logger.confirm( + "are you sure you want to destroy the RDS subnet group ‘{0}’?".format( + self.group_name + ) + ): + return False + + rds_client = self._connect_rds() + try: + self.logger.log( + "deleting RDS subnet group ‘{0}’..".format(self.group_name) + ) + nixops_aws.ec2_utils.retry( + lambda: rds_client.delete_db_subnet_group( + DBSubnetGroupName=self.group_name + ), + error_codes=["DependencyViolation"], + logger=self.logger, + ) + except rds_client.exceptions.DBSubnetGroupNotFoundFault: + self.logger.log( + "RDS subnet group ‘{0}’ does not exist, skipping.".format( + self.group_name + ) + ) + except rds_client.exceptions.InvalidDBSubnetGroupStateFault: + self.logger.error( + "RDS Subnet group ‘{0}’ is being used by a database instance".format( + self.group_name + ) + ) + return False + self.state = self.MISSING return True diff --git a/nixops_aws/resources/sns_topic.py b/nixops_aws/resources/sns_topic.py index ad75a681..9413cd7d 100644 --- a/nixops_aws/resources/sns_topic.py +++ b/nixops_aws/resources/sns_topic.py @@ -138,7 +138,9 @@ def create(self, defn: SNSTopicDefinition, check, allow_reboot, allow_recreate): if defn.config.displayName is not None: self._connect().set_topic_attributes( - topic=arn, attr_name="DisplayName", attr_value=defn.config.displayName, + topic=arn, + attr_name="DisplayName", + attr_value=defn.config.displayName, ) if defn.config.policy != "": diff --git a/nixops_aws/resources/types/ec2_rds_dbinstance.py b/nixops_aws/resources/types/ec2_rds_dbinstance.py index 5de1d301..96f687a8 100644 --- a/nixops_aws/resources/types/ec2_rds_dbinstance.py +++ b/nixops_aws/resources/types/ec2_rds_dbinstance.py @@ -16,5 +16,6 @@ class Ec2RdsDbinstanceOptions(ResourceOptions): port: int region: str subnetGroup: Optional[str] + snapshot: Optional[str] securityGroups: Sequence[str] vpcSecurityGroups: Optional[Sequence[str]] diff --git a/poetry.lock b/poetry.lock index 71a6e92d..79ac1dd4 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 = "20.3.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" [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", "zope.interface", "furo", "sphinx", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[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,350 @@ 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.16.24" +description = "The AWS SDK for Python" +category = "main" optional = false python-versions = "*" -version = "1.14.22" [package.dependencies] -botocore = ">=1.17.22,<1.18.0" +botocore = ">=1.19.24,<1.20.0" jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" [[package]] -category = "dev" -description = "Type annotations for boto3 1.14.21, generated by mypy-boto3-buider 2.2.0" name = "boto3-stubs" +version = "1.16.24.0" +description = "Type annotations for boto3 1.16.24, generated by mypy-boto3-buider 3.3.0" +category = "dev" 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 = "*" +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.16.24.0)"] +acm = ["mypy-boto3-acm (1.16.24.0)"] +acm-pca = ["mypy-boto3-acm-pca (1.16.24.0)"] +alexaforbusiness = ["mypy-boto3-alexaforbusiness (1.16.24.0)"] +all = ["mypy-boto3-accessanalyzer (1.16.24.0)", "mypy-boto3-acm (1.16.24.0)", "mypy-boto3-acm-pca (1.16.24.0)", "mypy-boto3-alexaforbusiness (1.16.24.0)", "mypy-boto3-amplify (1.16.24.0)", "mypy-boto3-apigateway (1.16.24.0)", "mypy-boto3-apigatewaymanagementapi (1.16.24.0)", "mypy-boto3-apigatewayv2 (1.16.24.0)", "mypy-boto3-appconfig (1.16.24.0)", "mypy-boto3-appflow (1.16.24.0)", "mypy-boto3-application-autoscaling (1.16.24.0)", "mypy-boto3-application-insights (1.16.24.0)", "mypy-boto3-appmesh (1.16.24.0)", "mypy-boto3-appstream (1.16.24.0)", "mypy-boto3-appsync (1.16.24.0)", "mypy-boto3-athena (1.16.24.0)", "mypy-boto3-autoscaling (1.16.24.0)", "mypy-boto3-autoscaling-plans (1.16.24.0)", "mypy-boto3-backup (1.16.24.0)", "mypy-boto3-batch (1.16.24.0)", "mypy-boto3-braket (1.16.24.0)", "mypy-boto3-budgets (1.16.24.0)", "mypy-boto3-ce (1.16.24.0)", "mypy-boto3-chime (1.16.24.0)", "mypy-boto3-cloud9 (1.16.24.0)", "mypy-boto3-clouddirectory (1.16.24.0)", "mypy-boto3-cloudformation (1.16.24.0)", "mypy-boto3-cloudfront (1.16.24.0)", "mypy-boto3-cloudhsm (1.16.24.0)", "mypy-boto3-cloudhsmv2 (1.16.24.0)", "mypy-boto3-cloudsearch (1.16.24.0)", "mypy-boto3-cloudsearchdomain (1.16.24.0)", "mypy-boto3-cloudtrail (1.16.24.0)", "mypy-boto3-cloudwatch (1.16.24.0)", "mypy-boto3-codeartifact (1.16.24.0)", "mypy-boto3-codebuild (1.16.24.0)", "mypy-boto3-codecommit (1.16.24.0)", "mypy-boto3-codedeploy (1.16.24.0)", "mypy-boto3-codeguru-reviewer (1.16.24.0)", "mypy-boto3-codeguruprofiler (1.16.24.0)", "mypy-boto3-codepipeline (1.16.24.0)", "mypy-boto3-codestar (1.16.24.0)", "mypy-boto3-codestar-connections (1.16.24.0)", "mypy-boto3-codestar-notifications (1.16.24.0)", "mypy-boto3-cognito-identity (1.16.24.0)", "mypy-boto3-cognito-idp (1.16.24.0)", "mypy-boto3-cognito-sync (1.16.24.0)", "mypy-boto3-comprehend (1.16.24.0)", "mypy-boto3-comprehendmedical (1.16.24.0)", "mypy-boto3-compute-optimizer (1.16.24.0)", "mypy-boto3-config (1.16.24.0)", "mypy-boto3-connect (1.16.24.0)", "mypy-boto3-connectparticipant (1.16.24.0)", "mypy-boto3-cur (1.16.24.0)", "mypy-boto3-databrew (1.16.24.0)", "mypy-boto3-dataexchange (1.16.24.0)", "mypy-boto3-datapipeline (1.16.24.0)", "mypy-boto3-datasync (1.16.24.0)", "mypy-boto3-dax (1.16.24.0)", "mypy-boto3-detective (1.16.24.0)", "mypy-boto3-devicefarm (1.16.24.0)", "mypy-boto3-directconnect (1.16.24.0)", "mypy-boto3-discovery (1.16.24.0)", "mypy-boto3-dlm (1.16.24.0)", "mypy-boto3-dms (1.16.24.0)", "mypy-boto3-docdb (1.16.24.0)", "mypy-boto3-ds (1.16.24.0)", "mypy-boto3-dynamodb (1.16.24.0)", "mypy-boto3-dynamodbstreams (1.16.24.0)", "mypy-boto3-ebs (1.16.24.0)", "mypy-boto3-ec2 (1.16.24.0)", "mypy-boto3-ec2-instance-connect (1.16.24.0)", "mypy-boto3-ecr (1.16.24.0)", "mypy-boto3-ecs (1.16.24.0)", "mypy-boto3-efs (1.16.24.0)", "mypy-boto3-eks (1.16.24.0)", "mypy-boto3-elastic-inference (1.16.24.0)", "mypy-boto3-elasticache (1.16.24.0)", "mypy-boto3-elasticbeanstalk (1.16.24.0)", "mypy-boto3-elastictranscoder (1.16.24.0)", "mypy-boto3-elb (1.16.24.0)", "mypy-boto3-elbv2 (1.16.24.0)", "mypy-boto3-emr (1.16.24.0)", "mypy-boto3-es (1.16.24.0)", "mypy-boto3-events (1.16.24.0)", "mypy-boto3-firehose (1.16.24.0)", "mypy-boto3-fms (1.16.24.0)", "mypy-boto3-forecast (1.16.24.0)", "mypy-boto3-forecastquery (1.16.24.0)", "mypy-boto3-frauddetector (1.16.24.0)", "mypy-boto3-fsx (1.16.24.0)", "mypy-boto3-gamelift (1.16.24.0)", "mypy-boto3-glacier (1.16.24.0)", "mypy-boto3-globalaccelerator (1.16.24.0)", "mypy-boto3-glue (1.16.24.0)", "mypy-boto3-greengrass (1.16.24.0)", "mypy-boto3-groundstation (1.16.24.0)", "mypy-boto3-guardduty (1.16.24.0)", "mypy-boto3-health (1.16.24.0)", "mypy-boto3-honeycode (1.16.24.0)", "mypy-boto3-iam (1.16.24.0)", "mypy-boto3-identitystore (1.16.24.0)", "mypy-boto3-imagebuilder (1.16.24.0)", "mypy-boto3-importexport (1.16.24.0)", "mypy-boto3-inspector (1.16.24.0)", "mypy-boto3-iot (1.16.24.0)", "mypy-boto3-iot-data (1.16.24.0)", "mypy-boto3-iot-jobs-data (1.16.24.0)", "mypy-boto3-iot1click-devices (1.16.24.0)", "mypy-boto3-iot1click-projects (1.16.24.0)", "mypy-boto3-iotanalytics (1.16.24.0)", "mypy-boto3-iotevents (1.16.24.0)", "mypy-boto3-iotevents-data (1.16.24.0)", "mypy-boto3-iotsecuretunneling (1.16.24.0)", "mypy-boto3-iotsitewise (1.16.24.0)", "mypy-boto3-iotthingsgraph (1.16.24.0)", "mypy-boto3-ivs (1.16.24.0)", "mypy-boto3-kafka (1.16.24.0)", "mypy-boto3-kendra (1.16.24.0)", "mypy-boto3-kinesis (1.16.24.0)", "mypy-boto3-kinesis-video-archived-media (1.16.24.0)", "mypy-boto3-kinesis-video-media (1.16.24.0)", "mypy-boto3-kinesis-video-signaling (1.16.24.0)", "mypy-boto3-kinesisanalytics (1.16.24.0)", "mypy-boto3-kinesisanalyticsv2 (1.16.24.0)", "mypy-boto3-kinesisvideo (1.16.24.0)", "mypy-boto3-kms (1.16.24.0)", "mypy-boto3-lakeformation (1.16.24.0)", "mypy-boto3-lambda (1.16.24.0)", "mypy-boto3-lex-models (1.16.24.0)", "mypy-boto3-lex-runtime (1.16.24.0)", "mypy-boto3-license-manager (1.16.24.0)", "mypy-boto3-lightsail (1.16.24.0)", "mypy-boto3-logs (1.16.24.0)", "mypy-boto3-machinelearning (1.16.24.0)", "mypy-boto3-macie (1.16.24.0)", "mypy-boto3-macie2 (1.16.24.0)", "mypy-boto3-managedblockchain (1.16.24.0)", "mypy-boto3-marketplace-catalog (1.16.24.0)", "mypy-boto3-marketplace-entitlement (1.16.24.0)", "mypy-boto3-marketplacecommerceanalytics (1.16.24.0)", "mypy-boto3-mediaconnect (1.16.24.0)", "mypy-boto3-mediaconvert (1.16.24.0)", "mypy-boto3-medialive (1.16.24.0)", "mypy-boto3-mediapackage (1.16.24.0)", "mypy-boto3-mediapackage-vod (1.16.24.0)", "mypy-boto3-mediastore (1.16.24.0)", "mypy-boto3-mediastore-data (1.16.24.0)", "mypy-boto3-mediatailor (1.16.24.0)", "mypy-boto3-meteringmarketplace (1.16.24.0)", "mypy-boto3-mgh (1.16.24.0)", "mypy-boto3-migrationhub-config (1.16.24.0)", "mypy-boto3-mobile (1.16.24.0)", "mypy-boto3-mq (1.16.24.0)", "mypy-boto3-mturk (1.16.24.0)", "mypy-boto3-neptune (1.16.24.0)", "mypy-boto3-network-firewall (1.16.24.0)", "mypy-boto3-networkmanager (1.16.24.0)", "mypy-boto3-opsworks (1.16.24.0)", "mypy-boto3-opsworkscm (1.16.24.0)", "mypy-boto3-organizations (1.16.24.0)", "mypy-boto3-outposts (1.16.24.0)", "mypy-boto3-personalize (1.16.24.0)", "mypy-boto3-personalize-events (1.16.24.0)", "mypy-boto3-personalize-runtime (1.16.24.0)", "mypy-boto3-pi (1.16.24.0)", "mypy-boto3-pinpoint (1.16.24.0)", "mypy-boto3-pinpoint-email (1.16.24.0)", "mypy-boto3-pinpoint-sms-voice (1.16.24.0)", "mypy-boto3-polly (1.16.24.0)", "mypy-boto3-pricing (1.16.24.0)", "mypy-boto3-qldb (1.16.24.0)", "mypy-boto3-qldb-session (1.16.24.0)", "mypy-boto3-quicksight (1.16.24.0)", "mypy-boto3-ram (1.16.24.0)", "mypy-boto3-rds (1.16.24.0)", "mypy-boto3-rds-data (1.16.24.0)", "mypy-boto3-redshift (1.16.24.0)", "mypy-boto3-redshift-data (1.16.24.0)", "mypy-boto3-rekognition (1.16.24.0)", "mypy-boto3-resource-groups (1.16.24.0)", "mypy-boto3-resourcegroupstaggingapi (1.16.24.0)", "mypy-boto3-robomaker (1.16.24.0)", "mypy-boto3-route53 (1.16.24.0)", "mypy-boto3-route53domains (1.16.24.0)", "mypy-boto3-route53resolver (1.16.24.0)", "mypy-boto3-s3 (1.16.24.0)", "mypy-boto3-s3control (1.16.24.0)", "mypy-boto3-s3outposts (1.16.24.0)", "mypy-boto3-sagemaker (1.16.24.0)", "mypy-boto3-sagemaker-a2i-runtime (1.16.24.0)", "mypy-boto3-sagemaker-runtime (1.16.24.0)", "mypy-boto3-savingsplans (1.16.24.0)", "mypy-boto3-schemas (1.16.24.0)", "mypy-boto3-sdb (1.16.24.0)", "mypy-boto3-secretsmanager (1.16.24.0)", "mypy-boto3-securityhub (1.16.24.0)", "mypy-boto3-serverlessrepo (1.16.24.0)", "mypy-boto3-service-quotas (1.16.24.0)", "mypy-boto3-servicecatalog (1.16.24.0)", "mypy-boto3-servicecatalog-appregistry (1.16.24.0)", "mypy-boto3-servicediscovery (1.16.24.0)", "mypy-boto3-ses (1.16.24.0)", "mypy-boto3-sesv2 (1.16.24.0)", "mypy-boto3-shield (1.16.24.0)", "mypy-boto3-signer (1.16.24.0)", "mypy-boto3-sms (1.16.24.0)", "mypy-boto3-sms-voice (1.16.24.0)", "mypy-boto3-snowball (1.16.24.0)", "mypy-boto3-sns (1.16.24.0)", "mypy-boto3-sqs (1.16.24.0)", "mypy-boto3-ssm (1.16.24.0)", "mypy-boto3-sso (1.16.24.0)", "mypy-boto3-sso-admin (1.16.24.0)", "mypy-boto3-sso-oidc (1.16.24.0)", "mypy-boto3-stepfunctions (1.16.24.0)", "mypy-boto3-storagegateway (1.16.24.0)", "mypy-boto3-sts (1.16.24.0)", "mypy-boto3-support (1.16.24.0)", "mypy-boto3-swf (1.16.24.0)", "mypy-boto3-synthetics (1.16.24.0)", "mypy-boto3-textract (1.16.24.0)", "mypy-boto3-timestream-query (1.16.24.0)", "mypy-boto3-timestream-write (1.16.24.0)", "mypy-boto3-transcribe (1.16.24.0)", "mypy-boto3-transfer (1.16.24.0)", "mypy-boto3-translate (1.16.24.0)", "mypy-boto3-waf (1.16.24.0)", "mypy-boto3-waf-regional (1.16.24.0)", "mypy-boto3-wafv2 (1.16.24.0)", "mypy-boto3-workdocs (1.16.24.0)", "mypy-boto3-worklink (1.16.24.0)", "mypy-boto3-workmail (1.16.24.0)", "mypy-boto3-workmailmessageflow (1.16.24.0)", "mypy-boto3-workspaces (1.16.24.0)", "mypy-boto3-xray (1.16.24.0)"] +amplify = ["mypy-boto3-amplify (1.16.24.0)"] +apigateway = ["mypy-boto3-apigateway (1.16.24.0)"] +apigatewaymanagementapi = ["mypy-boto3-apigatewaymanagementapi (1.16.24.0)"] +apigatewayv2 = ["mypy-boto3-apigatewayv2 (1.16.24.0)"] +appconfig = ["mypy-boto3-appconfig (1.16.24.0)"] +appflow = ["mypy-boto3-appflow (1.16.24.0)"] +application-autoscaling = ["mypy-boto3-application-autoscaling (1.16.24.0)"] +application-insights = ["mypy-boto3-application-insights (1.16.24.0)"] +appmesh = ["mypy-boto3-appmesh (1.16.24.0)"] +appstream = ["mypy-boto3-appstream (1.16.24.0)"] +appsync = ["mypy-boto3-appsync (1.16.24.0)"] +athena = ["mypy-boto3-athena (1.16.24.0)"] +autoscaling = ["mypy-boto3-autoscaling (1.16.24.0)"] +autoscaling-plans = ["mypy-boto3-autoscaling-plans (1.16.24.0)"] +backup = ["mypy-boto3-backup (1.16.24.0)"] +batch = ["mypy-boto3-batch (1.16.24.0)"] +braket = ["mypy-boto3-braket (1.16.24.0)"] +budgets = ["mypy-boto3-budgets (1.16.24.0)"] +ce = ["mypy-boto3-ce (1.16.24.0)"] +chime = ["mypy-boto3-chime (1.16.24.0)"] +cloud9 = ["mypy-boto3-cloud9 (1.16.24.0)"] +clouddirectory = ["mypy-boto3-clouddirectory (1.16.24.0)"] +cloudformation = ["mypy-boto3-cloudformation (1.16.24.0)"] +cloudfront = ["mypy-boto3-cloudfront (1.16.24.0)"] +cloudhsm = ["mypy-boto3-cloudhsm (1.16.24.0)"] +cloudhsmv2 = ["mypy-boto3-cloudhsmv2 (1.16.24.0)"] +cloudsearch = ["mypy-boto3-cloudsearch (1.16.24.0)"] +cloudsearchdomain = ["mypy-boto3-cloudsearchdomain (1.16.24.0)"] +cloudtrail = ["mypy-boto3-cloudtrail (1.16.24.0)"] +cloudwatch = ["mypy-boto3-cloudwatch (1.16.24.0)"] +codeartifact = ["mypy-boto3-codeartifact (1.16.24.0)"] +codebuild = ["mypy-boto3-codebuild (1.16.24.0)"] +codecommit = ["mypy-boto3-codecommit (1.16.24.0)"] +codedeploy = ["mypy-boto3-codedeploy (1.16.24.0)"] +codeguru-reviewer = ["mypy-boto3-codeguru-reviewer (1.16.24.0)"] +codeguruprofiler = ["mypy-boto3-codeguruprofiler (1.16.24.0)"] +codepipeline = ["mypy-boto3-codepipeline (1.16.24.0)"] +codestar = ["mypy-boto3-codestar (1.16.24.0)"] +codestar-connections = ["mypy-boto3-codestar-connections (1.16.24.0)"] +codestar-notifications = ["mypy-boto3-codestar-notifications (1.16.24.0)"] +cognito-identity = ["mypy-boto3-cognito-identity (1.16.24.0)"] +cognito-idp = ["mypy-boto3-cognito-idp (1.16.24.0)"] +cognito-sync = ["mypy-boto3-cognito-sync (1.16.24.0)"] +comprehend = ["mypy-boto3-comprehend (1.16.24.0)"] +comprehendmedical = ["mypy-boto3-comprehendmedical (1.16.24.0)"] +compute-optimizer = ["mypy-boto3-compute-optimizer (1.16.24.0)"] +config = ["mypy-boto3-config (1.16.24.0)"] +connect = ["mypy-boto3-connect (1.16.24.0)"] +connectparticipant = ["mypy-boto3-connectparticipant (1.16.24.0)"] +cur = ["mypy-boto3-cur (1.16.24.0)"] +databrew = ["mypy-boto3-databrew (1.16.24.0)"] +dataexchange = ["mypy-boto3-dataexchange (1.16.24.0)"] +datapipeline = ["mypy-boto3-datapipeline (1.16.24.0)"] +datasync = ["mypy-boto3-datasync (1.16.24.0)"] +dax = ["mypy-boto3-dax (1.16.24.0)"] +detective = ["mypy-boto3-detective (1.16.24.0)"] +devicefarm = ["mypy-boto3-devicefarm (1.16.24.0)"] +directconnect = ["mypy-boto3-directconnect (1.16.24.0)"] +discovery = ["mypy-boto3-discovery (1.16.24.0)"] +dlm = ["mypy-boto3-dlm (1.16.24.0)"] +dms = ["mypy-boto3-dms (1.16.24.0)"] +docdb = ["mypy-boto3-docdb (1.16.24.0)"] +ds = ["mypy-boto3-ds (1.16.24.0)"] +dynamodb = ["mypy-boto3-dynamodb (1.16.24.0)"] +dynamodbstreams = ["mypy-boto3-dynamodbstreams (1.16.24.0)"] +ebs = ["mypy-boto3-ebs (1.16.24.0)"] +ec2 = ["mypy-boto3-ec2 (1.16.24.0)"] +ec2-instance-connect = ["mypy-boto3-ec2-instance-connect (1.16.24.0)"] +ecr = ["mypy-boto3-ecr (1.16.24.0)"] +ecs = ["mypy-boto3-ecs (1.16.24.0)"] +efs = ["mypy-boto3-efs (1.16.24.0)"] +eks = ["mypy-boto3-eks (1.16.24.0)"] +elastic-inference = ["mypy-boto3-elastic-inference (1.16.24.0)"] +elasticache = ["mypy-boto3-elasticache (1.16.24.0)"] +elasticbeanstalk = ["mypy-boto3-elasticbeanstalk (1.16.24.0)"] +elastictranscoder = ["mypy-boto3-elastictranscoder (1.16.24.0)"] +elb = ["mypy-boto3-elb (1.16.24.0)"] +elbv2 = ["mypy-boto3-elbv2 (1.16.24.0)"] +emr = ["mypy-boto3-emr (1.16.24.0)"] +es = ["mypy-boto3-es (1.16.24.0)"] +essential = ["mypy-boto3-cloudformation (1.16.24.0)", "mypy-boto3-dynamodb (1.16.24.0)", "mypy-boto3-ec2 (1.16.24.0)", "mypy-boto3-lambda (1.16.24.0)", "mypy-boto3-rds (1.16.24.0)", "mypy-boto3-s3 (1.16.24.0)", "mypy-boto3-sqs (1.16.24.0)"] +events = ["mypy-boto3-events (1.16.24.0)"] +firehose = ["mypy-boto3-firehose (1.16.24.0)"] +fms = ["mypy-boto3-fms (1.16.24.0)"] +forecast = ["mypy-boto3-forecast (1.16.24.0)"] +forecastquery = ["mypy-boto3-forecastquery (1.16.24.0)"] +frauddetector = ["mypy-boto3-frauddetector (1.16.24.0)"] +fsx = ["mypy-boto3-fsx (1.16.24.0)"] +gamelift = ["mypy-boto3-gamelift (1.16.24.0)"] +glacier = ["mypy-boto3-glacier (1.16.24.0)"] +globalaccelerator = ["mypy-boto3-globalaccelerator (1.16.24.0)"] +glue = ["mypy-boto3-glue (1.16.24.0)"] +greengrass = ["mypy-boto3-greengrass (1.16.24.0)"] +groundstation = ["mypy-boto3-groundstation (1.16.24.0)"] +guardduty = ["mypy-boto3-guardduty (1.16.24.0)"] +health = ["mypy-boto3-health (1.16.24.0)"] +honeycode = ["mypy-boto3-honeycode (1.16.24.0)"] +iam = ["mypy-boto3-iam (1.16.24.0)"] +identitystore = ["mypy-boto3-identitystore (1.16.24.0)"] +imagebuilder = ["mypy-boto3-imagebuilder (1.16.24.0)"] +importexport = ["mypy-boto3-importexport (1.16.24.0)"] +inspector = ["mypy-boto3-inspector (1.16.24.0)"] +iot = ["mypy-boto3-iot (1.16.24.0)"] +iot-data = ["mypy-boto3-iot-data (1.16.24.0)"] +iot-jobs-data = ["mypy-boto3-iot-jobs-data (1.16.24.0)"] +iot1click-devices = ["mypy-boto3-iot1click-devices (1.16.24.0)"] +iot1click-projects = ["mypy-boto3-iot1click-projects (1.16.24.0)"] +iotanalytics = ["mypy-boto3-iotanalytics (1.16.24.0)"] +iotevents = ["mypy-boto3-iotevents (1.16.24.0)"] +iotevents-data = ["mypy-boto3-iotevents-data (1.16.24.0)"] +iotsecuretunneling = ["mypy-boto3-iotsecuretunneling (1.16.24.0)"] +iotsitewise = ["mypy-boto3-iotsitewise (1.16.24.0)"] +iotthingsgraph = ["mypy-boto3-iotthingsgraph (1.16.24.0)"] +ivs = ["mypy-boto3-ivs (1.16.24.0)"] +kafka = ["mypy-boto3-kafka (1.16.24.0)"] +kendra = ["mypy-boto3-kendra (1.16.24.0)"] +kinesis = ["mypy-boto3-kinesis (1.16.24.0)"] +kinesis-video-archived-media = ["mypy-boto3-kinesis-video-archived-media (1.16.24.0)"] +kinesis-video-media = ["mypy-boto3-kinesis-video-media (1.16.24.0)"] +kinesis-video-signaling = ["mypy-boto3-kinesis-video-signaling (1.16.24.0)"] +kinesisanalytics = ["mypy-boto3-kinesisanalytics (1.16.24.0)"] +kinesisanalyticsv2 = ["mypy-boto3-kinesisanalyticsv2 (1.16.24.0)"] +kinesisvideo = ["mypy-boto3-kinesisvideo (1.16.24.0)"] +kms = ["mypy-boto3-kms (1.16.24.0)"] +lakeformation = ["mypy-boto3-lakeformation (1.16.24.0)"] +lambda = ["mypy-boto3-lambda (1.16.24.0)"] +lex-models = ["mypy-boto3-lex-models (1.16.24.0)"] +lex-runtime = ["mypy-boto3-lex-runtime (1.16.24.0)"] +license-manager = ["mypy-boto3-license-manager (1.16.24.0)"] +lightsail = ["mypy-boto3-lightsail (1.16.24.0)"] +logs = ["mypy-boto3-logs (1.16.24.0)"] +machinelearning = ["mypy-boto3-machinelearning (1.16.24.0)"] +macie = ["mypy-boto3-macie (1.16.24.0)"] +macie2 = ["mypy-boto3-macie2 (1.16.24.0)"] +managedblockchain = ["mypy-boto3-managedblockchain (1.16.24.0)"] +marketplace-catalog = ["mypy-boto3-marketplace-catalog (1.16.24.0)"] +marketplace-entitlement = ["mypy-boto3-marketplace-entitlement (1.16.24.0)"] +marketplacecommerceanalytics = ["mypy-boto3-marketplacecommerceanalytics (1.16.24.0)"] +mediaconnect = ["mypy-boto3-mediaconnect (1.16.24.0)"] +mediaconvert = ["mypy-boto3-mediaconvert (1.16.24.0)"] +medialive = ["mypy-boto3-medialive (1.16.24.0)"] +mediapackage = ["mypy-boto3-mediapackage (1.16.24.0)"] +mediapackage-vod = ["mypy-boto3-mediapackage-vod (1.16.24.0)"] +mediastore = ["mypy-boto3-mediastore (1.16.24.0)"] +mediastore-data = ["mypy-boto3-mediastore-data (1.16.24.0)"] +mediatailor = ["mypy-boto3-mediatailor (1.16.24.0)"] +meteringmarketplace = ["mypy-boto3-meteringmarketplace (1.16.24.0)"] +mgh = ["mypy-boto3-mgh (1.16.24.0)"] +migrationhub-config = ["mypy-boto3-migrationhub-config (1.16.24.0)"] +mobile = ["mypy-boto3-mobile (1.16.24.0)"] +mq = ["mypy-boto3-mq (1.16.24.0)"] +mturk = ["mypy-boto3-mturk (1.16.24.0)"] +neptune = ["mypy-boto3-neptune (1.16.24.0)"] +network-firewall = ["mypy-boto3-network-firewall (1.16.24.0)"] +networkmanager = ["mypy-boto3-networkmanager (1.16.24.0)"] +opsworks = ["mypy-boto3-opsworks (1.16.24.0)"] +opsworkscm = ["mypy-boto3-opsworkscm (1.16.24.0)"] +organizations = ["mypy-boto3-organizations (1.16.24.0)"] +outposts = ["mypy-boto3-outposts (1.16.24.0)"] +personalize = ["mypy-boto3-personalize (1.16.24.0)"] +personalize-events = ["mypy-boto3-personalize-events (1.16.24.0)"] +personalize-runtime = ["mypy-boto3-personalize-runtime (1.16.24.0)"] +pi = ["mypy-boto3-pi (1.16.24.0)"] +pinpoint = ["mypy-boto3-pinpoint (1.16.24.0)"] +pinpoint-email = ["mypy-boto3-pinpoint-email (1.16.24.0)"] +pinpoint-sms-voice = ["mypy-boto3-pinpoint-sms-voice (1.16.24.0)"] +polly = ["mypy-boto3-polly (1.16.24.0)"] +pricing = ["mypy-boto3-pricing (1.16.24.0)"] +qldb = ["mypy-boto3-qldb (1.16.24.0)"] +qldb-session = ["mypy-boto3-qldb-session (1.16.24.0)"] +quicksight = ["mypy-boto3-quicksight (1.16.24.0)"] +ram = ["mypy-boto3-ram (1.16.24.0)"] +rds = ["mypy-boto3-rds (1.16.24.0)"] +rds-data = ["mypy-boto3-rds-data (1.16.24.0)"] +redshift = ["mypy-boto3-redshift (1.16.24.0)"] +redshift-data = ["mypy-boto3-redshift-data (1.16.24.0)"] +rekognition = ["mypy-boto3-rekognition (1.16.24.0)"] +resource-groups = ["mypy-boto3-resource-groups (1.16.24.0)"] +resourcegroupstaggingapi = ["mypy-boto3-resourcegroupstaggingapi (1.16.24.0)"] +robomaker = ["mypy-boto3-robomaker (1.16.24.0)"] +route53 = ["mypy-boto3-route53 (1.16.24.0)"] +route53domains = ["mypy-boto3-route53domains (1.16.24.0)"] +route53resolver = ["mypy-boto3-route53resolver (1.16.24.0)"] +s3 = ["mypy-boto3-s3 (1.16.24.0)"] +s3control = ["mypy-boto3-s3control (1.16.24.0)"] +s3outposts = ["mypy-boto3-s3outposts (1.16.24.0)"] +sagemaker = ["mypy-boto3-sagemaker (1.16.24.0)"] +sagemaker-a2i-runtime = ["mypy-boto3-sagemaker-a2i-runtime (1.16.24.0)"] +sagemaker-runtime = ["mypy-boto3-sagemaker-runtime (1.16.24.0)"] +savingsplans = ["mypy-boto3-savingsplans (1.16.24.0)"] +schemas = ["mypy-boto3-schemas (1.16.24.0)"] +sdb = ["mypy-boto3-sdb (1.16.24.0)"] +secretsmanager = ["mypy-boto3-secretsmanager (1.16.24.0)"] +securityhub = ["mypy-boto3-securityhub (1.16.24.0)"] +serverlessrepo = ["mypy-boto3-serverlessrepo (1.16.24.0)"] +service-quotas = ["mypy-boto3-service-quotas (1.16.24.0)"] +servicecatalog = ["mypy-boto3-servicecatalog (1.16.24.0)"] +servicecatalog-appregistry = ["mypy-boto3-servicecatalog-appregistry (1.16.24.0)"] +servicediscovery = ["mypy-boto3-servicediscovery (1.16.24.0)"] +ses = ["mypy-boto3-ses (1.16.24.0)"] +sesv2 = ["mypy-boto3-sesv2 (1.16.24.0)"] +shield = ["mypy-boto3-shield (1.16.24.0)"] +signer = ["mypy-boto3-signer (1.16.24.0)"] +sms = ["mypy-boto3-sms (1.16.24.0)"] +sms-voice = ["mypy-boto3-sms-voice (1.16.24.0)"] +snowball = ["mypy-boto3-snowball (1.16.24.0)"] +sns = ["mypy-boto3-sns (1.16.24.0)"] +sqs = ["mypy-boto3-sqs (1.16.24.0)"] +ssm = ["mypy-boto3-ssm (1.16.24.0)"] +sso = ["mypy-boto3-sso (1.16.24.0)"] +sso-admin = ["mypy-boto3-sso-admin (1.16.24.0)"] +sso-oidc = ["mypy-boto3-sso-oidc (1.16.24.0)"] +stepfunctions = ["mypy-boto3-stepfunctions (1.16.24.0)"] +storagegateway = ["mypy-boto3-storagegateway (1.16.24.0)"] +sts = ["mypy-boto3-sts (1.16.24.0)"] +support = ["mypy-boto3-support (1.16.24.0)"] +swf = ["mypy-boto3-swf (1.16.24.0)"] +synthetics = ["mypy-boto3-synthetics (1.16.24.0)"] +textract = ["mypy-boto3-textract (1.16.24.0)"] +timestream-query = ["mypy-boto3-timestream-query (1.16.24.0)"] +timestream-write = ["mypy-boto3-timestream-write (1.16.24.0)"] +transcribe = ["mypy-boto3-transcribe (1.16.24.0)"] +transfer = ["mypy-boto3-transfer (1.16.24.0)"] +translate = ["mypy-boto3-translate (1.16.24.0)"] +waf = ["mypy-boto3-waf (1.16.24.0)"] +waf-regional = ["mypy-boto3-waf-regional (1.16.24.0)"] +wafv2 = ["mypy-boto3-wafv2 (1.16.24.0)"] +workdocs = ["mypy-boto3-workdocs (1.16.24.0)"] +worklink = ["mypy-boto3-worklink (1.16.24.0)"] +workmail = ["mypy-boto3-workmail (1.16.24.0)"] +workmailmessageflow = ["mypy-boto3-workmailmessageflow (1.16.24.0)"] +workspaces = ["mypy-boto3-workspaces (1.16.24.0)"] +xray = ["mypy-boto3-xray (1.16.24.0)"] [[package]] -category = "main" -description = "Low-level, data-driven core of boto 3." name = "botocore" +version = "1.19.24" +description = "Low-level, data-driven core of boto 3." +category = "main" optional = false python-versions = "*" -version = "1.17.22" [package.dependencies] -docutils = ">=0.10,<0.16" jmespath = ">=0.7.1,<1.0.0" python-dateutil = ">=2.1,<3.0.0" - -[package.dependencies.urllib3] -python = "<3.4.0 || >=3.5.0" -version = ">=1.20,<1.26" +urllib3 = {version = ">=1.25.4,<1.27", markers = "python_version != \"3.4\""} [[package]] -category = "dev" -description = "Composable command line interface toolkit" name = "click" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "7.1.2" - -[[package]] -category = "main" -description = "Docutils -- Python Documentation Utilities" -name = "docutils" +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 = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] -category = "dev" -description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" +version = "3.8.4" +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" [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 = "*" - [[package]] -category = "main" -description = "Read metadata from Python packages" -marker = "python_version < \"3.8\"" name = "importlib-metadata" +version = "3.1.0" +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] zipp = ">=0.5" [package.extras] docs = ["sphinx", "rst.linker"] -testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] +testing = ["packaging", "pep517", "unittest2", "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 +395,207 @@ 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" -optional = false -python-versions = ">=3.6" -version = "1.14.21.0" - -[package.dependencies] -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" - -[[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" -optional = false -python-versions = ">=3.6" -version = "1.14.21.0" - -[package.dependencies] -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" - -[[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" -optional = false -python-versions = ">=3.6" -version = "1.14.21.0" - -[package.dependencies] -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" - -[[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" -optional = false -python-versions = ">=3.6" -version = "1.14.21.0" - -[package.dependencies] -[package.dependencies.typing-extensions] -python = "<3.8" -version = "*" - -[[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" [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 = "8de09879d7b1733bc4085257d5bf3cc734f1ed38" + [[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" [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 = "6e4d21f47f0c40023a56a9861886bde146476198" + [[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.8.1" +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" [[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.6.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.2.0" +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.1" +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 = "2020.11.13" +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.3.3" +description = "An Amazon S3 Transfer Manager" +category = "main" optional = false python-versions = "*" -version = "0.3.3" [package.dependencies] botocore = ">=1.12.36,<2.0a.0" [[package]] -category = "main" -description = "Python 2 and 3 compatibility utilities" name = "six" +version = "1.15.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.1" +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.10.0" +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"] [[package]] -category = "main" -description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" +version = "3.7.4.3" +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.2" +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"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >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.4.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"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "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 = "f897b654697f02de946d471339d81cc33251133652895ad21be758a02845c5d0" [metadata.files] appdirs = [ @@ -692,8 +603,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-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, + {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, ] black = [ {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, @@ -704,33 +615,28 @@ 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.16.24-py2.py3-none-any.whl", hash = "sha256:f12fc470d170b283dcea921f0ae3744dd8d0fc5263dcc8974c891edefb008a17"}, + {file = "boto3-1.16.24.tar.gz", hash = "sha256:7a76e9012bd7a47da0f75671d98a6cc2db0734b6f3ca17b34acfd381ebca2fb9"}, ] 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.16.24.0.tar.gz", hash = "sha256:e1b438d6c0adba9119cfba287b1ca6afd211e6c82ccce30a09d2251887d4f9b8"}, + {file = "boto3_stubs-1.16.24.0-py3-none-any.whl", hash = "sha256:2506c1affe51730c955db75489f71bf6d58dc4349b50d7194f43238ab7b626c1"}, ] 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.19.24-py2.py3-none-any.whl", hash = "sha256:7d4efbc621e3fe17226b356a65526210c9284f9a823ce7be7209108644823c40"}, + {file = "botocore-1.19.24.tar.gz", hash = "sha256:5975b10dbc6a70c6789b95d083fbb93e4191f13afe25cd7a834cf2168fddbcd8"}, ] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] -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"}, -] 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.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, + {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, ] 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-3.1.0-py2.py3-none-any.whl", hash = "sha256:590690d61efdd716ff82c39ca9a9d4209252adfe288a4b5721181050acbd4175"}, + {file = "importlib_metadata-3.1.0.tar.gz", hash = "sha256:d9b8a46a0885337627a6430db287176970fff18ad421becec1d64cfc763c2099"}, ] jmespath = [ {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, @@ -756,26 +662,6 @@ 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"}, -] -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"}, -] -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"}, -] -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"}, -] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, @@ -788,8 +674,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.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, ] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, @@ -813,27 +699,47 @@ python-dateutil = [ {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, ] 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-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, + {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, + {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, + {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, + {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, + {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, + {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, + {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, + {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, + {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, + {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, + {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, + {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, ] s3transfer = [ {file = "s3transfer-0.3.3-py2.py3-none-any.whl", hash = "sha256:2482b4259524933a022d59da830f51bd746db62f047d6eb213f2f8855dcb8a13"}, @@ -844,8 +750,8 @@ six = [ {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] 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"}, @@ -871,19 +777,19 @@ typed-ast = [ {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] 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.10.0-py3-none-any.whl", hash = "sha256:a75c6d86ac9d1faf85c5ae952de473e5d26824dda6d4394ff6bc676849cfb939"}, + {file = "typeguard-2.10.0.tar.gz", hash = "sha256:d830132dcd544d3f8a2a842ea739eaa0d7c099fcebb9dcdf3802f4c9929d8191"}, ] 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.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, + {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, + {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] 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.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, + {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, ] 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.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, + {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, ] diff --git a/pyproject.toml b/pyproject.toml index 10e1ae24..58bff8cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ include = [ "nixops_aws/nix/*.nix" ] [tool.poetry.dependencies] python = "^3.7" boto = "^2.49.0" -boto3 = "^1.13.7" +boto3 = "^1.16.24" 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 +19,7 @@ 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"} +boto3-stubs = {extras = ["ec2", "sqs", "efs", "rds"], version = "^1.16.24"} [tool.poetry.plugins."nixops"] aws = "nixops_aws.plugin" diff --git a/tests/unit/test_device_name_to_boto_expected.py b/tests/unit/test_device_name_to_boto_expected.py index 1739303e..f4317b49 100644 --- a/tests/unit/test_device_name_to_boto_expected.py +++ b/tests/unit/test_device_name_to_boto_expected.py @@ -7,7 +7,8 @@ class TestDeviceNameToBotoExpected(unittest.TestCase): def test_device_name_to_boto_expected(self): self.assertEqual( - device_name_to_boto_expected("/dev/sdf"), "/dev/sdf", + device_name_to_boto_expected("/dev/sdf"), + "/dev/sdf", ) self.assertEqual(device_name_to_boto_expected("/dev/sdg"), "/dev/sdg") self.assertEqual(device_name_to_boto_expected("/dev/xvdf"), "/dev/sdf")