def delete_log(cls, nodename, grpc_uri, auto_pw_request=False, user=None, pw=None):
        '''
        Deletes the log file associated with the given node.

        :param  str nodename: the name of the node (with name space)
        :param str grpc_uri: uri of the node manager daemon where to delete log
        :raise Exception: on errors while resolving host
        :see: :meth:`fkie_node_manager.is_local()`
        '''
        try:
            nm.nmd().screen.delete_log(grpc_uri, [nodename])
        except Exception as err:
            rospy.logwarn("delete log using SSH because of error: %s" % utf8(err))
            host = get_hostname(grpc_uri)
            if nm.is_local(host):
                screenLog = screen.get_logfile(node=nodename)
                pidFile = screen.get_pidfile(node=nodename)
                roslog = screen.get_ros_logfile(nodename)
                if os.path.isfile(screenLog):
                    os.remove(screenLog)
                if os.path.isfile(pidFile):
                    os.remove(pidFile)
                if os.path.isfile(roslog):
                    os.remove(roslog)
            else:
                try:
                    # output ignored: output, error, ok
                    _, stdout, _, ok = nm.ssh().ssh_exec(host, [nm.settings().start_remote_script, '--delete_logs', nodename], user, pw, auto_pw_request, close_stdin=True, close_stdout=False, close_stderr=True)
                    if ok:
                        stdout.readlines()
                        stdout.close()
                except nm.AuthenticationRequest as e:
                    raise nm.InteractionNeededError(e, cls.delete_log, {'nodename': nodename, 'grpc_uri': host, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw})
Example #2
0
 def kill_screens(cls,
                  node,
                  grpc_url,
                  auto_ok_request=True,
                  user=None,
                  pw=None):
     '''
     Searches for the screen associated with the given node and kill this screens.
     :param str node: the name of the node those screen output to kill
     :param str grpc_url: the url of node manager daemon where the screen is running
     '''
     if node is None or len(node) == 0:
         return False
     try:
         # get the available screens
         screens = nm.nmd().screen.get_screens(grpc_url, node)
         if screens:
             do_kill = True
             if auto_ok_request:
                 from fkie_node_manager.detailed_msg_box import MessageBox
                 result = MessageBox.question(
                     None,
                     "Kill SCREENs?",
                     '\n'.join(list(screens.keys())),
                     buttons=MessageBox.Ok | MessageBox.Cancel)
                 if result == MessageBox.Ok:
                     do_kill = True
             if do_kill:
                 host = get_hostname(grpc_url)
                 for sname, _nname in screens.items():
                     pid, _, _ = sname.partition('.')
                     if pid:
                         try:
                             nm.nmd().monitor.kill_process(
                                 int(pid), grpc_url)
                             # nm.starter()._kill_wo(host, int(pid), auto_ok_request, user, pw)
                         except Exception:
                             import traceback
                             rospy.logwarn(
                                 "Error while kill screen (PID: %s) on host '%s': %s",
                                 utf8(pid), utf8(host),
                                 traceback.format_exc(1))
                 nm.nmd().screen.wipe_screens(grpc_url)
                 # if nm.is_local(host):
                 #     SupervisedPopen([screen.SCREEN, '-wipe'], object_id='screen -wipe', description="screen: clean up the socket with -wipe")
                 # else:
                 #     nm.ssh().ssh_exec(host, [screen.SCREEN, '-wipe'], close_stdin=True, close_stdout=True, close_stderr=True)
     except nm.AuthenticationRequest as e:
         raise nm.InteractionNeededError(
             e, cls.kill_screens, {
                 'node': node,
                 'grpc_url': grpc_url,
                 'auto_ok_request': auto_ok_request,
                 'user': user,
                 'pw': pw
             })
 def rosclean(self, grpc_uri, auto_pw_request=False, user=None, pw=None):
     '''
     rosclean purge on given host.
     :param str grpc_uri: the address of the node manager daemon where rosclean is called.
     :raise StartException: on error
     :raise Exception: on errors while resolving host
     :see: L{fkie_node_manager.is_local()}
     '''
     try:
         self._rosclean_wo(grpc_uri, auto_pw_request, user, pw)
     except nm.AuthenticationRequest as e:
         raise nm.InteractionNeededError(e, self.rosclean, {'grpc_uri': grpc_uri, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw})
    def poweroff(self, host, auto_pw_request=False, user=None, pw=None):
        '''
        poweroff given host.

        :param str host: the name or address of the host, where the process must be killed.
        :raise StartException: on error
        :raise Exception: on errors while resolving host
        :see: :meth:`fkie_node_manager.is_local()`
        '''
        try:
            self._poweroff_wo(host, auto_pw_request, user, pw)
        except nm.AuthenticationRequest as e:
            raise nm.InteractionNeededError(e, self.poweroff, {'host': host, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw})
Example #5
0
    def killall_roscore(self, host, auto_pw_request=False, user=None, pw=None):
        '''
        Kills all roscore processes on given host.

        :param str host: the name or address of the host, where the process must be killed.
        :raise StartException: on error
        :raise Exception: on errors while resolving host
        :see: :meth:`fkie_node_manager.is_local()`
        '''
        try:
            self._killall_roscore_wo(host, auto_pw_request, user, pw)
        except nm.AuthenticationRequest as e:
            raise nm.InteractionNeededError(e, self.killall_roscore,
                                            (host, auto_pw_request))
 def get_log_path(cls,
                  host,
                  nodes=[],
                  auto_pw_request=False,
                  user=None,
                  pw=None):
     if nm.is_local(host):
         if len(nodes) == 1:
             return screen.get_logfile(node=nodes[0])
         else:
             return screen.LOG_PATH
     else:
         request = '[]' if len(nodes) != 1 else nodes[0]
         try:
             socket.setdefaulttimeout(3)
             _, stdout, _, ok = nm.ssh().ssh_exec(host, [
                 nm.settings().start_remote_script, '--ros_log_path',
                 request
             ],
                                                  user,
                                                  pw,
                                                  auto_pw_request,
                                                  close_stdin=True,
                                                  close_stderr=True)
             if ok:
                 output = stdout.read()
                 stdout.close()
                 return output.strip()
             else:
                 raise StartException(
                     utf8(''.join(['Get log path from "', host,
                                   '" failed'])))
         except nm.AuthenticationRequest as e:
             raise nm.InteractionNeededError(
                 e, cls.get_log_path, {
                     'host': host,
                     'nodes': nodes,
                     'auto_pw_request': auto_pw_request,
                     'user': user,
                     'pw': pw
                 })
         finally:
             socket.setdefaulttimeout(None)
 def transfer_files(cls, host, path, auto_pw_request=False, user=None, pw=None):
     '''
     Copies the given file to the remote host. Uses caching of remote paths.
     '''
     # get package of the file
     if nm.is_local(host):
         # it's local -> no copy needed
         return
     (pkg_name, pkg_path) = package_name(os.path.dirname(path))
     if pkg_name is not None:
         # get the subpath of the file
         subfile_path = path.replace(pkg_path, '')
         # get the path of the package on the remote machine
         try:
             output = ''
             error = ''
             ok = True
             if host in CACHED_PKG_PATH and pkg_name in CACHED_PKG_PATH[host]:
                 output = CACHED_PKG_PATH[host][pkg_name]
             else:
                 if host not in CACHED_PKG_PATH:
                     CACHED_PKG_PATH[host] = dict()
                 _, stdout, stderr, ok = nm.ssh().ssh_exec(host, [nm.settings().start_remote_script, '--package', pkg_name], user, pw, auto_pw_request, close_stdin=True)
                 output = stdout.read()
                 error = stderr.read()
                 stdout.close()
                 stderr.close()
             if ok:
                 if error:
                     rospy.logwarn("ERROR while transfer %s to %s: %s", path, host, error)
                     raise StartException(utf8(''.join(['The host "', host, '" reports:\n', error])))
                 if output:
                     CACHED_PKG_PATH[host][pkg_name] = output
                     nm.ssh().transfer(host, path, os.path.join(output.strip(), subfile_path.strip(os.sep)), user)
                 else:
                     raise StartException("Remote host no returned any answer. Is there the new version of node_manager installed?")
             else:
                 raise StartException("Can't get path from remote host. Is there the new version of node_manager installed?")
         except nm.AuthenticationRequest as e:
             raise nm.InteractionNeededError(e, cls.transfer_files, {'host': host, 'path': path, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw})
    def bc_run_node(cls,
                    name,
                    grpc_path='grpc://localhost:12321',
                    masteruri='',
                    reload_global_param=False,
                    loglevel='',
                    logformat='',
                    auto_pw_request=False,
                    user=None,
                    pw=None):
        '''
        Start the node with given name from the given configuration.

        :param runcfg: the configuration containing the start parameter
        :type runcfg: AdvRunCfg
        :raise StartException: if the screen is not available on host.
        :raise Exception: on errors while resolving host
        :see: :meth:`fkie_node_manager.is_local()`
        '''
        startcfg = nm.nmd().launch.get_start_cfg(
            name,
            grpc_path,
            masteruri,
            reload_global_param=reload_global_param,
            loglevel=loglevel,
            logformat=logformat)
        new_env = dict(startcfg.env)
        # set logging options
        if startcfg.namespace:
            new_env['ROS_NAMESPACE'] = startcfg.namespace
        # set logging
        if startcfg.logformat:
            new_env['ROSCONSOLE_FORMAT'] = '%s' % startcfg.logformat
#         if startcfg.loglevel:
#             new_env['ROSCONSOLE_CONFIG_FILE'] = launcher._rosconsole_cfg_file(startcfg.package, startcfg.loglevel)
        args = []
        # set name and namespace of the node
        if startcfg.name:
            args.append("__name:=%s" % startcfg.name)
        if startcfg.namespace:
            args.append("__ns:=%s" % startcfg.namespace)
        # add remap arguments
        for key, val in startcfg.remaps.items():
            args.append("%s:=%s" % (key, val))
        # handle respawn
        if startcfg.respawn:
            if startcfg.respawn_delay > 0:
                new_env['RESPAWN_DELAY'] = '%d' % startcfg.respawn_delay
            respawn_params = launcher._get_respawn_params(
                startcfg.fullname, startcfg.params)
            if respawn_params['max'] > 0:
                new_env['RESPAWN_MAX'] = '%d' % respawn_params['max']
            if respawn_params['min_runtime'] > 0:
                new_env['RESPAWN_MIN_RUNTIME'] = '%d' % respawn_params[
                    'min_runtime']
        if startcfg.cwd:
            cwd = get_cwd(startcfg.cwd, startcfg.binary_path)
            if cwd:
                args.append('__cwd:=%s' % cwd)
        # check for masteruri
        masteruri = startcfg.masteruri
        on_hostname = startcfg.hostname
        if masteruri is None:
            masteruri = masteruri_from_ros()
        if masteruri is not None:
            new_env['ROS_MASTER_URI'] = masteruri
            if 'ROS_HOSTNAME' in os.environ:
                # set only ROS_HOSTNAME if node manager have also one
                ros_hostname = nmdhost.get_ros_hostname(masteruri, on_hostname)
                if ros_hostname:
                    new_env['ROS_HOSTNAME'] = ros_hostname
            # load params to ROS master
            launcher._load_parameters(masteruri, startcfg.params,
                                      startcfg.clear_params)

        abs_paths = list()  # tuples of (parameter name, old value, new value)
        not_found_packages = list()  # package names
        #         # set the global parameter
        #         if runcfg.masteruri is not None and runcfg.masteruri not in runcfg.roslaunch_config.global_param_done:
        #             global_node_names = cls.getGlobalParams(runcfg.roslaunch_config.Roscfg)
        #             rospy.loginfo("Register global parameter:\n  %s", '\n  '.join("%s%s" % (utf8(v)[:80], '...' if len(utf8(v)) > 80 else'') for v in global_node_names.values()))
        #             abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(runcfg.masteruri, global_node_names, [], runcfg.user, runcfg.pw, runcfg.auto_pw_request)
        #             runcfg.roslaunch_config.global_param_done.append(runcfg.masteruri)
        #
        #         # add params
        #         if runcfg.masteruri is not None:
        #             nodens = ''.join([n.namespace, n.name, rospy.names.SEP])
        #             params = dict()
        #             for param, value in runcfg.roslaunch_config.Roscfg.params.items():
        #                 if param.startswith(nodens):
        #                     params[param] = value
        #             clear_params = []
        #             for cparam in runcfg.roslaunch_config.Roscfg.clear_params:
        #                 if cparam.startswith(nodens):
        #                     clear_params.append(cparam)
        #             rospy.loginfo("Delete parameter:\n  %s", '\n  '.join(clear_params))
        #             rospy.loginfo("Register parameter:\n  %s", '\n  '.join("%s%s" % (utf8(v)[:80], '...' if len(utf8(v)) > 80 else'') for v in params.values()))
        #             abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(runcfg.masteruri, params, clear_params, runcfg.user, runcfg.pw, runcfg.auto_pw_request)
        if not nm.is_local(on_hostname, wait=True):
            # start remote
            if not startcfg.package:
                raise StartException(
                    "Can't run remote without a valid package name!")
            # setup environment
            env_command = ''
            if new_env:
                try:
                    for k, v in new_env.items():
                        v_value, is_abs_path, found, package = cls._bc_resolve_abs_paths(
                            v, on_hostname, auto_pw_request, user, pw)
                        new_env[k] = v_value
                        if is_abs_path:
                            abs_paths.append(('ENV', "%s=%s" % (k, v),
                                              "%s=%s" % (k, v_value)))
                            if not found and package:
                                not_found_packages.append(package)
                    env_command = "env " + ' '.join(
                        ["%s=\'%s\'" % (k, v) for (k, v) in new_env.items()])
                except nm.AuthenticationRequest as e:
                    raise nm.InteractionNeededError(
                        e, cls.bc_run_node, {
                            'name': name,
                            'grpc_path': grpc_path,
                            'masteruri': masteruri,
                            'reload_global_param': reload_global_param,
                            'loglevel': loglevel,
                            'logformat': logformat,
                            'auto_pw_request': auto_pw_request,
                            'user': user,
                            'pw': pw
                        })
            startcmd = [
                env_command,
                nm.settings().start_remote_script, '--package',
                utf8(startcfg.package), '--node_type',
                utf8(startcfg.binary), '--node_name',
                utf8(startcfg.fullname),
                '--node_respawn true' if startcfg.respawn else ''
            ]
            if startcfg.masteruri is not None:
                startcmd.append('--masteruri')
                startcmd.append(startcfg.masteruri)
            if startcfg.prefix:
                startcmd[len(startcmd):] = ['--prefix', startcfg.prefix]
            if startcfg.loglevel:
                startcmd.append('--loglevel')
                startcmd.append(startcfg.loglevel)

            # rename the absolute paths in the args of the node
            node_args = []
            error = ''
            output = ''
            try:
                for a in startcfg.args:
                    a_value, is_abs_path, found, package = cls._bc_resolve_abs_paths(
                        a, on_hostname, auto_pw_request, user, pw)
                    node_args.append(a_value)
                    if is_abs_path:
                        abs_paths.append(('ARGS', a, a_value))
                        if not found and package:
                            not_found_packages.append(package)

                startcmd[len(startcmd):] = node_args
                startcmd[len(startcmd):] = args
                rospy.loginfo("Run remote on %s: %s", on_hostname,
                              utf8(' '.join(startcmd)))
                _, stdout, stderr, ok = nm.ssh().ssh_exec(on_hostname,
                                                          startcmd,
                                                          user,
                                                          pw,
                                                          auto_pw_request,
                                                          close_stdin=True)
                output = stdout.read()
                error = stderr.read()
                stdout.close()
                stderr.close()
            except nm.AuthenticationRequest as e:
                raise nm.InteractionNeededError(
                    e, cls.bc_run_node, {
                        'name': name,
                        'grpc_path': grpc_path,
                        'masteruri': masteruri,
                        'reload_global_param': reload_global_param,
                        'loglevel': loglevel,
                        'logformat': logformat,
                        'auto_pw_request': auto_pw_request,
                        'user': user,
                        'pw': pw
                    })
            if ok:
                if error:
                    rospy.logwarn("ERROR while start '%s': %s",
                                  startcfg.fullname, error)
                    raise StartException(
                        utf8(''.join(
                            ['The host "', on_hostname, '" reports:\n',
                             error])))
                if output:
                    rospy.logdebug("STDOUT while start '%s': %s",
                                   startcfg.fullname, output)
            # inform about absolute paths in parameter value
            if len(abs_paths) > 0:
                rospy.loginfo(
                    "Absolute paths found while start:\n%s",
                    utf8('\n'.join([
                        ''.join([p, '\n  OLD: ', ov, '\n  NEW: ', nv])
                        for p, ov, nv in abs_paths
                    ])))

            if len(not_found_packages) > 0:
                packages = '\n'.join(not_found_packages)
                raise StartException(
                    utf8('\n'.join([
                        'Some absolute paths are not renamed because following packages are not found on remote host:',
                        packages
                    ])))
    def runNodeWithoutConfig(cls,
                             host,
                             package,
                             binary,
                             name,
                             args=[],
                             masteruri=None,
                             use_nmd=True,
                             auto_pw_request=False,
                             user=None,
                             pw=None,
                             path=''):
        '''
        Start a node with using a launch configuration.

        :param str hosturi: the host or ip to run the node
        :param str package: the ROS package containing the binary
        :param str binary: the binary of the node to execute
        :param str name: the ROS name of the node (with name space)
        :param args: the list with arguments passed to the binary
        :type args: [str]
        :param bool use_nmd: start the node using node manager daemon
        :param bool auto_pw_request: opens question dialog directly, use True only if the method is called from the main GUI thread
        :raise Exception: on errors while resolving host
        :see: :meth:`fkie_node_manager.is_local()`
        '''
        # create the name with namespace
        args2 = list(args)
        fullname = roslib.names.ns_join(roslib.names.SEP, name)
        namespace = ''
        for a in args:
            if a.startswith('__ns:='):
                namespace = a.replace('__ns:=', '')
                fullname = roslib.names.ns_join(namespace, name)
        args2.append(''.join(['__name:=', name]))
        # run on local host
        if nm.is_local(host, wait=True):
            if not use_nmd:
                if path:
                    cmd = [path]
                else:
                    try:
                        cmd = roslib.packages.find_node(package, binary)
                    except roslib.packages.ROSPkgException as e:
                        # multiple nodes, invalid package
                        raise StartException(utf8(e))
                    # handle different result types str or array of string
                    if isstring(cmd):
                        cmd = [cmd]
                cmd_type = ''
                if cmd is None or len(cmd) == 0:
                    raise StartException('%s in package [%s] not found!' %
                                         (binary, package))
                # compatibility for python scripts installed with catkin_install_python()
                # avoid ask for select a binary
                cmd = cls._remove_src_binary(cmd)
                if len(cmd) > 1:
                    # Open selection for executables
                    err = 'Multiple executables with same name in package [%s] found' % package
                    bsel = nm.BinarySelectionRequest(cmd, err)
                    raise nm.InteractionNeededError(
                        bsel, cls.runNodeWithoutConfig, {
                            'host': host,
                            'package': package,
                            'binary': binary,
                            'name': name,
                            'args': args,
                            'masteruri': masteruri,
                            'use_nmd': use_nmd,
                            'auto_pw_request': auto_pw_request,
                            'user': user,
                            'pw': pw,
                            'path': path
                        })
                else:
                    cmd_type = cmd[0]
            new_env = {}  # dict(os.environ)
            if namespace:
                new_env['ROS_NAMESPACE'] = namespace
            if masteruri is not None:
                cls._prepareROSMaster(masteruri)
                new_env['ROS_MASTER_URI'] = masteruri
                if 'ROS_HOSTNAME' in os.environ:
                    # set ROS_HOSTNAME only if node_manager has also one
                    ros_hostname = nmdhost.get_ros_hostname(masteruri, host)
                    if ros_hostname:
                        new_env['ROS_HOSTNAME'] = ros_hostname
            if use_nmd:
                nm.nmd().launch.start_standalone_node(nmdurl.nmduri(), package,
                                                      binary, name, namespace,
                                                      args, new_env, masteruri,
                                                      host)
            else:
                local_env = dict(os.environ)
                local_env.update(new_env)
                cmd_str = utf8(' '.join([
                    screen.get_cmd(fullname, local_env), cmd_type,
                    ' '.join(args2)
                ]))
                rospy.loginfo("Run without config: %s",
                              fullname if use_nmd else cmd_str)
                SupervisedPopen(shlex.split(cmd_str),
                                env=local_env,
                                object_id="Run without config",
                                description="Run without config [%s]%s" %
                                (utf8(package), utf8(binary)))
        else:
            # run on a remote machine
            startcmd = [
                nm.settings().start_remote_script, '--package',
                utf8(package), '--node_type',
                utf8(binary), '--node_name',
                utf8(fullname)
            ]
            startcmd[len(startcmd):] = args2
            if masteruri is not None:
                startcmd.append('--masteruri')
                startcmd.append(masteruri)
            rospy.loginfo("Run remote on %s: %s", host, ' '.join(startcmd))
            try:
                _, stdout, stderr, ok = nm.ssh().ssh_exec(host,
                                                          startcmd,
                                                          user,
                                                          pw,
                                                          auto_pw_request,
                                                          close_stdin=True)
                if ok:
                    output = stdout.read()
                    error = stderr.read()
                    stdout.close()
                    stderr.close()
                    if error:
                        rospy.logwarn("ERROR while start '%s': %s", name,
                                      error)
                        raise StartException(''.join(
                            ['The host "', host, '" reports:\n', error]))
                    if output:
                        if output.find("dn't") != -1:
                            rospy.logwarn("Warning while start '%s': %s", name,
                                          output)
                        else:
                            rospy.loginfo("STDOUT while start '%s': %s", name,
                                          output)
                else:
                    if error:
                        rospy.logwarn("ERROR while start '%s': %s", name,
                                      error)
                        raise StartException(''.join(
                            ['The host "', host, '" reports:\n', error]))
            except nm.AuthenticationRequest as e:
                raise nm.InteractionNeededError(
                    e, cls.runNodeWithoutConfig, {
                        'host': host,
                        'package': package,
                        'binary': binary,
                        'name': name,
                        'args': args,
                        'masteruri': masteruri,
                        'use_nmd': use_nmd,
                        'auto_pw_request': auto_pw_request,
                        'user': user,
                        'pw': pw,
                        'path': path
                    })
 def open_screen(cls,
                 node,
                 grpc_url,
                 auto_item_request=False,
                 use_log_widget=False,
                 user=None,
                 pw=None,
                 items=[],
                 use_nmd=True):
     '''
     Searches for the screen associated with the given node and open the screen
     output in a new terminal.
     :param str node: the name of the node those screen output to show
     :param str grpc_url: the url of node manager daemon where the screen is running
     :raise Exception: on errors while resolving host
     :see: L{open_screen_terminal()}
     '''
     if node is None or len(node) == 0:
         return False
     try:
         host = get_hostname(grpc_url)
         try:
             muri = url.masteruri(grpc_url)
         except ValueError:
             muri = host
         if items:
             for item in items:
                 # open the selected screen
                 cls.open_screen_terminal(muri, item, node, use_log_widget,
                                          user)
         else:
             # get the available screens
             screens = {}
             try:
                 if use_nmd:
                     screens = nm.nmd().screen.get_screens(grpc_url, node)
                 else:
                     screens = cls._bc_get_active_screens(host,
                                                          node,
                                                          False,
                                                          user=user,
                                                          pwd=pw)
             except grpc.RpcError as e:
                 rospy.logwarn(
                     "can not connect to node manager daemon, detect screens using ssh..."
                 )
                 screens = cls._bc_get_active_screens(host,
                                                      node,
                                                      False,
                                                      user=user,
                                                      pwd=pw)
             if len(screens) == 1:
                 cls.open_screen_terminal(muri,
                                          list(screens.keys())[0], node,
                                          use_log_widget, user)
             else:
                 # create a list to let the user make a choice, which screen must be open
                 choices = {}
                 for sname, _nname in screens.items():
                     pid, session_name = screen.split_session_name(sname)
                     choices['%s [%d]' % (session_name, pid)] = sname
                 # Open selection
                 if len(choices) > 0:
                     if len(choices) == 1:
                         cls.open_screen_terminal(muri,
                                                  choices[0],
                                                  node,
                                                  use_log_widget=False,
                                                  user=user)
                     elif auto_item_request:
                         from select_dialog import SelectDialog
                         items, _ = SelectDialog.getValue(
                             'Show screen',
                             '',
                             list(choices.keys()),
                             False,
                             store_geometry='show_screens')
                         for item in items:
                             # open the selected screen
                             cls.open_screen_terminal(muri,
                                                      choices[item],
                                                      node,
                                                      use_log_widget=False,
                                                      user=user)
                     else:
                         raise ScreenSelectionRequest(
                             choices, 'Show screen')
                 else:
                     if use_log_widget:
                         nm._MAIN_FORM.open_screen_dock(
                             muri, '', node, user)
                     raise nm.InteractionNeededError(
                         NoScreenOpenLogRequest(node, host),
                         nm.starter().openLog, (node, host, user))
             return len(screens) > 0
     except nm.AuthenticationRequest as e:
         raise nm.InteractionNeededError(
             e, cls.open_screen,
             (node, grpc_url, auto_item_request, use_log_widget))
     except ScreenSelectionRequest as e:
         # set use_log_widget to False on multiple screens for same node
         raise nm.InteractionNeededError(
             e, cls.open_screen,
             (node, grpc_url, auto_item_request, False, user, pw))