Example #1
0
    def update_countdown(self):
        """Update the countdown label."""
        self.timeleft -= 1
        if self.timeleft >= 0:
            self.lbl_countdown.set_text(
                _("Benchmark finishing in %d seconds...") % self.timeleft)
        else:
            self.lbl_countdown.set_text(
                _("Some clients didn't respond in time!") + "\n"
                + _("Waiting for %d more seconds...") % (self.timeleft + 3))

        # Always recall; the timeout will be cancelled in on_iperf_exit.
        return True
    def run(self, client, execute):
        """Show the dialog, then hide it so that it may be reused."""
        self.client = client

        inst = client[C_INSTANCE]
        handle = inst.hsystem or client[C_SESSION_HANDLE]

        self.lbl_type.set_text(inst.type)
        self.lbl_alias.set_text(inst.alias)
        self.lbl_hostname.set_text(inst.hostname)
        self.lbl_mac.set_text(inst.mac)
        self.lbl_ip.set_text(handle.split(':')[0])
        if client[C_SESSION_HANDLE]:
            uname, realname = inst.users[client[C_SESSION_HANDLE]].values()
            if realname:
                user = '******'.format(uname, realname)
            else:
                user = uname
        else:
            user = ''
        self.lbl_user.set_text(user)
        self.lbl_cpu.set_text('')
        self.lbl_ram.set_text('')
        self.lbl_vga.set_text('')
        if handle:
            execute(handle, 'echo "$CPU"').addCallback(
                self.cb_set_text, self.lbl_cpu)
            execute(handle, 'echo "$RAM MiB"').addCallback(
                self.cb_set_text, self.lbl_ram)
            execute(handle, 'echo "$VGA"').addCallback(
                self.cb_set_text, self.lbl_vga)
        # TODO: consider new string formatting vs updating translations
        self.dialog.set_title(_('Properties of %s') % inst.get_name())
        self.dialog.run()
        self.dialog.hide()
Example #3
0
 def on_imi_clients_remove_from_group_activate(self, _widget):
     """Handle imi_clients_remove_from_group.activate event."""
     clients = self.get_selected_clients()
     group = self.get_selected_group()[1]
     if self.confirmation_dialog(
             _('Are you sure you want to remove the selected client(s)'
               ' from group "%s"?') % group.name):
         for client in clients:
             group.remove_client(client[C_INSTANCE])
         self.fill_icon_view(self.get_selected_group()[1], True)
Example #4
0
 def warning_dialog(self, text):
     """Show a warning dialog."""
     dlg = Gtk.MessageDialog(self.mainwin,
                             0,
                             Gtk.MessageType.WARNING,
                             Gtk.ButtonsType.CLOSE,
                             text,
                             title=_('Warning'))
     dlg.run()
     dlg.destroy()
Example #5
0
 def disconnected(self, _daemon):
     """Called from uiconnection->Daemon->connectionLost."""
     self.mainwin.set_sensitive(False)
     # If the reactor is not running at this point it means that we were
     # closed normally.
     # noinspection PyUnresolvedReferences
     if not reactor.running:
         return
     self.save_settings()
     msg = _("Lost connection with the epoptes service.")
     msg += "\n\n" + \
            _("Make sure the service is running and then restart epoptes.")
     dlg = Gtk.MessageDialog(type=Gtk.MessageType.ERROR,
                             buttons=Gtk.ButtonsType.OK,
                             message_format=msg)
     dlg.set_title(_('Service connection error'))
     dlg.run()
     dlg.destroy()
     # noinspection PyUnresolvedReferences
     reactor.stop()
Example #6
0
    def on_btn_group_remove_clicked(self, _widget):
        """Handle btn_group_remove.clicked event."""
        group_iter = self.get_selected_group()[0]
        group = self.gstore[group_iter][G_INSTANCE]

        if self.confirmation_dialog(
                _('Are you sure you want to remove group "%s"?') % group.name):
            path = self.gstore.get_path(group_iter)[0]
            self.gstore.remove(group_iter)
            menuitem = self.mnu_add_to_group.get_children()[path - 1]
            self.mnu_add_to_group.remove(menuitem)
Example #7
0
 def confirmation_dialog(self, text):
     """Show a Yes/No dialog, returning True/False accordingly."""
     dlg = Gtk.MessageDialog(self.mainwin,
                             0,
                             Gtk.MessageType.WARNING,
                             Gtk.ButtonsType.YES_NO,
                             text,
                             title=_('Confirm action'))
     resp = dlg.run()
     dlg.destroy()
     return resp == Gtk.ResponseType.YES
Example #8
0
 def on_btn_group_add_clicked(self, _widget):
     """Handle btn_group_add.clicked event."""
     new_group = structs.Group(_('New group'), {})
     itr = self.gstore.append([new_group.name, new_group, True])
     # Edit the name of the newly created group
     self.trv_groups.set_cursor(self.gstore.get_path(itr),
                                self.get('tvc_group'), True)
     menuitem = Gtk.MenuItem(new_group.name)
     menuitem.show()
     menuitem.connect('activate', self.on_imi_clients_add_to_group_activate,
                      new_group)
     self.mnu_add_to_group.append(menuitem)
Example #9
0
 def __init__(self, summary, icon):
     """Initialize Notify and local variables."""
     if not NotifyQueue.initialized:
         NotifyQueue.initialized = True
         if not Notify.init("Epoptes"):
             raise ImportError(_('Could not initialize notifications!'))
     self.summary = summary
     self.icon = icon
     self.items = []
     # The heading of the last item enqueued
     self.last_heading = ''
     self.last_time = time.time()
     self.notification = None
Example #10
0
    def run(self, clients):
        """Show the dialog, then hide it so that it may be reused."""
        self.clients = {}
        # This can happen on an empty group.
        # Btw, "if not clients" is wrong as it's a Gtk.ListStore, not a dict.
        # pylint: disable=len-as-condition
        if len(clients) == 0:
            self.warning_message(
                _('There are no selected clients to run the benchmark on.'))
            return

        # Check if offline clients or clients with no root client are selected
        off = []
        for client in clients:
            inst = client[C_INSTANCE]
            if inst.hsystem:
                self.clients[inst.hsystem.split(':')[0]] =\
                    (inst.hsystem, inst.get_name())
            else:
                off.append(inst.get_name())

        # Now self.clients is the list of clients that can run the benchmark
        if not self.clients:
            self.warning_message(
                _('All of the selected clients are either offline,'
                  ' or do not have epoptes-client running as root.'))
            return
        if off:
            self.warning_message(
                _('The following clients will be excluded from the benchmark'
                  ' because they are either offline, or do not have'
                  ' epoptes-client running as root.')
                + '\n\n' + ', '.join(off))

        self.box_seconds.set_visible(True)
        self.box_countdown.set_visible(False)
        self.btn_start.set_visible(True)
        self.btn_stop.set_visible(False)
        self.dlg_benchmark.run()
Example #11
0
    def on_iperf_exit(self, out_data, err_data, reason):
        """The benchmark has finished, show the results dialog."""
        GLib.source_remove(self.countdown_event)
        self.box_seconds.set_visible(True)
        self.box_countdown.set_visible(False)
        self.btn_start.set_visible(True)
        self.btn_stop.set_visible(False)

        if reason == "stopped":
            self.btn_stop.set_sensitive(True)
            return
        elif reason == "closed":
            return

        self.dlg_benchmark.hide()
        self.parse_iperf_output(out_data.decode("utf-8"))
        if not self.results:
            msg = _("Did not get measurements from any of the clients."
                    " Check your network settings.")
            if err_data:
                msg += "\n\n" + err_data.decode("utf-8")
            self.error_message(msg)
            return

        # At this point we do have some results, so show dlg_results
        total_up = 0
        total_down = 0
        self.lss_results.clear()
        # List all the clients regardless of if we received measurements
        for client_ip in self.clients:
            client_name = self.clients[client_ip][1]
            if client_ip in self.results:
                upload, download = self.results[client_ip]
            else:
                upload, download = (0, 0)
            self.lss_results.append([client_name, upload, download])
            total_up += upload
            total_down += download

        clients_n = len(self.clients)
        self.lbl_avg_up.set_text(
            humanize(total_up / clients_n, unit='bps'))
        self.lbl_total_up.set_text(humanize(total_up, unit='bps'))
        self.lbl_avg_down.set_text(
            humanize(total_down / clients_n, unit='bps'))
        self.lbl_total_down.set_text(humanize(total_down, unit='bps'))

        self.box_partial_results.set_visible(
            self.spawn_process.lines_count != 2*len(self.clients))
        self.dlg_results.run()
Example #12
0
    def amp_client_disconnected(self, handle):
        """Called from uiconnection->Daemon->client_disconnected."""
        def determine_offline(client_):
            """Helper function to call client.set_offline when appropriate."""
            if client_.hsystem == '' and client_.users == {}:
                client_.set_offline()

        LOG.w("Disconnect from", handle)
        client = None
        for client in structs.clients:
            if client.hsystem == handle:
                if self.get_selected_group()[1].has_client(client) \
                        or self.is_default_group_selected():
                    self.notify_queue.enqueue(_("Shut down:"),
                                              client.get_name())
                client.hsystem = ''
                determine_offline(client)
                break
            elif handle in client.users:
                if self.get_selected_group()[1].has_client(client) \
                        or self.is_default_group_selected():
                    self.notify_queue.enqueue(
                        _("Disconnected:"),
                        _("%(user)s from %(host)s") % {
                            "user": client.users[handle]['uname'],
                            "host": client.get_name()
                        })
                del client.users[handle]
                determine_offline(client)
                break
            else:
                client = None
        if client is not None:
            for row in self.cstore:
                if row[C_INSTANCE] is client:
                    self.fill_icon_view(self.get_selected_group()[1], True)
                    break
Example #13
0
 def on_btn_start_clicked(self, _widget):
     """Handle btn_start.clicked event."""
     seconds = int(self.adj_seconds.get_value())
     self.spawn_process.spawn('iperf -s -xS -yC'.split(),
                              timeout=(seconds + 3),
                              lines_max=2*len(self.clients))
     for client in self.clients:
         handle = self.clients[client][0]
         # Half time for upload speed and half for download
         self.execute(handle, 'start_benchmark %d' % int(seconds/2))
     self.timeleft = seconds
     self.box_seconds.set_visible(False)
     self.box_countdown.set_visible(True)
     self.btn_start.set_visible(False)
     self.btn_stop.set_visible(True)
     self.lbl_countdown.set_text(_("Benchmark finishing in %d seconds...")
                                 % self.timeleft)
     self.countdown_event = GLib.timeout_add(1000, self.update_countdown)
Example #14
0
    def on_icv_clients_selection_changed(self, _widget):
        """Handle icv_clients.selection_changed event."""
        selected = self.get_selected_clients()
        single_client = False
        if len(selected) == 1:
            single_client = True
        self.get('imi_clients_information').set_sensitive(single_client)
        self.get('tlb_clients_information').set_sensitive(single_client)

        if selected:
            self.get('mni_add_to_group').set_sensitive(True)
            self.get('imi_clients_remove_from_group').set_sensitive(
                not self.is_default_group_selected())
        else:
            self.get('mni_add_to_group').set_sensitive(False)
            self.get('imi_clients_remove_from_group').set_sensitive(False)

        if len(selected) > 1:
            self.get('lbl_status').set_text(
                _('%d clients selected' % len(selected)))
        else:
            self.get('lbl_status').set_text('')
Example #15
0
 def on_imi_restrictions_lock_screen_activate(self, _widget):
     """Handle imi_restrictions_lock_screen.activate event."""
     msg = _("The screen is locked by a system administrator.")
     self.exec_on_selected_clients(['lock_screen', 0, msg])
Example #16
0
    def __init__(self):
        # Initialization of general-purpose variables
        self.about = None
        self.benchmark = None
        self.client_information = None
        self.current_macs = subprocess.Popen(
            [
                'sh', '-c', r"""ip -oneline -family inet link show | """
                r"""sed -n '/.*ether[[:space:]]*\([[:xdigit:]:]*\).*/"""
                r"""{s//\1/;y/abcdef-/ABCDEF:/;p;}';"""
                r"""echo $LTSP_CLIENT_MAC"""
            ],
            stdout=subprocess.PIPE).communicate()[0].split()
        self.current_thumbshots = dict()
        self.daemon = None
        self.displayed_compatibility_warning = False
        self.exec_command = None
        self.imagetypes = {
            'thin': GdkPixbuf.Pixbuf.new_from_file('images/thin.svg'),
            'fat': GdkPixbuf.Pixbuf.new_from_file('images/fat.svg'),
            'standalone':
            GdkPixbuf.Pixbuf.new_from_file('images/standalone.svg'),
            'offline': GdkPixbuf.Pixbuf.new_from_file('images/offline.svg')
        }
        self.labels_order = (1, 0)
        self.notify_queue = NotifyQueue(
            'Epoptes', '/usr/share/icons/hicolor/scalable/apps/epoptes.svg')
        self.send_message = None
        self.show_real_names = config.settings.getboolean('GUI',
                                                          'show_real_names',
                                                          fallback=False)
        # Thumbshot width and height. Good width defaults are multiples of 16,
        # so that the height is an integer in both 16/9 and 4/3 aspect ratios.
        self.ts_width = config.settings.getint('GUI',
                                               'thumbshots_width',
                                               fallback=128)
        self.ts_height = int(self.ts_width / (4 / 3))
        self.uid = os.getuid()
        self.vncserver = None
        self.vncserver_port = None
        self.vncserver_pwd = None
        self.vncviewer = None
        self.vncviewer_port = None

        self.builder = Gtk.Builder()
        self.builder.add_from_file('epoptes.ui')
        self.get = self.builder.get_object
        # Hide the remote assistance menuitem if epoptes-client isn't installed
        if not os.path.isfile(
                '/usr/share/epoptes-client/remote_assistance.py'):
            self.get('mi_remote_assistance').set_property('visible', False)
            self.get('smi_help_remote_support').set_property('visible', False)
        self.mnu_add_to_group = self.get('mnu_add_to_group')
        self.mni_add_to_group = self.get('mni_add_to_group')
        self.gstore = Gtk.ListStore(str, object, bool)
        self.trv_groups = self.get('trv_groups')
        self.trv_groups.set_model(self.gstore)
        self.mainwin = self.get('wnd_main')
        self.cstore = Gtk.ListStore(str, GdkPixbuf.Pixbuf, object, str)
        self.icv_clients = self.get('icv_clients')
        self.set_labels_order(1, 0, None)
        self.icv_clients.set_model(self.cstore)
        self.icv_clients.set_pixbuf_column(C_PIXBUF)
        self.icv_clients.set_text_column(C_LABEL)
        self.cstore.set_sort_column_id(C_LABEL, Gtk.SortType.ASCENDING)
        self.on_icv_clients_selection_changed(None)
        self.icv_clients.enable_model_drag_source(
            Gdk.ModifierType.BUTTON1_MASK,
            [Gtk.TargetEntry.new("add", Gtk.TargetFlags.SAME_APP, 0)],
            Gdk.DragAction.COPY)
        self.trv_groups.enable_model_drag_dest(
            [("add", Gtk.TargetFlags.SAME_APP, 0)], Gdk.DragAction.COPY)
        self.default_group = structs.Group(
            '<b>' + _('Detected clients') + '</b>', {})
        default_iter = self.gstore.append(
            [self.default_group.name, self.default_group, False])
        self.default_group_ref = Gtk.TreeRowReference.new(
            self.gstore, self.gstore.get_path(default_iter))
        # Connect glade handlers with the callback functions
        self.builder.connect_signals(self)
        self.trv_groups.get_selection().select_path(
            self.default_group_ref.get_path())
        self.get('adj_icon_size').set_value(self.ts_width)
        _saved_clients, groups = config.read_groups(
            config.expand_filename('groups.json'))
        if groups:
            self.mni_add_to_group.set_sensitive(True)
        for group in groups:
            self.gstore.append([group.name, group, True])
            mitem = Gtk.MenuItem(label=group.name)
            mitem.show()
            mitem.connect('activate',
                          self.on_imi_clients_add_to_group_activate, group)
            self.mnu_add_to_group.append(mitem)
        self.fill_icon_view(self.get_selected_group()[1])
        self.trv_groups.get_selection().select_path(
            config.settings.getint('GUI', 'selected_group', fallback=0))
        mitem = self.get(
            config.settings.get('GUI',
                                'label',
                                fallback='rmi_labels_host_user'))
        if not mitem:
            mitem = self.get('rmi_labels_host_user')
        mitem.set_active(True)
        self.get('cmi_show_real_names').set_active(self.show_real_names)
        self.mainwin.set_sensitive(False)
Example #17
0
 def on_imi_session_shutdown_activate(self, _widget):
     """Handle imi_session_shutdown.activate event."""
     self.exec_on_selected_clients(
         ["shutdown"],
         warn=_('Are you sure you want to shutdown all the computers?'))
Example #18
0
 def on_imi_session_reboot_activate(self, _widget):
     """Handle imi_session_reboot.activate event."""
     self.exec_on_selected_clients(
         ["reboot"],
         warn=_('Are you sure you want to reboot all the computers?'))
Example #19
0
 def warning_message(self, msg):
     """Show a warning dialog."""
     self.dlg_message.set_property("message-type", Gtk.MessageType.WARNING)
     self.dlg_message.set_title(_("Warning"))
     self.dlg_message.set_markup(msg)
     self.dlg_message.run()
Example #20
0
        LOG.e(exc)


# The system settings are shared with epoptes-client, that's why the caps.
system = read_shell_file('/etc/default/epoptes')
# TODO: check if the types, e.g. PORT=int, may cause problems.
system.setdefault('PORT', 789)
system.setdefault('SOCKET_GROUP', 'epoptes')
system.setdefault('DIR', '/run/epoptes')
# Allow running unencrypted, for clients with very low RAM.
try:
    if os.path.getsize('/etc/epoptes/server.crt') == 0:
        system.setdefault('ENCRYPTION', False)
except (IOError, OSError) as ex:
    LOG.e(ex)
finally:
    system.setdefault('ENCRYPTION', True)

settings = read_ini_file(expand_filename('settings'))
if not settings.has_section('GUI'):
    settings.add_section('GUI')
if not settings.has_option('GUI', 'messages_default_title'):
    settings.set('GUI', 'messages_default_title',
                 _('Message from administrator'))
if not settings.has_option('GUI', 'messages_use_markup'):
    settings.set('GUI', 'messages_use_markup', 'False')
if not settings.has_option('GUI', 'grabkbdptr'):
    settings.set('GUI', 'grabkbdptr', 'False')

history = read_plain_file(expand_filename('history'))
Example #21
0
 def error_message(self, msg):
     """Show an error dialog."""
     self.dlg_message.set_property("message-type", Gtk.MessageType.ERROR)
     self.dlg_message.set_title(_("Error"))
     self.dlg_message.set_markup(msg)
     self.dlg_message.run()
Example #22
0
    def add_client(self, handle, reply, already=False):
        """Callback after running `info` on a client."""
        # already is True if the client was started before epoptes
        LOG.w("add_client's been called for", handle)
        try:
            info = {}
            for line in reply.strip().split('\n'):
                key, value = line.split('=', 1)
                info[key.strip()] = value.strip()
            user, host, _ip, mac, type_, uid, version, name = \
                info['user'], info['hostname'], info['ip'], info['mac'], \
                info['type'], int(info['uid']), info['version'], info['name']
        except (KeyError, ValueError) as exc:
            LOG.e("  Can't extract client information, won't add this client",
                  exc)
            return False

        # Check if the incoming client is the same with the computer in which
        # epoptes is running, so we don't add it to the list.
        if (mac in self.current_macs) and ((uid == self.uid) or (uid == 0)):
            LOG.w("  Won't add this client to my lists")
            return False

        # Compatibility check
        if LooseVersion(version) < LooseVersion(COMPATIBILITY_VERSION):
            self.daemon.command(handle,
                                "die 'Incompatible Epoptes server version!'")
            if not self.displayed_compatibility_warning:
                self.displayed_compatibility_warning = True
                self.warning_dialog(
                    _("""A connection attempt was made by a client with"""
                      """ version %s, which is incompatible with the current"""
                      """ epoptes version.\n\nYou need to update your clients"""
                      """ to the latest epoptes-client version.""") % version)
            return False
        sel_group = self.get_selected_group()[1]
        client = None
        for inst in structs.clients:
            # Find if the new handle is a known client
            if mac == inst.mac:
                client = inst
                LOG.w('  Old client: ', end='')
                break
        if client is None:
            LOG.w('  New client: ', end='')
            client = structs.Client(mac=mac)
        LOG.w('hostname=%s, type=%s, uid=%s, user=%s' %
              (host, type_, uid, user))

        # Update/fill the client information
        client.type, client.hostname = type_, host
        if uid == 0:
            # This is a root epoptes-client
            client.hsystem = handle
        else:
            # This is a user epoptes-client
            client.add_user(user, name, handle)
            if not already and (sel_group.has_client(client)
                                or self.is_default_group_selected()):
                self.notify_queue.enqueue(
                    _("Connected:"),
                    _("%(user)s on %(host)s") % {
                        "user": user,
                        "host": host
                    })
        if sel_group.has_client(client) or self.is_default_group_selected():
            self.fill_icon_view(sel_group, True)

        return True
Example #23
0
 def on_imi_session_logout_activate(self, _widget):
     """Handle imi_session_logout.activate event."""
     self.exec_on_selected_clients(
         ['logout'],
         mode=EM_SESSION,
         warn=_('Are you sure you want to log off all the users?'))