Пример #1
0
 def _SetThroughput(self, rcu: int, wcu: int) -> None:
   """Updates the table's rcu and wcu."""
   cmd = util.AWS_PREFIX + [
       'dynamodb', 'update-table',
       '--table-name', self.table_name,
       '--region', self.region,
       '--provisioned-throughput',
       f'ReadCapacityUnits={rcu},WriteCapacityUnits={wcu}',
   ]
   logging.info('Setting %s table provisioned throughput to %s rcu and %s wcu',
                self.table_name, rcu, wcu)
   util.IssueRetryableCommand(cmd)
Пример #2
0
 def _Exists(self):
     """Returns true if the internet gateway exists."""
     describe_cmd = util.AWS_PREFIX + [
         'ec2', 'describe-internet-gateways',
         '--region=%s' % self.region,
         '--filter=Name=internet-gateway-id,Values=%s' % self.id
     ]
     stdout, _ = util.IssueRetryableCommand(describe_cmd)
     response = json.loads(stdout)
     internet_gateways = response['InternetGateways']
     assert len(internet_gateways) < 2, 'Too many internet gateways.'
     return len(internet_gateways) > 0
Пример #3
0
 def Attach(self, vpc_id):
     """Attaches the internetgateway to the VPC."""
     if not self.attached:
         self.vpc_id = vpc_id
         attach_cmd = util.AWS_PREFIX + [
             'ec2', 'attach-internet-gateway',
             '--region=%s' % self.region,
             '--internet-gateway-id=%s' % self.id,
             '--vpc-id=%s' % self.vpc_id
         ]
         util.IssueRetryableCommand(attach_cmd)
         self.attached = True
Пример #4
0
 def _Exists(self):
     """Returns true if the VPC exists."""
     describe_cmd = util.AWS_PREFIX + [
         'ec2', 'describe-vpcs',
         '--region=%s' % self.region,
         '--filter=Name=vpc-id,Values=%s' % self.id
     ]
     stdout, _ = util.IssueRetryableCommand(describe_cmd)
     response = json.loads(stdout)
     vpcs = response['Vpcs']
     assert len(vpcs) < 2, 'Too many VPCs.'
     return len(vpcs) > 0
Пример #5
0
 def _Exists(self):
     """Returns true if the subnet exists."""
     describe_cmd = util.AWS_PREFIX + [
         'ec2', 'describe-subnets',
         '--region=%s' % self.region,
         '--filter=Name=subnet-id,Values=%s' % self.id
     ]
     stdout, _ = util.IssueRetryableCommand(describe_cmd)
     response = json.loads(stdout)
     subnets = response['Subnets']
     assert len(subnets) < 2, 'Too many subnets.'
     return len(subnets) > 0
 def _Exists(self):
   """Returns true if the Placement Group exists."""
   describe_cmd = util.AWS_PREFIX + [
       'ec2',
       'describe-placement-groups',
       '--region=%s' % self.region,
       '--filter=Name=group-name,Values=%s' % self.name]
   stdout, _ = util.IssueRetryableCommand(describe_cmd)
   response = json.loads(stdout)
   placement_groups = response['PlacementGroups']
   assert len(placement_groups) < 2, 'Too many placement groups.'
   return bool(placement_groups)
  def _RunCommand(self, cmds):
    """Runs the AWS ec2 command in the defined region.

    Args:
      cmds: List of AWS ec2 commands to run, example: ['describe-route-tables']

    Returns:
      Dict of the AWS response.
    """
    cmd = util.AWS_PREFIX + ['ec2', '--region=%s' % self.region] + list(cmds)
    stdout, _ = util.IssueRetryableCommand(cmd)
    return json.loads(stdout)
Пример #8
0
 def _GetImageId(self):
   """Gets the current EKS worker image for the region."""
   describe_cmd = util.AWS_PREFIX + [
       '--region=%s' % self.region,
       'ec2',
       'describe-images',
       '--query', 'Images[*].{Name:Name,ImageId:ImageId}',
       '--filters',
       'Name=name,Values=eks-worker-v*',
   ]
   stdout, _ = util.IssueRetryableCommand(describe_cmd)
   return max(json.loads(stdout), key=lambda image: image['Name'])['ImageId']
Пример #9
0
    def AllowPortInSecurityGroup(self,
                                 region,
                                 security_group,
                                 start_port,
                                 end_port=None,
                                 source_range=None):
        """Opens a port on the firewall for a security group.

    Args:
      region: The region of the security group
      security_group: The security group in which to open the ports
      start_port: The first local port to open in a range.
      end_port: The last local port to open in a range. If None, only start_port
        will be opened.
      source_range: List of source CIDRs to allow for this port.
    """
        end_port = end_port or start_port
        source_range = source_range or ['0.0.0.0/0']
        for source in source_range:
            entry = (start_port, end_port, region, security_group, source)
            if entry in self.firewall_set:
                continue
            if self._RuleExists(region, security_group, start_port, end_port,
                                source):
                self.firewall_set.add(entry)
                continue
            with self._lock:
                if entry in self.firewall_set:
                    continue
                authorize_cmd = util.AWS_PREFIX + [
                    'ec2',
                    'authorize-security-group-ingress',
                    '--region=%s' % region,
                    '--group-id=%s' % security_group,
                    '--port=%s-%s' % (start_port, end_port),
                    '--cidr=%s' % source,
                ]
                util.IssueRetryableCommand(authorize_cmd + ['--protocol=tcp'])
                util.IssueRetryableCommand(authorize_cmd + ['--protocol=udp'])
                self.firewall_set.add(entry)
    def _Exists(self):
        """Returns whether the VM exists.

    This method waits until the VM is no longer pending.

    Returns:
      Whether the VM exists.

    Raises:
      AwsUnknownStatusError: If an unknown status is returned from AWS.
      AwsTransitionalVmRetryableError: If the VM is pending. This is retried.
    """
        describe_cmd = util.AWS_PREFIX + [
            'ec2', 'describe-instances',
            '--region=%s' % self.region,
            '--filter=Name=client-token,Values=%s' % self.client_token
        ]

        stdout, _ = util.IssueRetryableCommand(describe_cmd)
        response = json.loads(stdout)
        reservations = response['Reservations']
        assert len(reservations) < 2, 'Too many reservations.'
        if not reservations:
            if not self.create_start_time:
                return False
            logging.info('No reservation returned by describe-instances. This '
                         'sometimes shows up immediately after a successful '
                         'run-instances command. Retrying describe-instances '
                         'command.')
            raise AwsTransitionalVmRetryableError()
        instances = reservations[0]['Instances']
        assert len(instances) == 1, 'Wrong number of instances.'
        status = instances[0]['State']['Name']
        self.id = instances[0]['InstanceId']
        if self.use_spot_instance:
            self.spot_instance_request_id = instances[0][
                'SpotInstanceRequestId']

        if status not in INSTANCE_KNOWN_STATUSES:
            raise AwsUnknownStatusError('Unknown status %s' % status)
        if status in INSTANCE_TRANSITIONAL_STATUSES:
            logging.info(
                'VM has status %s; retrying describe-instances command.',
                status)
            raise AwsTransitionalVmRetryableError()
        # In this path run-instances succeeded, a pending instance was created, but
        # not fulfilled so it moved to terminated.
        if (status == TERMINATED and instances[0]['StateReason']['Code']
                == 'Server.InsufficientInstanceCapacity'):
            raise errors.Benchmarks.InsufficientCapacityCloudFailure(
                instances[0]['StateReason']['Message'])
        return status in INSTANCE_EXISTS_STATUSES
Пример #11
0
 def CreateRoute(self, internet_gateway_id):
   """Adds a route to the internet gateway."""
   if self.RouteExists():
     logging.info('Internet route already exists.')
     return
   create_cmd = util.AWS_PREFIX + [
       'ec2',
       'create-route',
       '--region=%s' % self.region,
       '--route-table-id=%s' % self.id,
       '--gateway-id=%s' % internet_gateway_id,
       '--destination-cidr-block=0.0.0.0/0']
   util.IssueRetryableCommand(create_cmd)
Пример #12
0
 def DeleteKeyfile(cls, region):
   """Deletes the imported keyfile for a region."""
   with cls._lock:
     if _GetKeyfileSetKey(region) in cls.deleted_keyfile_set:
       return
     delete_cmd = util.AWS_PREFIX + [
         'ec2', '--region=%s' % region,
         'delete-key-pair',
         '--key-name=%s' % cls.GetKeyNameForRun()]
     util.IssueRetryableCommand(delete_cmd)
     cls.deleted_keyfile_set.add(_GetKeyfileSetKey(region))
     if _GetKeyfileSetKey(region) in cls.imported_keyfile_set:
       cls.imported_keyfile_set.remove(_GetKeyfileSetKey(region))
 def DeleteKeyfile(self):
   """Deletes the imported keyfile for a region."""
   with self._lock:
     if self.region in self.deleted_keyfile_set:
       return
     delete_cmd = util.AWS_PREFIX + [
         'ec2', '--region=%s' % self.region,
         'delete-key-pair',
         '--key-name=%s' % 'perfkit-key-%s' % FLAGS.run_uri]
     util.IssueRetryableCommand(delete_cmd)
     self.deleted_keyfile_set.add(self.region)
     if self.region in self.imported_keyfile_set:
       self.imported_keyfile_set.remove(self.region)
Пример #14
0
    def _EnableDnsHostnames(self):
        """Sets the enableDnsHostnames attribute of this VPC to True.

    By default, instances launched in non-default VPCs are assigned an
    unresolvable hostname. This breaks the hadoop benchmark.  Setting the
    enableDnsHostnames attribute to 'true' on the VPC resolves this. See:
    http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_DHCP_Options.html
    """
        enable_hostnames_command = util.AWS_PREFIX + [
            'ec2', 'modify-vpc-attribute',
            '--region=%s' % self.region, '--vpc-id', self.id,
            '--enable-dns-hostnames', '{ "Value": true }'
        ]

        util.IssueRetryableCommand(enable_hostnames_command)
Пример #15
0
    def Detach(self):
        """Detaches the disk from a VM."""
        detach_cmd = util.AWS_PREFIX + [
            'ec2', 'detach-volume',
            '--region=%s' % self.region,
            '--instance-id=%s' % self.attached_vm_id,
            '--volume-id=%s' % self.id
        ]
        util.IssueRetryableCommand(detach_cmd)

        with self._lock:
            assert self.attached_vm_id in AwsDisk.vm_devices
            AwsDisk.vm_devices[self.attached_vm_id].add(self.device_letter)
            self.attached_vm_id = None
            self.device_letter = None
Пример #16
0
    def AllowPort(self, vm, port):
        """Opens a port on the firewall.

    Args:
      vm: The BaseVirtualMachine object to open the port for.
      port: The local port to open.
    """
        if vm.is_static:
            return
        entry = (port, vm.group_id)
        if entry in self.firewall_set:
            return
        with self._lock:
            if entry in self.firewall_set:
                return
            authorize_cmd = util.AWS_PREFIX + [
                'ec2', 'authorize-security-group-ingress',
                '--region=%s' % vm.region,
                '--group-id=%s' % vm.group_id,
                '--port=%s' % port, '--cidr=0.0.0.0/0'
            ]
            util.IssueRetryableCommand(authorize_cmd + ['--protocol=tcp'])
            util.IssueRetryableCommand(authorize_cmd + ['--protocol=udp'])
            self.firewall_set.add(entry)
Пример #17
0
 def _Exists(self):
     """Returns true if the disk exists."""
     describe_cmd = util.AWS_PREFIX + [
         'ec2', 'describe-volumes',
         '--region=%s' % self.region,
         '--filter=Name=volume-id,Values=%s' % self.id
     ]
     stdout, _ = util.IssueRetryableCommand(describe_cmd)
     response = json.loads(stdout)
     volumes = response['Volumes']
     assert len(volumes) < 2, 'Too many volumes.'
     if not volumes:
         return False
     status = volumes[0]['State']
     assert status in VOLUME_KNOWN_STATUSES, status
     return status in VOLUME_EXISTS_STATUSES
Пример #18
0
 def _RuleExists(self, region, security_group, start_port, end_port, source):
   """Whether the firewall rule exists in the VPC."""
   query_cmd = util.AWS_PREFIX + [
       'ec2',
       'describe-security-groups',
       '--region=%s' % region,
       '--group-ids=%s' % security_group,
       '--filters',
       'Name=ip-permission.cidr,Values={}'.format(source),
       'Name=ip-permission.from-port,Values={}'.format(start_port),
       'Name=ip-permission.to-port,Values={}'.format(end_port),
   ]
   stdout, _ = util.IssueRetryableCommand(query_cmd)
   # "groups" will be an array of all the matching firewall rules
   groups = json.loads(stdout)['SecurityGroups']
   return bool(groups)
 def ImportKeyfile(self):
   """Imports the public keyfile to AWS."""
   with self._lock:
     if self.region in self.imported_keyfile_set:
       return
     cat_cmd = ['cat',
                vm_util.GetPublicKeyPath()]
     keyfile, _ = vm_util.IssueRetryableCommand(cat_cmd)
     import_cmd = util.AWS_PREFIX + [
         'ec2', '--region=%s' % self.region,
         'import-key-pair',
         '--key-name=%s' % 'perfkit-key-%s' % FLAGS.run_uri,
         '--public-key-material=%s' % keyfile]
     util.IssueRetryableCommand(import_cmd)
     self.imported_keyfile_set.add(self.region)
     if self.region in self.deleted_keyfile_set:
       self.deleted_keyfile_set.remove(self.region)
 def ImportKeyfile(cls, region):
     """Imports the public keyfile to AWS."""
     with cls._lock:
         if _GetKeyfileSetKey(region) in cls.imported_keyfile_set:
             return
         cat_cmd = ['cat', vm_util.GetPublicKeyPath()]
         keyfile, _ = vm_util.IssueRetryableCommand(cat_cmd)
         import_cmd = util.AWS_PREFIX + [
             'ec2',
             '--region=%s' % region, 'import-key-pair',
             '--key-name=%s' % cls.GetKeyNameForRun(),
             '--public-key-material=%s' % keyfile
         ]
         util.IssueRetryableCommand(import_cmd)
         cls.imported_keyfile_set.add(_GetKeyfileSetKey(region))
         if _GetKeyfileSetKey(region) in cls.deleted_keyfile_set:
             cls.deleted_keyfile_set.remove(_GetKeyfileSetKey(region))
  def _GetDefaultImage(cls, machine_type, region):
    """Returns the default image given the machine type and region.

    If specified, aws_image_name_filter will override os_type defaults.
    If no default is configured, this will return None.

    Args:
      machine_type: The machine_type of the VM, used to determine virtualization
        type.
      region: The region of the VM, as images are region specific.
    """
    if cls.IMAGE_NAME_FILTER is None:
      return None

    if FLAGS.aws_image_name_filter:
      cls.IMAGE_NAME_FILTER = FLAGS.aws_image_name_filter

    prefix = machine_type.split('.')[0]
    virt_type = 'paravirtual' if prefix in NON_HVM_PREFIXES else 'hvm'

    describe_cmd = util.AWS_PREFIX + [
        '--region=%s' % region,
        'ec2',
        'describe-images',
        '--query', 'Images[*].{Name:Name,ImageId:ImageId}',
        '--filters',
        'Name=name,Values=%s' % cls.IMAGE_NAME_FILTER,
        'Name=block-device-mapping.volume-type,Values=%s' %
        cls.DEFAULT_ROOT_DISK_TYPE,
        'Name=virtualization-type,Values=%s' % virt_type]
    if cls.IMAGE_PRODUCT_CODE_FILTER:
      describe_cmd.extend(['Name=product-code,Values=%s' %
                           cls.IMAGE_PRODUCT_CODE_FILTER])
    if cls.IMAGE_OWNER:
      describe_cmd.extend(['--owners', cls.IMAGE_OWNER])
    stdout, _ = util.IssueRetryableCommand(describe_cmd)

    if not stdout:
      return None

    images = json.loads(stdout)
    # We want to return the latest version of the image, and since the wildcard
    # portion of the image name is the image's creation date, we can just take
    # the image with the 'largest' name.
    return max(images, key=lambda image: image['Name'])['ImageId']
 def _Exists(self):
     """Returns true if the VM exists."""
     describe_cmd = util.AWS_PREFIX + [
         'ec2', 'describe-instances',
         '--region=%s' % self.region,
         '--filter=Name=instance-id,Values=%s' % self.id
     ]
     stdout, _ = util.IssueRetryableCommand(describe_cmd)
     response = json.loads(stdout)
     reservations = response['Reservations']
     assert len(reservations) < 2, 'Too many reservations.'
     if not reservations:
         return False
     instances = reservations[0]['Instances']
     assert len(instances) == 1, 'Wrong number of instances.'
     status = instances[0]['State']['Name']
     assert status in INSTANCE_KNOWN_STATUSES, status
     return status in INSTANCE_EXISTS_STATUSES
Пример #23
0
  def _GetDecodedPasswordData(self):
    # Retrieve a base64 encoded, encrypted password for the VM.
    get_password_cmd = util.AWS_PREFIX + [
        'ec2',
        'get-password-data',
        '--region=%s' % self.region,
        '--instance-id=%s' % self.id]
    stdout, _ = util.IssueRetryableCommand(get_password_cmd)
    response = json.loads(stdout)
    password_data = response['PasswordData']

    # AWS may not populate the password data until some time after
    # the VM shows as running. Simply retry until the data shows up.
    if not password_data:
      raise ValueError('No PasswordData in response.')

    # Decode the password data.
    return base64.b64decode(password_data)
Пример #24
0
  def Detach(self):
    """Detaches the internet gateway from the VPC."""

    def _suppress_failure(stdout, stderr, retcode):
      """Suppresses Detach failure when internet gateway is in a bad state."""
      del stdout  # unused
      if retcode and ('InvalidInternetGatewayID.NotFound' in stderr or
                      'Gateway.NotAttached' in stderr):
        return True
      return False

    if self.attached and not self.user_managed:
      detach_cmd = util.AWS_PREFIX + [
          'ec2',
          'detach-internet-gateway',
          '--region=%s' % self.region,
          '--internet-gateway-id=%s' % self.id,
          '--vpc-id=%s' % self.vpc_id]
      util.IssueRetryableCommand(detach_cmd, suppress_failure=_suppress_failure)
      self.attached = False
  def _PostCreate(self):
    """Get the instance's data and tag it."""
    describe_cmd = util.AWS_PREFIX + [
        'ec2',
        'describe-instances',
        '--region=%s' % self.region,
        '--instance-ids=%s' % self.id]
    logging.info('Getting instance %s public IP. This will fail until '
                 'a public IP is available, but will be retried.', self.id)
    stdout, _ = util.IssueRetryableCommand(describe_cmd)
    response = json.loads(stdout)
    instance = response['Reservations'][0]['Instances'][0]
    self.ip_address = instance['PublicIpAddress']
    self.internal_ip = instance['PrivateIpAddress']
    if util.IsRegion(self.zone):
      self.zone = str(instance['Placement']['AvailabilityZone'])
    util.AddDefaultTags(self.id, self.region)

    assert self.group_id == instance['SecurityGroups'][0]['GroupId'], (
        self.group_id, instance['SecurityGroups'][0]['GroupId'])
Пример #26
0
 def SetThroughput(self,
                   rcu: Optional[int] = None,
                   wcu: Optional[int] = None) -> None:
   """Updates the table's rcu and wcu."""
   if not rcu:
     rcu = self.rcu
   if not wcu:
     wcu = self.wcu
   cmd = util.AWS_PREFIX + [
       'dynamodb', 'update-table',
       '--table-name', self.table_name,
       '--region', self.region,
       '--provisioned-throughput',
       f'ReadCapacityUnits={rcu},WriteCapacityUnits={wcu}',
   ]
   logging.info('Setting %s table provisioned throughput to %s rcu and %s wcu',
                self.table_name, rcu, wcu)
   util.IssueRetryableCommand(cmd)
   while not self._IsReady():
     continue
Пример #27
0
  def GetDict(self):
    """The 'aws ec2 describe-subnets' for this VPC / subnet id.

    Returns:
      A dict of the single subnet or an empty dict if there are no subnets.

    Raises:
      AssertionError: If there is more than one subnet.
    """
    describe_cmd = util.AWS_PREFIX + [
        'ec2', 'describe-subnets',
        '--region=%s' % self.region,
        '--filter=Name=vpc-id,Values=%s' % self.vpc_id
    ]
    if self.id:
      describe_cmd.append('--filter=Name=subnet-id,Values=%s' % self.id)
    stdout, _ = util.IssueRetryableCommand(describe_cmd)
    response = json.loads(stdout)
    subnets = response['Subnets']
    assert len(subnets) < 2, 'Too many subnets.'
    return subnets[0] if subnets else {}
Пример #28
0
  def Attach(self, vm):
    """Attaches the disk to a VM.

    Args:
      vm: The AwsVirtualMachine instance to which the disk will be attached.
    """
    with self._lock:
      self.attached_vm_id = vm.id
      if self.attached_vm_id not in AwsDisk.vm_devices:
        AwsDisk.vm_devices[self.attached_vm_id] = set(
            string.ascii_lowercase)
      self.device_letter = min(AwsDisk.vm_devices[self.attached_vm_id])
      AwsDisk.vm_devices[self.attached_vm_id].remove(self.device_letter)

    attach_cmd = util.AWS_PREFIX + [
        'ec2',
        'attach-volume',
        '--region=%s' % self.region,
        '--instance-id=%s' % self.attached_vm_id,
        '--volume-id=%s' % self.id,
        '--device=%s' % self.GetDevicePath()]
    logging.info('Attaching AWS volume %s. This may fail if the disk is not '
                 'ready, but will be retried.', self.id)
    util.IssueRetryableCommand(attach_cmd)
Пример #29
0
  def _PostCreate(self):
    """Get the instance's data and tag it."""
    describe_cmd = util.AWS_PREFIX + [
        'ec2',
        'describe-instances',
        '--region=%s' % self.region,
        '--instance-ids=%s' % self.id]
    logging.info('Getting instance %s public IP. This will fail until '
                 'a public IP is available, but will be retried.', self.id)
    stdout, _ = util.IssueRetryableCommand(describe_cmd)
    response = json.loads(stdout)
    instance = response['Reservations'][0]['Instances'][0]
    self.ip_address = instance['PublicIpAddress']
    self.internal_ip = instance['PrivateIpAddress']
    if util.IsRegion(self.zone):
      self.zone = str(instance['Placement']['AvailabilityZone'])

    assert self.group_id == instance['SecurityGroups'][0]['GroupId'], (
        self.group_id, instance['SecurityGroups'][0]['GroupId'])
    if FLAGS.aws_efa:
      self.InstallPackages('curl')
      url = _EFA_URL.format(version=FLAGS.aws_efa_version)
      self.RemoteCommand(
          _EFA_INSTALL_CMD.format(url=url, tarfile=posixpath.basename(url)))
Пример #30
0
 def UpdateWithDefaultTags(self) -> None:
   """Adds default tags to the table."""
   tags = util.MakeFormattedDefaultTags()
   cmd = self._GetTagResourceCommand(tags)
   logging.info('Setting default tags on table %s', self.table_name)
   util.IssueRetryableCommand(cmd)