Esempio n. 1
0
    def Run(self, args):
        """See ssh_utils.BaseSSHCLICommand.Run."""
        holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
        client = holder.client

        ssh_helper = ssh_utils.BaseSSHCLIHelper()
        ssh_helper.Run(args)
        user, instance_name = ssh_utils.GetUserAndInstance(args.user_host)
        instance_ref = instance_flags.SSH_INSTANCE_RESOLVER.ResolveResources(
            [instance_name],
            compute_scope.ScopeEnum.ZONE,
            args.zone,
            holder.resources,
            scope_lister=instance_flags.GetInstanceZoneScopeLister(client))[0]
        instance = ssh_helper.GetInstance(client, instance_ref)
        project = ssh_helper.GetProject(client, instance_ref.project)
        if args.plain:
            use_oslogin = False
        else:
            public_key = ssh_helper.keys.GetPublicKey().ToEntry(
                include_comment=True)
            user, use_oslogin = ssh.CheckForOsloginAndGetUser(
                instance, project, user, public_key, self.ReleaseTrack())
        if args.internal_ip:
            ip_address = ssh_utils.GetInternalIPAddress(instance)
        else:
            ip_address = ssh_utils.GetExternalIPAddress(instance)

        remote = ssh.Remote(ip_address, user)

        identity_file = None
        options = None
        if not args.plain:
            identity_file = ssh_helper.keys.key_file
            options = ssh_helper.GetConfig(ssh_utils.HostKeyAlias(instance),
                                           args.strict_host_key_checking)

        extra_flags = ssh.ParseAndSubstituteSSHFlags(args, remote, ip_address)
        remainder = []

        if args.ssh_args:
            remainder.extend(args.ssh_args)

        # Transform args.command into arg list or None if no command
        command_list = args.command.split(' ') if args.command else None
        tty = containers.GetTty(args.container, command_list)
        remote_command = containers.GetRemoteCommand(args.container,
                                                     command_list)

        target_remote = remote
        port = ssh_utils.DEFAULT_SSH_PORT
        ip_type = (ip.IpTypeEnum.INTERNAL
                   if args.internal_ip else ip.IpTypeEnum.EXTERNAL)
        tunnel_helper = None
        interface = None
        if hasattr(args, 'tunnel_through_iap') and args.tunnel_through_iap:
            tunnel_helper, interface = ssh_utils.CreateIapTunnelHelper(
                args, instance_ref, instance, ip_type)
            tunnel_helper.StartListener()
            target_remote = ssh.Remote('localhost', user)
            port = tunnel_helper.GetLocalPort()

        cmd = ssh.SSHCommand(target_remote,
                             port=str(port),
                             identity_file=identity_file,
                             options=options,
                             extra_flags=extra_flags,
                             remote_command=remote_command,
                             tty=tty,
                             remainder=remainder)
        if args.dry_run:
            log.out.Print(' '.join(cmd.Build(ssh_helper.env)))
            if tunnel_helper:
                tunnel_helper.StopListener()
            return

        if args.plain or use_oslogin:
            keys_newly_added = False
        else:
            keys_newly_added = ssh_helper.EnsureSSHKeyExists(
                client, remote.user, instance, project)

        if keys_newly_added:
            poller_tunnel_helper = None
            if tunnel_helper:
                poller_tunnel_helper, _ = ssh_utils.CreateIapTunnelHelper(
                    args, instance_ref, instance, ip_type, interface=interface)
                poller_tunnel_helper.StartListener(
                    accept_multiple_connections=True)
            poller = ssh_utils.CreateSSHPoller(remote,
                                               identity_file,
                                               options,
                                               poller_tunnel_helper,
                                               extra_flags=extra_flags)

            log.status.Print('Waiting for SSH key to propagate.')
            # TODO(b/35355795): Don't force_connect
            try:
                poller.Poll(ssh_helper.env, force_connect=True)
            except retry.WaitException:
                if tunnel_helper:
                    tunnel_helper.StopListener()
                raise ssh_utils.NetworkError()
            finally:
                if poller_tunnel_helper:
                    poller_tunnel_helper.StopListener()

        if args.internal_ip and not tunnel_helper:
            # The IAP Tunnel connection uses instance name and network interface name,
            # so do not need to additionally verify the instance.  Also, the
            # SSHCommand used within the function does not support IAP Tunnels.
            ssh_helper.PreliminarilyVerifyInstance(instance.id, remote,
                                                   identity_file, options)

        try:
            # Errors from SSH itself result in an ssh.CommandError being raised
            return_code = cmd.Run(ssh_helper.env, force_connect=True)
        finally:
            if tunnel_helper:
                tunnel_helper.StopListener()
        if return_code:
            # This is the return code of the remote command.  Problems with SSH itself
            # will result in ssh.CommandError being raised above.
            sys.exit(return_code)
Esempio n. 2
0
    def RunScp(self,
               compute_holder,
               args,
               port=None,
               recursive=False,
               compress=False,
               extra_flags=None,
               release_track=None,
               ip_type=ip.IpTypeEnum.EXTERNAL):
        """SCP files between local and remote GCE instance.

    Run this method from subclasses' Run methods.

    Args:
      compute_holder: The ComputeApiHolder.
      args: argparse.Namespace, the args the command was invoked with.
      port: str or None, Port number to use for SSH connection.
      recursive: bool, Whether to use recursive copying using -R flag.
      compress: bool, Whether to use compression.
      extra_flags: [str] or None, extra flags to add to command invocation.
      release_track: obj, The current release track.
      ip_type: IpTypeEnum, Specify using internal ip or external ip address.

    Raises:
      ssh_utils.NetworkError: Network issue which likely is due to failure
        of SSH key propagation.
      ssh.CommandError: The SSH command exited with SSH exit code, which
        usually implies that a connection problem occurred.
    """
        if release_track is None:
            release_track = base.ReleaseTrack.GA
        super(BaseScpHelper, self).Run(args)

        dst = ssh.FileReference.FromPath(args.destination)
        srcs = [ssh.FileReference.FromPath(src) for src in args.sources]

        # Make sure we have a unique remote
        ssh.SCPCommand.Verify(srcs, dst, single_remote=True)

        remote = dst.remote or srcs[0].remote
        if not dst.remote:  # Make sure all remotes point to the same ref
            for src in srcs:
                src.remote = remote

        instance_ref = instance_flags.SSH_INSTANCE_RESOLVER.ResolveResources(
            [remote.host],
            compute_scope.ScopeEnum.ZONE,
            args.zone,
            compute_holder.resources,
            scope_lister=instance_flags.GetInstanceZoneScopeLister(
                compute_holder.client))[0]
        instance = self.GetInstance(compute_holder.client, instance_ref)
        project = self.GetProject(compute_holder.client, instance_ref.project)

        if not remote.user:
            remote.user = ssh.GetDefaultSshUsername(warn_on_account_user=True)
        if args.plain:
            use_oslogin = False
        else:
            public_key = self.keys.GetPublicKey().ToEntry(include_comment=True)
            remote.user, use_oslogin = ssh.CheckForOsloginAndGetUser(
                instance, project, remote.user, public_key, release_track)

        identity_file = None
        options = None
        if not args.plain:
            identity_file = self.keys.key_file
            options = self.GetConfig(ssh_utils.HostKeyAlias(instance),
                                     args.strict_host_key_checking)

        tunnel_helper = None
        cmd_port = port
        if hasattr(args, 'tunnel_through_iap') and args.tunnel_through_iap:
            tunnel_helper = ssh_utils.CreateIapTunnelHelper(args,
                                                            instance_ref,
                                                            instance,
                                                            port=port)
            tunnel_helper.StartListener()
            cmd_port = str(tunnel_helper.GetLocalPort())
            if dst.remote:
                dst.remote.host = 'localhost'
            else:
                for src in srcs:
                    src.remote.host = 'localhost'
        else:
            # Now replace the instance name with the actual IP/hostname
            if ip_type is ip.IpTypeEnum.INTERNAL:
                remote.host = ssh_utils.GetInternalIPAddress(instance)
            else:
                remote.host = ssh_utils.GetExternalIPAddress(instance)

        cmd = ssh.SCPCommand(srcs,
                             dst,
                             identity_file=identity_file,
                             options=options,
                             recursive=recursive,
                             compress=compress,
                             port=cmd_port,
                             extra_flags=extra_flags)

        if args.dry_run:
            log.out.Print(' '.join(cmd.Build(self.env)))
            if tunnel_helper:
                tunnel_helper.StopListener()
            return

        if args.plain or use_oslogin:
            keys_newly_added = False
        else:
            keys_newly_added = self.EnsureSSHKeyExists(compute_holder.client,
                                                       remote.user, instance,
                                                       project)

        if keys_newly_added:
            poller_tunnel_helper = None
            if tunnel_helper:
                poller_tunnel_helper = ssh_utils.CreateIapTunnelHelper(
                    args, instance_ref, instance, port=port)
                poller_tunnel_helper.StartListener(
                    accept_multiple_connections=True)
            poller = ssh_utils.CreateSSHPoller(remote,
                                               identity_file,
                                               options,
                                               poller_tunnel_helper,
                                               port=port)

            log.status.Print('Waiting for SSH key to propagate.')
            # TODO(b/35355795): Don't force_connect
            try:
                poller.Poll(self.env, force_connect=True)
            except retry.WaitException:
                if tunnel_helper:
                    tunnel_helper.StopListener()
                raise ssh_utils.NetworkError()
            finally:
                if poller_tunnel_helper:
                    poller_tunnel_helper.StopListener()

        if ip_type is ip.IpTypeEnum.INTERNAL and not tunnel_helper:
            # The IAP Tunnel connection uses instance name and network interface name,
            # so do not need to additionally verify the instance. Also, the
            # SSHCommand used within the function does not support IAP Tunnels.
            self.PreliminarilyVerifyInstance(instance.id, remote,
                                             identity_file, options)

        try:
            # Errors from the SCP command result in an ssh.CommandError being raised
            cmd.Run(self.env, force_connect=True)
        finally:
            if tunnel_helper:
                tunnel_helper.StopListener()