Beispiel #1
0
    def get_machines_header(self, machines_column):
        b = PlainButton("Open in Browser", on_press=self.browse_maas)
        self.open_maas_button = AttrMap(b, 'button_secondary',
                                        'button_secondary focus')
        self.maastitle = Text("Connected to MAAS")
        maastitle_widgets = Padding(Columns(
            [self.maastitle, (22, self.open_maas_button)]),
                                    align='center',
                                    width='pack',
                                    left=2,
                                    right=2)

        f = machines_column.machines_list.handle_filter_change
        self.filter_edit_box = FilterBox(f)
        pl = [
            Divider(),
            Text(('body', "Ready Machines {}".format(
                MetaScroll().get_text()[0])),
                 align='center'),
            Divider(), maastitle_widgets,
            Divider(), self.filter_edit_box
        ]

        self.machines_header_pile = Pile(pl)
        return self.machines_header_pile
Beispiel #2
0
 def get_options_header(self, options_column):
     simple_widgets = self._simple_header_widgets("Options Editor")
     fb = FilterBox(options_column.handle_filter_change,
                    info_text="Filter by option name")
     padded_fb = Padding(AttrMap(fb, 'filter', 'filter_focus'),
                         left=2,
                         right=2)
     return Pile(simple_widgets + [padded_fb])
Beispiel #3
0
    def build_widgets(self, title_widgets):
        if title_widgets is None:
            if len(self.constraints) > 0:
                cstr = " matching constraints"
            else:
                cstr = ""

            title_widgets = [Text("Machines" + cstr, align='center')]

        self.filter_edit_box = FilterBox(self.handle_filter_change)

        header_widgets = title_widgets + [Divider()]

        if self.show_filter_box:
            header_widgets.append(self.filter_edit_box)

        self.header_padding = len(header_widgets)
        self.machine_pile = Pile(header_widgets + self.machine_widgets)
        return self.machine_pile
    def build_widgets(self, title_widgets):
        if title_widgets is None:
            if len(self.constraints) > 0:
                cstr = " matching constraints"
            else:
                cstr = ""

            title_widgets = Text("Machines" + cstr, align="center")

        self.filter_edit_box = FilterBox(self.handle_filter_change)

        self.machine_pile = Pile([title_widgets, Divider(), self.filter_edit_box] + self.machine_widgets)
        return self.machine_pile
Beispiel #5
0
    def build_widgets(self, title_widgets):
        if title_widgets is None:
            if len(self.constraints) > 0:
                cstr = " matching constraints"
            else:
                cstr = ""

            title_widgets = [Text("Machines" + cstr, align='center')]

        self.filter_edit_box = FilterBox(self.handle_filter_change)

        header_widgets = title_widgets + [Divider()]

        if self.show_filter_box:
            header_widgets.append(self.filter_edit_box)

        self.header_padding = len(header_widgets)
        self.machine_pile = Pile(header_widgets + self.machine_widgets)
        return self.machine_pile
Beispiel #6
0
class MachinesList(WidgetWrap):

    """A list of machines with configurable action buttons for each
    machine.

    action - a function to call when the machine's button is pressed

    constraints - a dict of constraints to filter the machines list.
    only machines matching all the constraints will be shown.

    show_hardware - bool, whether or not to show the hardware details
    for each of the machines

    title_widgets - A Text Widget to be used in place of the default
    title.

    show_assignments - bool, whether or not to show the assignments
    for each of the machines.

    show_only_ready - bool, only show machines with a ready state.

    """

    def __init__(self, controller, display_controller,
                 constraints=None, show_hardware=False,
                 title_widgets=None, show_assignments=True,
                 show_placeholders=True, show_only_ready=False,
                 show_filter_box=False):
        self.controller = controller
        self.display_controller = display_controller
        self.machine_widgets = []
        if constraints is None:
            self.constraints = {}
        else:
            self.constraints = constraints
        self.show_hardware = show_hardware
        self.show_assignments = show_assignments
        self.show_placeholders = show_placeholders
        self.show_only_ready = show_only_ready
        self.show_filter_box = show_filter_box
        self.filter_string = ""
        w = self.build_widgets(title_widgets)
        self.update()
        super().__init__(w)

    def selectable(self):
        # overridden to ensure that we can arrow through the buttons
        # shouldn't be necessary according to documented behavior of
        # Pile & Columns, but discovered via trial & error.
        return True

    def build_widgets(self, title_widgets):
        if title_widgets is None:
            if len(self.constraints) > 0:
                cstr = " matching constraints"
            else:
                cstr = ""

            title_widgets = [Text("Machines" + cstr, align='center')]

        self.filter_edit_box = FilterBox(self.handle_filter_change)

        header_widgets = title_widgets + [Divider()]

        if self.show_filter_box:
            header_widgets.append(self.filter_edit_box)

        self.header_padding = len(header_widgets)
        self.machine_pile = Pile(header_widgets + self.machine_widgets)
        return self.machine_pile

    def handle_filter_change(self, edit_button, userdata):
        self.filter_string = userdata
        self.update()

    def find_machine_widget(self, m):
        return next((mw for mw in self.machine_widgets if
                     mw.machine.instance_id == m.instance_id), None)

    def update(self):
        machines = self.controller.machines(
            include_placeholders=self.show_placeholders)
        if self.show_only_ready:
            machines = [m for m in machines
                        if m.status == MaasMachineStatus.READY]
        for mw in self.machine_widgets:
            machine = next((m for m in machines if
                            mw.machine.instance_id == m.instance_id), None)
            if machine is None:
                self.remove_machine(mw.machine)

        n_satisfying_machines = len(machines)

        def get_placement_filter_label(d):
            s = ""
            for atype, al in d.items():
                s += " ".join(["{} {}".format(cc.service_name,
                                              cc.display_name)
                               for cc in al])
            return s

        for m in machines:
            if not satisfies(m, self.constraints)[0]:
                self.remove_machine(m)
                n_satisfying_machines -= 1
                continue

            assignment_names = ""
            ad = self.controller.assignments_for_machine(m)
            assignment_names = get_placement_filter_label(ad)
            filter_label = "{} {}".format(m.filter_label(),
                                          assignment_names)
            if self.filter_string != "" and \
               self.filter_string not in filter_label:
                self.remove_machine(m)
                continue

            mw = self.find_machine_widget(m)
            if mw is None:
                mw = self.add_machine_widget(m)
            mw.update()

        self.filter_edit_box.set_info(len(self.machine_widgets),
                                      n_satisfying_machines)

        self.sort_machine_widgets()

    def add_machine_widget(self, machine):
        mw = SimpleMachineWidget(machine,
                                 self.controller,
                                 self.display_controller,
                                 self.show_assignments)
        self.machine_widgets.append(mw)
        options = self.machine_pile.options()
        self.machine_pile.contents.append((mw, options))

        # NOTE: see the +1: indexing in remove_machine if you re-add
        # this divider. it should then be +2.

        # self.machine_pile.contents.append((AttrMap(Padding(Divider('\u23bc'),
        #                                                    left=2, right=2),
        #                                            'label'), options))
        return mw

    def remove_machine(self, machine):
        mw = self.find_machine_widget(machine)
        if mw is None:
            return

        self.machine_widgets.remove(mw)
        mw_idx = 0
        for w, opts in self.machine_pile.contents:
            if w == mw:
                break
            mw_idx += 1

        c = self.machine_pile.contents[:mw_idx] + \
            self.machine_pile.contents[mw_idx + 1:]
        self.machine_pile.contents = c

    def sort_machine_widgets(self):
        def keyfunc(mw):
            m = mw.machine
            hwinfo = " ".join(map(str, [m.arch, m.cpu_cores, m.mem,
                                        m.storage]))
            if str(mw.machine.status) == 'ready':
                skey = 'A'
            else:
                skey = str(mw.machine.status)
            return skey + mw.machine.hostname + hwinfo
        self.machine_widgets.sort(key=keyfunc)

        def wrappedkeyfunc(t):
            mw, options = t
            if not isinstance(mw, SimpleMachineWidget):
                return 'A'
            return keyfunc(mw)

        self.machine_pile.contents.sort(key=wrappedkeyfunc)

    def focus_prev_or_top(self):
        self.update()
        try:
            if self.machine_pile.focus_position <= self.header_padding:
                self.machine_pile.focus_position = self.header_padding
        except IndexError:
            log.debug("index error in machines_list focus_top")
Beispiel #7
0
class MachinesList(WidgetWrap):
    """A list of machines with configurable action buttons for each
    machine.

    action - a function to call when the machine's button is pressed

    constraints - a dict of constraints to filter the machines list.
    only machines matching all the constraints will be shown.

    show_hardware - bool, whether or not to show the hardware details
    for each of the machines

    title_widgets - A Text Widget to be used in place of the default
    title.

    show_assignments - bool, whether or not to show the assignments
    for each of the machines.

    show_only_ready - bool, only show machines with a ready state.

    """
    def __init__(self,
                 controller,
                 display_controller,
                 constraints=None,
                 show_hardware=False,
                 title_widgets=None,
                 show_assignments=True,
                 show_placeholders=True,
                 show_only_ready=False,
                 show_filter_box=False):
        self.controller = controller
        self.display_controller = display_controller
        self.machine_widgets = []
        if constraints is None:
            self.constraints = {}
        else:
            self.constraints = constraints
        self.show_hardware = show_hardware
        self.show_assignments = show_assignments
        self.show_placeholders = show_placeholders
        self.show_only_ready = show_only_ready
        self.show_filter_box = show_filter_box
        self.filter_string = ""
        w = self.build_widgets(title_widgets)
        self.update()
        super().__init__(w)

    def selectable(self):
        # overridden to ensure that we can arrow through the buttons
        # shouldn't be necessary according to documented behavior of
        # Pile & Columns, but discovered via trial & error.
        return True

    def build_widgets(self, title_widgets):
        if title_widgets is None:
            if len(self.constraints) > 0:
                cstr = " matching constraints"
            else:
                cstr = ""

            title_widgets = [Text("Machines" + cstr, align='center')]

        self.filter_edit_box = FilterBox(self.handle_filter_change)

        header_widgets = title_widgets + [Divider()]

        if self.show_filter_box:
            header_widgets.append(self.filter_edit_box)

        self.header_padding = len(header_widgets)
        self.machine_pile = Pile(header_widgets + self.machine_widgets)
        return self.machine_pile

    def handle_filter_change(self, edit_button, userdata):
        self.filter_string = userdata
        self.update()

    def find_machine_widget(self, m):
        return next((mw for mw in self.machine_widgets
                     if mw.machine.instance_id == m.instance_id), None)

    def update(self):
        machines = self.controller.machines(
            include_placeholders=self.show_placeholders)
        if self.show_only_ready:
            machines = [
                m for m in machines if m.status == MaasMachineStatus.READY
            ]
        for mw in self.machine_widgets:
            machine = next(
                (m
                 for m in machines if mw.machine.instance_id == m.instance_id),
                None)
            if machine is None:
                self.remove_machine(mw.machine)

        n_satisfying_machines = len(machines)

        def get_placement_filter_label(d):
            s = ""
            for atype, al in d.items():
                s += " ".join([
                    "{} {}".format(cc.service_name, cc.display_name)
                    for cc in al
                ])
            return s

        for m in machines:
            if not satisfies(m, self.constraints)[0]:
                self.remove_machine(m)
                n_satisfying_machines -= 1
                continue

            assignment_names = ""
            ad = self.controller.assignments_for_machine(m)
            assignment_names = get_placement_filter_label(ad)
            filter_label = "{} {}".format(m.filter_label(), assignment_names)
            if self.filter_string != "" and \
               self.filter_string not in filter_label:
                self.remove_machine(m)
                continue

            mw = self.find_machine_widget(m)
            if mw is None:
                mw = self.add_machine_widget(m)
            mw.update()

        self.filter_edit_box.set_info(len(self.machine_widgets),
                                      n_satisfying_machines)

        self.sort_machine_widgets()

    def add_machine_widget(self, machine):
        mw = SimpleMachineWidget(machine, self.controller,
                                 self.display_controller,
                                 self.show_assignments)
        self.machine_widgets.append(mw)
        options = self.machine_pile.options()
        self.machine_pile.contents.append((mw, options))

        # NOTE: see the +1: indexing in remove_machine if you re-add
        # this divider. it should then be +2.

        # self.machine_pile.contents.append((AttrMap(Padding(Divider('\u23bc'),
        #                                                    left=2, right=2),
        #                                            'label'), options))
        return mw

    def remove_machine(self, machine):
        mw = self.find_machine_widget(machine)
        if mw is None:
            return

        self.machine_widgets.remove(mw)
        mw_idx = 0
        for w, opts in self.machine_pile.contents:
            if w == mw:
                break
            mw_idx += 1

        c = self.machine_pile.contents[:mw_idx] + \
            self.machine_pile.contents[mw_idx + 1:]
        self.machine_pile.contents = c

    def sort_machine_widgets(self):
        def keyfunc(mw):
            m = mw.machine
            hwinfo = " ".join(map(str,
                                  [m.arch, m.cpu_cores, m.mem, m.storage]))
            if str(mw.machine.status) == 'ready':
                skey = 'A'
            else:
                skey = str(mw.machine.status)
            return skey + mw.machine.hostname + hwinfo

        self.machine_widgets.sort(key=keyfunc)

        def wrappedkeyfunc(t):
            mw, options = t
            if not isinstance(mw, SimpleMachineWidget):
                return 'A'
            return keyfunc(mw)

        self.machine_pile.contents.sort(key=wrappedkeyfunc)

    def focus_prev_or_top(self):
        self.update()
        try:
            if self.machine_pile.focus_position <= self.header_padding:
                self.machine_pile.focus_position = self.header_padding
        except IndexError:
            log.debug("index error in machines_list focus_top")
class MachinesList(WidgetWrap):

    """A list of machines with configurable action buttons for each
    machine.

    actions - a list of ('label', function) pairs that wil be used to
    create buttons for each machine.  The machine will be passed to
    the function as userdata.

    constraints - a dict of constraints to filter the machines list.
    only machines matching all the constraints will be shown.

    show_hardware - bool, whether or not to show the hardware details
    for each of the machines

    title_widgets - A Text Widget to be used in place of the default
    title.

    show_assignments - bool, whether or not to show the assignments
    for each of the machines.

    """

    def __init__(
        self, controller, actions, constraints=None, show_hardware=False, title_widgets=None, show_assignments=True
    ):
        self.controller = controller
        self.actions = actions
        self.machine_widgets = []
        if constraints is None:
            self.constraints = {}
        else:
            self.constraints = constraints
        self.show_hardware = show_hardware
        self.show_assignments = show_assignments
        self.filter_string = ""
        w = self.build_widgets(title_widgets)
        self.update()
        super().__init__(w)

    def selectable(self):
        # overridden to ensure that we can arrow through the buttons
        # shouldn't be necessary according to documented behavior of
        # Pile & Columns, but discovered via trial & error.
        return True

    def build_widgets(self, title_widgets):
        if title_widgets is None:
            if len(self.constraints) > 0:
                cstr = " matching constraints"
            else:
                cstr = ""

            title_widgets = Text("Machines" + cstr, align="center")

        self.filter_edit_box = FilterBox(self.handle_filter_change)

        self.machine_pile = Pile([title_widgets, Divider(), self.filter_edit_box] + self.machine_widgets)
        return self.machine_pile

    def handle_filter_change(self, edit_button, userdata):
        self.filter_string = userdata
        self.update()

    def find_machine_widget(self, m):
        return next((mw for mw in self.machine_widgets if mw.machine.instance_id == m.instance_id), None)

    def update(self):
        machines = self.controller.machines()
        for mw in self.machine_widgets:
            machine = next((m for m in machines if mw.machine.instance_id == m.instance_id), None)
            if machine is None:
                self.remove_machine(mw.machine)

        n_satisfying_machines = len(machines)

        def get_placement_filter_label(d):
            s = ""
            for atype, al in d.items():
                s += " ".join(["{} {}".format(cc.charm_name, cc.display_name) for cc in al])
            return s

        for m in machines:
            if not satisfies(m, self.constraints)[0]:
                self.remove_machine(m)
                n_satisfying_machines -= 1
                continue

            assignment_names = ""
            ad = self.controller.assignments_for_machine(m)
            assignment_names = get_placement_filter_label(ad)
            dd = self.controller.deployments_for_machine(m)
            deployment_names = get_placement_filter_label(dd)
            filter_label = "{} {} {}".format(m.filter_label(), assignment_names, deployment_names)

            if self.filter_string != "" and self.filter_string not in filter_label:
                self.remove_machine(m)
                continue

            mw = self.find_machine_widget(m)

            if mw is None:
                mw = self.add_machine_widget(m)
            mw.update()

        self.filter_edit_box.set_info(len(self.machine_widgets), n_satisfying_machines)

    def add_machine_widget(self, machine):
        mw = MachineWidget(machine, self.controller, self.actions, self.show_hardware, self.show_assignments)
        self.machine_widgets.append(mw)
        options = self.machine_pile.options()
        self.machine_pile.contents.append((mw, options))

        self.machine_pile.contents.append((AttrMap(Padding(Divider("\u23bc"), left=2, right=2), "label"), options))
        return mw

    def remove_machine(self, machine):
        mw = self.find_machine_widget(machine)
        if mw is None:
            return

        self.machine_widgets.remove(mw)
        mw_idx = 0
        for w, opts in self.machine_pile.contents:
            if w == mw:
                break
            mw_idx += 1

        c = self.machine_pile.contents[:mw_idx] + self.machine_pile.contents[mw_idx + 2 :]
        self.machine_pile.contents = c