Example #1
0
    def test_show_matching_filter(self, mock_machinewidget):
        self.mock_maas_state.machines.return_value = [
            self.mock_machine, self.mock_machine2, self.mock_machine3
        ]
        # a little extra work to ensure that calls to
        # MockWidget.__init__() return mocks with the intended machine
        # attribute set:
        mw1 = MagicMock(name="mw1")
        mw1.machine = self.mock_machine
        mw2 = MagicMock(name="mw2")
        mw2.machine = self.mock_machine2
        mw3 = MagicMock(name="mw3")
        mw3.machine = self.mock_machine3
        # the rest are the placeholders:
        mw4 = MagicMock(name="mock_placeholder_widget1")
        mw4.machine = self.pc.sub_placeholder
        mw5 = MagicMock(name="mock_placeholder_widget2")
        mw5.machine = self.pc.def_placeholder
        mock_machinewidget.side_effect = [mw1, mw2, mw3, mw4, mw5]

        ml = MachinesList(self.pc, self.actions)
        self.assertEqual(5, len(ml.machine_widgets))

        ml.filter_string = "machine1-filter_label"
        ml.update()
        print("ml.machinewidgets is {}".format(ml.machine_widgets))
        self.assertEqual(1, len(ml.machine_widgets))
    def test_show_matching_filter(self, mock_machinewidget):
        self.mock_maas_state.machines.return_value = [self.mock_machine,
                                                      self.mock_machine2,
                                                      self.mock_machine3]
        # a little extra work to ensure that calls to
        # MockWidget.__init__() return mocks with the intended machine
        # attribute set:
        mw1 = MagicMock(name="mw1")
        mw1.machine = self.mock_machine
        mw2 = MagicMock(name="mw2")
        mw2.machine = self.mock_machine2
        mw3 = MagicMock(name="mw3")
        mw3.machine = self.mock_machine3
        # the rest are the placeholders:
        mw4 = MagicMock(name="mock_placeholder_widget1")
        mw4.machine = self.pc.sub_placeholder
        mw5 = MagicMock(name="mock_placeholder_widget2")
        mw5.machine = self.pc.def_placeholder
        mock_machinewidget.side_effect = [mw1, mw2, mw3, mw4, mw5]

        ml = MachinesList(self.pc, self.actions)
        self.assertEqual(5, len(ml.machine_widgets))

        ml.filter_string = "machine1-filter_label"
        ml.update()
        print("ml.machinewidgets is {}".format(ml.machine_widgets))
        self.assertEqual(1, len(ml.machine_widgets))
Example #3
0
    def build_widgets(self):
        def has_services_p(m):
            pc = self.placement_controller
            n = sum(
                [len(al) for at, al in pc.assignments_for_machine(m).items()])
            return n > 0

        clear_machine_func = self.placement_view.do_clear_machine
        show_chooser_func = self.placement_view.do_show_service_chooser

        self.open_maas_button = AttrMap(
            Button("Open in Browser", on_press=self.browse_maas),
            'button_secondary', 'button_secondary focus')

        bc = self.placement_view.config.juju_env['bootstrap-config']
        maasname = "'{}' <{}>".format(bc['name'], bc['maas-server'])
        maastitle = "Connected to MAAS {} l:root p:{}".format(
            maasname, self.placement_view.config.getopt('openstack_password'))
        tw = Columns([
            Text(maastitle),
            Padding(self.open_maas_button,
                    align='right',
                    width=BUTTON_SIZE,
                    right=2)
        ])

        self.machines_list = MachinesList(
            self.placement_controller,
            [(has_services_p, 'Clear All Services', clear_machine_func),
             (has_services_p, 'Remove Some Services', show_chooser_func)],
            show_hardware=True,
            title_widgets=tw)
        self.machines_list.update()

        self.machines_list_pile = Pile([self.machines_list, Divider()])

        # placeholders replaced in update() with absolute indexes, so
        # if you change this list, check update().
        pl = [
            Text(('subheading', "Machines"), align='center'),
            Divider(),
            Pile([]),  # machines_list
            Divider()
        ]

        self.main_pile = Pile(pl)

        return self.main_pile
Example #4
0
 def test_widgets_config(self, mock_machinewidget):
     for show_hardware in [False, True]:
         for show_assignments in [False, True]:
             MachinesList(self.pc,
                          self.actions,
                          show_hardware=show_hardware,
                          show_assignments=show_assignments)
             mock_machinewidget.assert_any_call(self.mock_machine, self.pc,
                                                self.actions, show_hardware,
                                                show_assignments)
             mock_machinewidget.reset_mock()
    def build_widgets(self):

        if self.charm_class.allow_multi_units:
            machine_string = "machines"
            plural_string = "s"
        else:
            machine_string = "a machine"
            plural_string = ""
        instructions = Text("Select {} to host {}".format(
            machine_string, self.charm_class.display_name))

        self.service_widget = ServiceWidget(self.charm_class,
                                            self.controller,
                                            show_constraints=True,
                                            show_placements=True)

        all_actions = [(AssignmentType.BareMetal, 'Add as Bare Metal',
                        self.do_select_baremetal),
                       (AssignmentType.LXC, 'Add as LXC', self.do_select_lxc),
                       (AssignmentType.KVM, 'Add as KVM', self.do_select_kvm)]

        actions = [(label, func) for atype, label, func in all_actions
                   if atype in self.charm_class.allowed_assignment_types]

        constraints = self.charm_class.constraints
        # NOTE: show_assignments=False is a WORKAROUND for #194
        self.machines_list = MachinesList(self.controller,
                                          actions,
                                          constraints=constraints,
                                          show_hardware=True,
                                          show_assignments=False)
        self.machines_list.update()
        close_button = AttrMap(Button('X', on_press=self.close_pressed),
                               'button_secondary', 'button_secondary focus')
        p = Pile([
            GridFlow([close_button], 5, 1, 0, 'right'), instructions,
            Divider(), self.service_widget,
            Divider(), self.machines_list
        ])

        return LineBox(p, title="Select Machine{}".format(plural_string))
Example #6
0
    def build_widgets(self):

        def has_services_p(m):
            pc = self.placement_controller
            n = sum([len(al) for at, al in
                     pc.assignments_for_machine(m).items()])
            return n > 0

        clear_machine_func = self.placement_view.do_clear_machine
        show_chooser_func = self.placement_view.do_show_service_chooser

        self.open_maas_button = AttrMap(Button("Open in Browser",
                                               on_press=self.browse_maas),
                                        'button_secondary',
                                        'button_secondary focus')

        bc = self.placement_view.config.juju_env['bootstrap-config']
        maasname = "'{}' <{}>".format(bc['name'], bc['maas-server'])
        maastitle = "Connected to MAAS {} l:root p:{}".format(
            maasname, self.placement_view.config.getopt('openstack_password'))
        tw = Columns([Text(maastitle),
                      Padding(self.open_maas_button, align='right',
                              width=BUTTON_SIZE, right=2)])

        self.machines_list = MachinesList(self.placement_controller,
                                          [(has_services_p,
                                            'Clear All Services',
                                            clear_machine_func),
                                           (has_services_p,
                                            'Remove Some Services',
                                            show_chooser_func)],
                                          show_hardware=True,
                                          title_widgets=tw)
        self.machines_list.update()

        self.machines_list_pile = Pile([self.machines_list,
                                        Divider()])

        # placeholders replaced in update() with absolute indexes, so
        # if you change this list, check update().
        pl = [Text(('subheading', "Machines"), align='center'),
              Divider(),
              Pile([]),         # machines_list
              Divider()]

        self.main_pile = Pile(pl)

        return self.main_pile
    def build_widgets(self):

        if self.charm_class.allow_multi_units:
            machine_string = "machines"
            plural_string = "s"
        else:
            machine_string = "a machine"
            plural_string = ""
        instructions = Text("Select {} to host {}".format(
            machine_string, self.charm_class.display_name))

        self.service_widget = ServiceWidget(self.charm_class,
                                            self.controller,
                                            show_constraints=True,
                                            show_placements=True)

        all_actions = [(AssignmentType.BareMetal,
                        'Add as Bare Metal',
                        self.do_select_baremetal),
                       (AssignmentType.LXC,
                        'Add as LXC', self.do_select_lxc),
                       (AssignmentType.KVM,
                        'Add as KVM', self.do_select_kvm)]

        actions = [(label, func) for atype, label, func in all_actions
                   if atype in self.charm_class.allowed_assignment_types]

        constraints = self.charm_class.constraints
        # NOTE: show_assignments=False is a WORKAROUND for #194
        self.machines_list = MachinesList(self.controller,
                                          actions,
                                          constraints=constraints,
                                          show_hardware=True,
                                          show_assignments=False)
        self.machines_list.update()
        close_button = AttrMap(Button('X',
                                      on_press=self.close_pressed),
                               'button_secondary', 'button_secondary focus')
        p = Pile([GridFlow([close_button], 5, 1, 0, 'right'),
                  instructions, Divider(), self.service_widget,
                  Divider(), self.machines_list])

        return LineBox(p, title="Select Machine{}".format(plural_string))
class MachinesColumn(WidgetWrap):
    """Shows machines or a link to MAAS to add more"""
    def __init__(self, display_controller, placement_controller,
                 placement_view):
        self.display_controller = display_controller
        self.placement_controller = placement_controller
        self.placement_view = placement_view
        w = self.build_widgets()
        super().__init__(w)
        self.update()

    def selectable(self):
        return True

    def build_widgets(self):
        def has_services_p(m):
            pc = self.placement_controller
            n = sum(
                [len(al) for at, al in pc.assignments_for_machine(m).items()])
            return n > 0

        clear_machine_func = self.placement_view.do_clear_machine
        show_chooser_func = self.placement_view.do_show_service_chooser

        self.open_maas_button = AttrMap(
            Button("Open in Browser", on_press=self.browse_maas),
            'button_secondary', 'button_secondary focus')

        bc = self.placement_view.config.juju_env['bootstrap-config']
        maasname = "'{}' <{}>".format(bc['name'], bc['maas-server'])
        maastitle = "Connected to MAAS {}".format(maasname)
        tw = Columns([
            Text(maastitle),
            Padding(self.open_maas_button,
                    align='right',
                    width=BUTTON_SIZE,
                    right=2)
        ])

        self.machines_list = MachinesList(
            self.placement_controller,
            [(has_services_p, 'Clear All Services', clear_machine_func),
             (has_services_p, 'Remove Some Services', show_chooser_func)],
            show_hardware=True,
            title_widgets=tw)
        self.machines_list.update()

        self.machines_list_pile = Pile([self.machines_list, Divider()])

        # placeholders replaced in update() with absolute indexes, so
        # if you change this list, check update().
        pl = [
            Text(('subheading', "Machines"), align='center'),
            Divider(),
            Pile([]),  # machines_list
            Divider()
        ]

        self.main_pile = Pile(pl)

        return self.main_pile

    def update(self):
        self.machines_list.update()

        bc = self.placement_view.config.juju_env['bootstrap-config']
        empty_maas_msg = ("There are no available machines.\n"
                          "Open {} to add machines to "
                          "'{}':".format(bc['maas-server'], bc['name']))

        self.empty_maas_widgets = Pile([
            Text([('error_icon', "\N{WARNING SIGN} "), empty_maas_msg],
                 align='center'),
            Padding(self.open_maas_button, align='center', width=BUTTON_SIZE)
        ])

        # 1 machine is the subordinate placeholder:
        if len(self.placement_controller.machines()) == 1:
            self.main_pile.contents[2] = (self.empty_maas_widgets,
                                          self.main_pile.options())
        else:
            self.main_pile.contents[2] = (self.machines_list_pile,
                                          self.main_pile.options())

    def browse_maas(self, sender):

        bc = self.placement_view.config.juju_env['bootstrap-config']
        try:
            p = Popen(["sensible-browser", bc['maas-server']],
                      stdout=PIPE,
                      stderr=PIPE)
            outs, errs = p.communicate(timeout=5)

        except TimeoutExpired:
            # went five seconds without an error, so we assume it's
            # OK. Don't kill it, just let it go:
            return
        e = errs.decode('utf-8')
        msg = "Error opening '{}' in a browser:\n{}".format(bc['name'], e)

        w = InfoDialog(msg, self.placement_view.remove_overlay)
        self.placement_view.show_overlay(w)
Example #9
0
 def test_hide_non_matching_constraints(self, mock_machinewidget):
     ml = MachinesList(self.pc, self.actions, {'cpu_cores': 16384})
     self.assertEqual(0, len(ml.machine_widgets))
Example #10
0
 def test_show_matching_constraints(self, mock_machinewidget):
     ml = MachinesList(self.pc, self.actions, {'cpu_cores': 2})
     self.assertEqual(1, len(ml.machine_widgets))
class MachineChooser(WidgetWrap):

    """Presents list of machines to assign a service to.
    Supports multiple selection if the service does.
    """

    def __init__(self, controller, charm_class, parent_widget):
        self.controller = controller
        self.charm_class = charm_class
        self.parent_widget = parent_widget
        w = self.build_widgets()
        super().__init__(w)

    def build_widgets(self):

        if self.charm_class.allow_multi_units:
            machine_string = "machines"
            plural_string = "s"
        else:
            machine_string = "a machine"
            plural_string = ""
        instructions = Text("Select {} to host {}".format(
            machine_string, self.charm_class.display_name))

        self.service_widget = ServiceWidget(self.charm_class,
                                            self.controller,
                                            show_constraints=True,
                                            show_placements=True)

        all_actions = [(AssignmentType.BareMetal,
                        'Add as Bare Metal',
                        self.do_select_baremetal),
                       (AssignmentType.LXC,
                        'Add as LXC', self.do_select_lxc),
                       (AssignmentType.KVM,
                        'Add as KVM', self.do_select_kvm)]

        actions = [(label, func) for atype, label, func in all_actions
                   if atype in self.charm_class.allowed_assignment_types]

        constraints = self.charm_class.constraints
        # NOTE: show_assignments=False is a WORKAROUND for #194
        self.machines_list = MachinesList(self.controller,
                                          actions,
                                          constraints=constraints,
                                          show_hardware=True,
                                          show_assignments=False)
        self.machines_list.update()
        close_button = AttrMap(Button('X',
                                      on_press=self.close_pressed),
                               'button_secondary', 'button_secondary focus')
        p = Pile([GridFlow([close_button], 5, 1, 0, 'right'),
                  instructions, Divider(), self.service_widget,
                  Divider(), self.machines_list])

        return LineBox(p, title="Select Machine{}".format(plural_string))

    def do_select_baremetal(self, sender, machine):
        self.do_select(sender, machine, AssignmentType.BareMetal)

    def do_select_lxc(self, sender, machine):
        self.do_select(sender, machine, AssignmentType.LXC)

    def do_select_kvm(self, sender, machine):
        self.do_select(sender, machine, AssignmentType.KVM)

    def do_select(self, sender, machine, atype):
        self.controller.assign(machine, self.charm_class, atype)
        self.machines_list.update()
        self.service_widget.update()
        self.parent_widget.remove_overlay(self)

    def close_pressed(self, sender):
        self.parent_widget.remove_overlay(self)
Example #12
0
class MachinesColumn(WidgetWrap):

    """Shows machines or a link to MAAS to add more"""

    def __init__(self, display_controller, placement_controller,
                 placement_view):
        self.display_controller = display_controller
        self.placement_controller = placement_controller
        self.placement_view = placement_view
        w = self.build_widgets()
        super().__init__(w)
        self.update()

    def selectable(self):
        return True

    def build_widgets(self):

        def has_services_p(m):
            pc = self.placement_controller
            n = sum([len(al) for at, al in
                     pc.assignments_for_machine(m).items()])
            return n > 0

        clear_machine_func = self.placement_view.do_clear_machine
        show_chooser_func = self.placement_view.do_show_service_chooser

        self.open_maas_button = AttrMap(Button("Open in Browser",
                                               on_press=self.browse_maas),
                                        'button_secondary',
                                        'button_secondary focus')

        bc = self.placement_view.config.juju_env['bootstrap-config']
        maasname = "'{}' <{}>".format(bc['name'], bc['maas-server'])
        maastitle = "Connected to MAAS {} l:root p:{}".format(
            maasname, self.placement_view.config.getopt('openstack_password'))
        tw = Columns([Text(maastitle),
                      Padding(self.open_maas_button, align='right',
                              width=BUTTON_SIZE, right=2)])

        self.machines_list = MachinesList(self.placement_controller,
                                          [(has_services_p,
                                            'Clear All Services',
                                            clear_machine_func),
                                           (has_services_p,
                                            'Remove Some Services',
                                            show_chooser_func)],
                                          show_hardware=True,
                                          title_widgets=tw)
        self.machines_list.update()

        self.machines_list_pile = Pile([self.machines_list,
                                        Divider()])

        # placeholders replaced in update() with absolute indexes, so
        # if you change this list, check update().
        pl = [Text(('subheading', "Machines"), align='center'),
              Divider(),
              Pile([]),         # machines_list
              Divider()]

        self.main_pile = Pile(pl)

        return self.main_pile

    def update(self):
        self.machines_list.update()

        bc = self.placement_view.config.juju_env['bootstrap-config']
        empty_maas_msg = ("There are no available machines.\n"
                          "Open {} to add machines to "
                          "'{}':".format(bc['maas-server'], bc['name']))

        self.empty_maas_widgets = Pile([Text([('error_icon',
                                               "\N{WARNING SIGN} "),
                                              empty_maas_msg],
                                             align='center'),
                                        Padding(self.open_maas_button,
                                                align='center',
                                                width=BUTTON_SIZE)])

        # 1 machine is the subordinate placeholder:
        if len(self.placement_controller.machines()) == 1:
            self.main_pile.contents[2] = (self.empty_maas_widgets,
                                          self.main_pile.options())
        else:
            self.main_pile.contents[2] = (self.machines_list_pile,
                                          self.main_pile.options())

    def browse_maas(self, sender):

        bc = self.placement_view.config.juju_env['bootstrap-config']
        try:
            p = Popen(["sensible-browser", bc['maas-server']],
                      stdout=PIPE, stderr=PIPE)
            outs, errs = p.communicate(timeout=5)

        except TimeoutExpired:
            # went five seconds without an error, so we assume it's
            # OK. Don't kill it, just let it go:
            return
        e = errs.decode('utf-8')
        msg = "Error opening '{}' in a browser:\n{}".format(bc['name'], e)

        w = InfoDialog(msg, self.placement_view.remove_overlay)
        self.placement_view.show_overlay(w)
class MachineChooser(WidgetWrap):
    """Presents list of machines to assign a service to.
    Supports multiple selection if the service does.
    """
    def __init__(self, controller, charm_class, parent_widget):
        self.controller = controller
        self.charm_class = charm_class
        self.parent_widget = parent_widget
        w = self.build_widgets()
        super().__init__(w)

    def build_widgets(self):

        if self.charm_class.allow_multi_units:
            machine_string = "machines"
            plural_string = "s"
        else:
            machine_string = "a machine"
            plural_string = ""
        instructions = Text("Select {} to host {}".format(
            machine_string, self.charm_class.display_name))

        self.service_widget = ServiceWidget(self.charm_class,
                                            self.controller,
                                            show_constraints=True,
                                            show_placements=True)

        all_actions = [(AssignmentType.BareMetal, 'Add as Bare Metal',
                        self.do_select_baremetal),
                       (AssignmentType.LXC, 'Add as LXC', self.do_select_lxc),
                       (AssignmentType.KVM, 'Add as KVM', self.do_select_kvm)]

        actions = [(label, func) for atype, label, func in all_actions
                   if atype in self.charm_class.allowed_assignment_types]

        constraints = self.charm_class.constraints
        # NOTE: show_assignments=False is a WORKAROUND for #194
        self.machines_list = MachinesList(self.controller,
                                          actions,
                                          constraints=constraints,
                                          show_hardware=True,
                                          show_assignments=False)
        self.machines_list.update()
        close_button = AttrMap(Button('X', on_press=self.close_pressed),
                               'button_secondary', 'button_secondary focus')
        p = Pile([
            GridFlow([close_button], 5, 1, 0, 'right'), instructions,
            Divider(), self.service_widget,
            Divider(), self.machines_list
        ])

        return LineBox(p, title="Select Machine{}".format(plural_string))

    def do_select_baremetal(self, sender, machine):
        self.do_select(sender, machine, AssignmentType.BareMetal)

    def do_select_lxc(self, sender, machine):
        self.do_select(sender, machine, AssignmentType.LXC)

    def do_select_kvm(self, sender, machine):
        self.do_select(sender, machine, AssignmentType.KVM)

    def do_select(self, sender, machine, atype):
        self.controller.assign(machine, self.charm_class, atype)
        self.machines_list.update()
        self.service_widget.update()
        self.parent_widget.remove_overlay(self)

    def close_pressed(self, sender):
        self.parent_widget.remove_overlay(self)