Ejemplo n.º 1
0
def PopulatePublicKey(api_client, service_id, version_id, instance_id,
                      public_key, release_track):
    """Enable debug mode on and send SSH keys to a flex instance.

  Common method for SSH-like commands, does the following:
  - Makes sure that the service/version/instance specified exists and is of the
    right type (Flexible).
  - If not already done, prompts and enables debug on the instance.
  - Populates the public key onto the instance.

  Args:
    api_client: An appengine_api_client.AppEngineApiClient.
    service_id: str, The service ID.
    version_id: str, The version ID.
    instance_id: str, The instance ID.
    public_key: ssh.Keys.PublicKey, Public key to send.
    release_track: calliope.base.ReleaseTrack, The current release track.

  Raises:
    InvalidInstanceTypeError: The instance is not supported for SSH.
    MissingVersionError: The version specified does not exist.
    MissingInstanceError: The instance specified does not exist.
    UnattendedPromptError: Not running in a tty.
    OperationCancelledError: User cancelled the operation.

  Returns:
    ConnectionDetails, the details to use for SSH/SCP for the SSH
    connection.
  """
    try:
        version = api_client.GetVersionResource(service=service_id,
                                                version=version_id)
    except apitools_exceptions.HttpNotFoundError:
        raise command_exceptions.MissingVersionError('{}/{}'.format(
            service_id, version_id))
    version = version_util.Version.FromVersionResource(version, None)
    if version.environment is not env.FLEX:
        if version.environment is env.MANAGED_VMS:
            environment = 'Managed VMs'
            msg = 'Use `gcloud compute ssh` for Managed VMs instances.'
        else:
            environment = 'Standard'
            msg = None
        raise command_exceptions.InvalidInstanceTypeError(environment, msg)
    res = resources.REGISTRY.Parse(
        instance_id,
        params={
            'appsId': properties.VALUES.core.project.GetOrFail,
            'versionsId': version_id,
            'instancesId': instance_id,
            'servicesId': service_id,
        },
        collection='appengine.apps.services.versions.instances')
    rel_name = res.RelativeName()
    try:
        instance = api_client.GetInstanceResource(res)
    except apitools_exceptions.HttpNotFoundError:
        raise command_exceptions.MissingInstanceError(rel_name)

    if not instance.vmDebugEnabled:
        log.warning(_ENABLE_DEBUG_WARNING)
        console_io.PromptContinue(cancel_on_no=True, throw_if_unattended=True)
    user = ssh.GetDefaultSshUsername()
    project = _GetComputeProject(release_track)
    user, use_oslogin = ssh.CheckForOsloginAndGetUser(None, project, user,
                                                      public_key.ToEntry(),
                                                      release_track)
    remote = ssh.Remote(instance.vmIp, user=user)
    if not use_oslogin:
        ssh_key = '{user}:{key} {user}'.format(user=user,
                                               key=public_key.ToEntry())
        log.status.Print(
            'Sending public key to instance [{}].'.format(rel_name))
        api_client.DebugInstance(res, ssh_key)
    options = {
        'IdentitiesOnly':
        'yes',  # No ssh-agent as of yet
        'UserKnownHostsFile':
        ssh.KnownHosts.DEFAULT_PATH,
        'CheckHostIP':
        'no',
        'HostKeyAlias':
        _HOST_KEY_ALIAS.format(project=api_client.project,
                               instance_id=instance_id)
    }
    return ConnectionDetails(remote, options)
Ejemplo n.º 2
0
    def Run(self, args):
        """Connect to a running flex instance.

    Args:
      args: argparse.Namespace, the args the command was invoked with.

    Raises:
      InvalidInstanceTypeError: The instance is not supported for SSH.
      MissingVersionError: The version specified does not exist.
      MissingInstanceError: The instance specified does not exist.
      UnattendedPromptError: Not running in a tty.
      OperationCancelledError: User cancelled the operation.
      ssh.CommandError: The SSH command exited with SSH exit code, which
        usually implies that a connection problem occurred.

    Returns:
      int, The exit code of the SSH command.
    """
        api_client = appengine_api_client.GetApiClient()
        env = ssh.Environment.Current()
        env.RequireSSH()
        keys = ssh.Keys.FromFilename()
        keys.EnsureKeysExist(overwrite=False)

        try:
            version = api_client.GetVersionResource(service=args.service,
                                                    version=args.version)
        except api_exceptions.NotFoundError:
            raise command_exceptions.MissingVersionError('{}/{}'.format(
                args.service, args.version))
        version = version_util.Version.FromVersionResource(version, None)
        if version.environment is not util.Environment.FLEX:
            if version.environment is util.Environment.MANAGED_VMS:
                environment = 'Managed VMs'
                msg = 'Use `gcloud compute ssh` for Managed VMs instances.'
            else:
                environment = 'Standard'
                msg = None
            raise command_exceptions.InvalidInstanceTypeError(environment, msg)
        res = resources.REGISTRY.Parse(
            args.instance,
            params={
                'appsId': properties.VALUES.core.project.GetOrFail,
                'versionsId': args.version,
                'instancesId': args.instance,
                'servicesId': args.service,
            },
            collection='appengine.apps.services.versions.instances')
        rel_name = res.RelativeName()
        try:
            instance = api_client.GetInstanceResource(res)
        except api_exceptions.NotFoundError:
            raise command_exceptions.MissingInstanceError(rel_name)

        if not instance.vmDebugEnabled:
            log.warn(ENABLE_DEBUG_WARNING)
            console_io.PromptContinue(cancel_on_no=True,
                                      throw_if_unattended=True)
        user = ssh.GetDefaultSshUsername()
        remote = ssh.Remote(instance.vmIp, user=user)
        public_key = keys.GetPublicKey().ToEntry()
        ssh_key = '{user}:{key} {user}'.format(user=user, key=public_key)
        log.status.Print(
            'Sending public key to instance [{}].'.format(rel_name))
        api_client.DebugInstance(res, ssh_key)
        options = {
            'IdentitiesOnly':
            'yes',  # No ssh-agent as of yet
            'UserKnownHostsFile':
            ssh.KnownHosts.DEFAULT_PATH,
            'CheckHostIP':
            'no',
            'HostKeyAlias':
            HOST_KEY_ALIAS.format(project=api_client.project,
                                  instance_id=args.instance)
        }
        cmd = ssh.SSHCommand(remote,
                             identity_file=keys.key_file,
                             options=options)
        if args.container:
            cmd.tty = True
            cmd.remote_command = ['container_exec', args.container, '/bin/sh']
        return cmd.Run(env)