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)
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)