def testSingleInternalNic(self):
     instance = self.messages.Instance(
         name='instance-1',
         zone='zone-1',
         networkInterfaces=[self.internal_nic])
     ip_result = ssh_utils.GetInternalIPAddress(instance)
     self.assertEqual(self.internal_ip_address, ip_result)
     self.assertIs(ssh_utils.GetInternalInterface(instance),
                   self.internal_nic)
 def testMultipleNics(self):
     instance = self.messages.Instance(
         name='instance-1',
         zone='zone-1',
         networkInterfaces=[self.internal_nic, self.external_nic])
     self.assertEqual(ssh_utils.GetExternalIPAddress(instance),
                      self.external_ip_address)
     self.assertIs(ssh_utils.GetExternalInterface(instance),
                   self.external_nic)
     self.assertEqual(ssh_utils.GetInternalIPAddress(instance),
                      self.internal_ip_address)
     self.assertIs(ssh_utils.GetInternalInterface(instance),
                   self.internal_nic)
Beispiel #3
0
  def _GetTargetArgs(self, args):
    holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
    client = holder.client
    ssh_helper = ssh_utils.BaseSSHCLIHelper()

    instance_ref = flags.SSH_INSTANCE_RESOLVER.ResolveResources(
        [args.instance_name], scope.ScopeEnum.ZONE, args.zone, holder.resources,
        scope_lister=flags.GetInstanceZoneScopeLister(client))[0]
    instance_obj = ssh_helper.GetInstance(client, instance_ref)

    project = instance_ref.project
    zone = instance_ref.zone
    instance = instance_obj.name
    port = args.instance_port
    interface = ssh_utils.GetInternalInterface(instance_obj).name

    return project, zone, instance, interface, port
    def _GetTargetArgs(self, args):
        # TODO(b/190426150): change to just "IsSpecified" when going to GA
        if args.IsKnownAndSpecified('network') and args.IsKnownAndSpecified(
                'region'):
            return _CreateTargetArgs(
                project=properties.VALUES.core.project.GetOrFail(),
                region=args.region,
                network=args.network,
                host=args.instance_name,
                port=args.instance_port,
                dest_group=args.dest_group,
                zone=None,
                instance=None,
                interface=None)

        if self._ShouldFetchInstanceAfterConnectError(args.zone):
            # Do not fetch instance prior to connecting.
            return _CreateTargetArgs(
                project=properties.VALUES.core.project.GetOrFail(),
                zone=args.zone,
                instance=args.instance_name,
                interface='nic0',
                port=args.instance_port,
                region=None,
                network=None,
                host=None,
                dest_group=None)

        instance_ref, instance_obj = self._FetchInstance(args)

        return _CreateTargetArgs(
            project=instance_ref.project,
            zone=instance_ref.zone,
            instance=instance_obj.name,
            interface=ssh_utils.GetInternalInterface(instance_obj).name,
            port=args.instance_port,
            region=None,
            network=None,
            host=None,
            dest_group=None)
    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 self.get_host_keys:
            host_keys = ssh_helper.GetHostKeysFromGuestAttributes(
                client, instance_ref)
            if not host_keys:
                log.warning(
                    'Unable to retrieve host keys from instance metadata. '
                    'Continuing.')
        else:
            host_keys = {}
        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())

        iap_tunnel_args = iap_tunnel.SshTunnelArgs.FromArgs(
            args, self.ReleaseTrack(), instance_ref,
            ssh_utils.GetInternalInterface(instance),
            ssh_utils.GetExternalInterface(instance, no_raise=True))

        if iap_tunnel_args:
            # IAP Tunnel only uses ip_address for the purpose of --ssh-flag
            # substitution. In this case, dest_addr doesn't do much, it just matches
            # against entries in the user's ssh_config file. It's best to use
            # something unique to avoid false positive matches, thus we use
            # HostKeyAlias.
            ip_address = ssh_utils.GetInternalIPAddress(instance)
            dest_addr = ssh_utils.HostKeyAlias(instance)
        elif args.internal_ip:
            ip_address = ssh_utils.GetInternalIPAddress(instance)
            dest_addr = ip_address
        else:
            ip_address = ssh_utils.GetExternalIPAddress(instance)
            dest_addr = ip_address
        remote = ssh.Remote(dest_addr, 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,
                                           host_keys_to_add=host_keys)

        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)

        # Do not include default port since that will prevent users from
        # specifying a custom port (b/121998342).
        ssh_cmd_args = {
            'remote': remote,
            'identity_file': identity_file,
            'options': options,
            'extra_flags': extra_flags,
            'remote_command': remote_command,
            'tty': tty,
            'iap_tunnel_args': iap_tunnel_args,
            'remainder': remainder
        }

        cmd = ssh.SSHCommand(**ssh_cmd_args)

        if args.dry_run:
            log.out.Print(' '.join(cmd.Build(ssh_helper.env)))
            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 = ssh_utils.CreateSSHPoller(remote,
                                               identity_file,
                                               options,
                                               iap_tunnel_args,
                                               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:
                raise ssh_utils.NetworkError()

        if args.internal_ip:
            ssh_helper.PreliminarilyVerifyInstance(instance.id, remote,
                                                   identity_file, options)

        # Errors from SSH itself result in an ssh.CommandError being raised
        return_code = cmd.Run(ssh_helper.env, force_connect=True)
        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)
Beispiel #6
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)

        iap_tunnel_args = iap_tunnel.SshTunnelArgs.FromArgs(
            args, release_track, instance_ref,
            ssh_utils.GetInternalInterface(instance),
            ssh_utils.GetExternalInterface(instance, no_raise=True))

        if iap_tunnel_args:
            remote.host = ssh_utils.HostKeyAlias(instance)
        elif 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=port,
                             extra_flags=extra_flags,
                             iap_tunnel_args=iap_tunnel_args)

        if args.dry_run:
            log.out.Print(' '.join(cmd.Build(self.env)))
            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 = ssh_utils.CreateSSHPoller(remote,
                                               identity_file,
                                               options,
                                               iap_tunnel_args,
                                               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:
                raise ssh_utils.NetworkError()

        if ip_type is ip.IpTypeEnum.INTERNAL:
            # This will never happen when IAP Tunnel is enabled, because ip_type is
            # always EXTERNAL when IAP Tunnel is enabled, even if the instance has no
            # external IP. IAP Tunnel doesn't need verification because it uses
            # unambiguous identifiers for the instance.
            self.PreliminarilyVerifyInstance(instance.id, remote,
                                             identity_file, options)

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