  def GetOrCreateVm(
      self,
      vm_name: str,
      boot_volume_size: int,
      ami: str,
      cpu_cores: int,
      boot_volume_type: str = 'gp3',
      ssh_key_name: Optional[str] = None,
      tags: Optional[Dict[str, str]] = None,
      subnet_id: Optional[str] = None,
      security_group_id: Optional[str] = None,
      userdata: Optional[str] = None,
      instance_profile: Optional[str] = None,
      terminate_on_shutdown: bool = False,
      wait_for_health_checks: bool = True
      ) -> Tuple[AWSInstance, bool]:
    """Get or create a new virtual machine for analysis purposes.

    Args:
      vm_name (str): The instance name tag of the virtual machine.
      boot_volume_size (int): The size of the analysis VM boot volume (in GB).
      ami (str): The Amazon Machine Image ID to use to create the VM.
      cpu_cores (int): Number of CPU cores for the analysis VM.
      boot_volume_type (str): Optional. The volume type for the boot volume
          of the VM. Can be one of 'standard'|'io1'|'gp2'|'gp3'|'sc1'|'st1'. The
          default is 'gp3'.
      ssh_key_name (str): Optional. A SSH key pair name linked to the AWS
          account to associate with the VM. If none provided, the VM can only
          be accessed through in-browser SSH from the AWS management console
          with the EC2 client connection package (ec2-instance-connect). Note
          that if this package fails to install on the target VM, then the VM
          will not be accessible. It is therefore recommended to fill in this
          parameter.
      tags (Dict[str, str]): Optional. A dictionary of tags to add to the
          instance, for example {'TicketID': 'xxx'}. An entry for the instance
          name is added by default.
      subnet_id (str): Optional. Subnet to launch the instance in.
      security_group_id (str): Optional. Security group id to attach.
      userdata (str): Optional. String passed to the instance as a userdata
          launch script.
      instance_profile (str): Optional. Instance role to be attached.
      terminate_on_shutdown (bool): Optional. Terminate the instance when the
          instance initiates shutdown.
      wait_for_health_checks (bool): Optional. Wait for health checks on the
          instance before returning

    Returns:
      Tuple[AWSInstance, bool]: A tuple with an AWSInstance object and a
          boolean indicating if the virtual machine was created (True) or
          reused (False).

    Raises:
      ResourceCreationError: If the virtual machine cannot be created.
    """

    # Re-use instance if it already exists, or create a new one.
    instances = self.GetInstancesByName(vm_name)
    if instances:
      created = False
      return instances[0], created

    instance_type = common.GetInstanceTypeByCPU(cpu_cores)

    if not tags:
      tags = {}
    tags['Name'] = vm_name

    client = self.aws_account.ClientApi(common.EC2_SERVICE)
    vm_args = {
        'BlockDeviceMappings':
            [self._GetBootVolumeConfigByAmi(
                ami, boot_volume_size, boot_volume_type)],
        'ImageId': ami,
        'MinCount': 1,
        'MaxCount': 1,
        'InstanceType': instance_type,
        'TagSpecifications': [common.CreateTags(common.INSTANCE, tags)],
        'Placement': {
            'AvailabilityZone': self.aws_account.default_availability_zone}
    }
    if ssh_key_name:
      vm_args['KeyName'] = ssh_key_name
    if subnet_id:
      interface = {
            'AssociatePublicIpAddress': True,
            'DeleteOnTermination': True,
            'DeviceIndex': 0,
            'SubnetId': subnet_id}
      if security_group_id:
        interface['Groups'] = [security_group_id]
      vm_args['NetworkInterfaces']=[interface]
    elif security_group_id:
      vm_args['SecurityGroupIds'] = [security_group_id]
    if userdata:
      vm_args['UserData'] = userdata
    if instance_profile:
      vm_args['IamInstanceProfile'] = {'Arn': instance_profile}
    if terminate_on_shutdown:
      vm_args['InstanceInitiatedShutdownBehavior'] = 'terminate'
    # Create the instance in AWS
    try:
      instance = client.run_instances(**vm_args)
      # If the call to run_instances was successful, then the API response
      # contains the instance ID for the new instance.
      instance_id = instance['Instances'][0]['InstanceId']
      if wait_for_health_checks:
        # Wait for the instance to be running
        client.get_waiter('instance_running').wait(InstanceIds=[instance_id])
        # Wait for the status checks to pass
        client.get_waiter('instance_status_ok').wait(InstanceIds=[instance_id])
      vpc = instance['Instances'][0]['VpcId']
    except (client.exceptions.ClientError,
            botocore.exceptions.WaiterError) as exception:
      raise errors.ResourceCreationError(
          'Could not create instance {0:s}: {1!s}'.format(vm_name, exception),
          __name__) from exception

    instance = AWSInstance(self.aws_account,
                           instance_id,
                           self.aws_account.default_region,
                           self.aws_account.default_availability_zone,
                           vpc,
                           name=vm_name)
    created = True
    return instance, created
Get or create a new virtual machine for analysis purposes.

Args:
vm_name (str): The instance name tag of the virtual machine.
boot_volume_size (int): The size of the analysis VM boot volume (in GB).
ami (str): The Amazon Machine Image ID to use to create the VM.
cpu_cores (int): Number of CPU cores for the analysis VM.
boot_volume_type (str): Optional. The volume type for the boot volume
of the VM. Can be one of 'standard'|'io1'|'gp2'|'gp3'|'sc1'|'st1'. The
default is 'gp3'.
ssh_key_name (str): Optional. A SSH key pair name linked to the AWS
account to associate with the VM. If none provided, the VM can only
be accessed through in-browser SSH from the AWS management console
with the EC2 client connection package (ec2-instance-connect). Note
that if this package fails to install on the target VM, then the VM
will not be accessible. It is therefore recommended to fill in this
parameter.
tags (Dict[str, str]): Optional. A dictionary of tags to add to the
instance, for example {'TicketID': 'xxx'}. An entry for the instance
name is added by default.
subnet_id (str): Optional. Subnet to launch the instance in.
security_group_id (str): Optional. Security group id to attach.
userdata (str): Optional. String passed to the instance as a userdata
launch script.
instance_profile (str): Optional. Instance role to be attached.
terminate_on_shutdown (bool): Optional. Terminate the instance when the
instance initiates shutdown.
wait_for_health_checks (bool): Optional. Wait for health checks on the
instance before returning

Returns:
Tuple[AWSInstance, bool]: A tuple with an AWSInstance object and a
boolean indicating if the virtual machine was created (True) or
reused (False).

Raises:
ResourceCreationError: If the virtual machine cannot be created.
libcloudforensics/providers/aws/internal/ec2.py