Example #1
0
    def _Delete(self):
        """Delete a DigitalOcean VM instance."""
        stdout, ret = util.RunCurlCommand('DELETE',
                                          'droplets/%s' % self.droplet_id)
        if ret != 0:
            if ret == 404:
                return  # Assume already deleted.
            raise errors.Resource.RetryableDeletionError(
                'Deletion failed: %s' % GetErrorMessage(stdout))

        # Get the droplet's actions so that we can look up the
        # ID for the deletion just issued.
        stdout, ret = util.RunCurlCommand(
            'GET', 'droplets/%s/actions' % self.droplet_id)
        if ret != 0:
            # There's a race condition here - if the lookup fails, assume it's
            # due to deletion already being complete. Don't raise an error in
            # that case,  the _Exists check should trigger retry if needed.
            return
        response = json.loads(stdout)['actions']

        # Get the action ID for the 'destroy' action. This assumes there's only
        # one of them, but AFAIK there can't be more since 'destroy' locks the VM.
        destroy = [v for v in response if v['type'] == 'destroy'][0]

        # Wait for completion. Actions are global objects, so the action
        # status should still be retrievable after the VM got destroyed.
        # We don't care about the result, let the _Exists check decide if we
        # need to try again.
        self._GetActionResult(destroy['id'])
Example #2
0
 def _PostCreate(self):
     """Get the instance's data."""
     stdout, _ = util.RunCurlCommand('GET', 'droplets/%s' % self.droplet_id)
     response = json.loads(stdout)['droplet']
     for interface in response['networks']['v4']:
         if interface['type'] == 'public':
             self.ip_address = interface['ip_address']
         else:
             self.internal_ip = interface['ip_address']
Example #3
0
 def _Exists(self):
     """Returns true if the VM exists."""
     _, ret = util.RunCurlCommand('GET',
                                  'droplets/%s' % self.droplet_id,
                                  suppress_warning=True)
     if ret == 0:
         return True
     if ret == 404:
         # Definitely doesn't exist.
         return False
     # Unknown status - assume it doesn't exist. TODO(klausw): retry?
     return False
Example #4
0
    def _Create(self):
        """Create a DigitalOcean VM instance (droplet)."""
        with open(self.ssh_public_key) as f:
            public_key = f.read().rstrip('\n')

        stdout, ret = util.RunCurlCommand(
            'POST', 'droplets', {
                'name':
                self.name,
                'region':
                self.zone,
                'size':
                self.machine_type,
                'image':
                self.image,
                'backups':
                False,
                'ipv6':
                False,
                'private_networking':
                True,
                'ssh_keys': [],
                'user_data':
                CLOUD_CONFIG_TEMPLATE.format(self.user_name, public_key)
            })
        if ret != 0:
            msg = GetErrorMessage(stdout)
            if ret in FATAL_CREATION_ERRORS:
                raise errors.Error(
                    'Creation request invalid, not retrying: %s' % msg)
            raise errors.Resource.RetryableCreationError(
                'Creation failed: %s' % msg)
        response = json.loads(stdout)
        self.droplet_id = response['droplet']['id']

        # The freshly created droplet will be in a locked and unusable
        # state for a while, and it cannot be deleted or modified in
        # this state. Wait for the action to finish and check the
        # reported result.
        if not self._GetActionResult(response['links']['actions'][0]['id']):
            raise errors.Resource.RetryableCreationError(
                'Creation failed, see log.')
Example #5
0
 def _GetActionResult(self,
                      action_id,
                      wait_seconds=DEFAULT_ACTION_WAIT_SECONDS,
                      max_tries=DEFAULT_ACTION_MAX_TRIES):
     """Wait until a VM action completes."""
     for _ in xrange(max_tries):
         time.sleep(wait_seconds)
         stdout, ret = util.RunCurlCommand('GET', 'actions/%s' % action_id)
         if ret != 0:
             logging.warn('Unexpected action lookup failure.')
             return False
         response = json.loads(stdout)
         status = response['action']['status']
         logging.debug('action %d: status is "%s".', action_id, status)
         if status == 'completed':
             return True
         elif status == 'errored':
             return False
     # If we get here, waiting timed out. Treat as failure.
     logging.debug('action %d: timed out waiting.', action_id)
     return False