示例#1
0
 def __init__(self, juju_state):
     table = Table()
     table.addHeadings([
         Text('Service'),
         Text('Hardware'),
         Text('Hostname'),
         Text('Machine'),
     ])
     for name, service in juju_state['Services'].items():
         s = ServiceWidget(name, service)
         q(s)
         for u in s.Units:
             m = MachineWidget(
                 juju_state['Machines'][u.Machine.get_text()[0]])
             table.addColumns(u.Name.get_text()[0],
                              [u.Name, m.Hardware, m.DNSName, u.Machine])
     super().__init__(body=table.render())
示例#2
0
 def __init__(self, machine_view):
     table = Table()
     table.addHeadings([
         Text('Hostname'),
         Text('CPU'),
         Text('Storage'),
         Text('Memory'),
     ])
     for m in machine_view:
         m = MachineWidget(m)
         table.addColumns(m.hostname, [
             m.hostname,
             m.cpu_count,
             m.storage,
             m.memory
         ])
     super().__init__(body=table.render())
 def __init__(self, juju_state):
     table = Table()
     table.addHeadings([
         Text('Service'),
         Text('Hardware'),
         Text('Hostname'),
         Text('Machine'),
     ])
     for name, service in juju_state['Services'].items():
         s = ServiceWidget(name, service)
         q(s)
         for u in s.Units:
             m = MachineWidget(juju_state['Machines'][u.Machine.get_text()[0]])
             table.addColumns(u.Name.get_text()[0], [
                 u.Name,
                 m.Hardware,
                 m.DNSName,
                 u.Machine
             ])
     super().__init__(body=table.render())
示例#4
0
class ServicesView(WidgetWrap):

    view_columns = [
        ('Icon', "", 2),
        ('Name', "Service", 0),
        ('AgentStatus', "Status", 20),
        ('PublicAddress', "IP", 20),
        ('Machine', "Machine", 20),
    ]

    def __init__(self, app):
        self.app = app
        self.deployed = {}
        self.unit_w = None
        self.table = Table()

        headings = []
        for key, label, width in self.view_columns:
            # If no width assume ('weight', 1, widget)
            if width == 0:
                headings.append(Color.column_header(Text(label)))
            else:
                headings.append(
                    ('fixed', width, Color.column_header(Text(label))))
        self.table.addHeadings(headings)
        super().__init__(self.table.render())

        self.refresh_nodes()

    def refresh_nodes(self):
        """ Adds services to the view if they don't already exist
        """
        status = model_status()
        for name, service in sorted(status['applications'].items()):
            service_w = ServiceWidget(name, service)
            for unit in service_w.Units:
                services_list = []
                try:
                    unit_w = self.deployed[unit._name]
                except:
                    self.deployed[unit._name] = unit
                    unit_w = self.deployed[unit._name]
                    for k, label, width in self.view_columns:
                        if width == 0:
                            services_list.append(getattr(unit_w, k))
                        else:
                            if not hasattr(unit_w, k):
                                continue
                            services_list.append(
                                ('fixed', width, getattr(unit_w, k)))

                    self.table.addColumns(unit._name, services_list)
                    if not hasattr(unit_w, 'WorkloadInfo'):
                        continue
                    self.table.addColumns(
                        unit._name, [('fixed', 5, Text("")),
                                     Color.info_context(unit_w.WorkloadInfo)],
                        force=True)
                self.update_ui_state(unit_w, unit._unit)

    def status_icon_state(self, agent_state):
        if agent_state == "maintenance" \
           or agent_state == "allocating" \
           or agent_state == "executing":
            pending_status = [("pending_icon", "\N{CIRCLED BULLET}"),
                              ("pending_icon", "\N{CIRCLED WHITE BULLET}"),
                              ("pending_icon", "\N{FISHEYE}")]
            status = random.choice(pending_status)
        elif agent_state == "waiting":
            status = ("pending_icon", "\N{HOURGLASS}")
        elif agent_state == "idle" \
                or agent_state == "active":
            status = ("success_icon", "\u2713")
        elif agent_state == "blocked":
            status = ("error_icon", "\N{BLACK FLAG}")
        elif agent_state == "unknown":
            status = ("error_icon", "\N{DOWNWARDS BLACK ARROW}")
        else:
            # NOTE: Should not get here, if we do make sure we account
            # for that error type above.
            status = ("error_icon", "?")
        return status

    def update_ui_state(self, unit_w, unit):
        """ Updates individual machine information

        Arguments:
        service: current service
        unit_w: UnitInfo widget
        unit: current unit for service
        """
        try:
            unit_w.Machine.set_text(unit.get('machine', '-'))
            unit_w.PublicAddress.set_text(unit['public-address'])
            unit_w.WorkloadInfo.set_text(unit['workload-status']['info'])
            if unit['workload-status']['status'] != 'unknown':
                unit_w.AgentStatus.set_text(unit['workload-status']['status'])
                unit_w.Icon.set_text(
                    self.status_icon_state(unit['workload-status']['status']))
            else:
                unit_w.AgentStatus.set_text(unit['agent-status']['status'])
                unit_w.Icon.set_text(
                    self.status_icon_state(unit['agent-status']['status']))
        except Exception as e:
            self.app.log.exception(e)
            self.app.ui.show_exception_message(e)
示例#5
0
class ServicesView(WidgetWrap):

    view_columns = [('icon', "", 2), ('display_name', "Service", 0),
                    ('agent_state', "Status", 12),
                    ('public_address', "IP", 12), ('machine', "Machine", 12),
                    ('container', "Container", 12), ('arch', "Arch ", 12),
                    ('cpu_cores', "Cores", 12), ('mem', "Mem ", 12),
                    ('storage', "Storage", 12)]

    def __init__(self, nodes, juju_state, maas_state, config):
        self.deployed = {}
        self.nodes = [] if nodes is None else nodes
        self.juju_state = juju_state
        self.maas_state = maas_state
        self.config = config
        self.unit_w = None
        self.log_cache = None
        self.table = Table()

        headings = []
        for key, label, width in self.view_columns:
            # If no width assume ('weight', 1, widget)
            if width == 0:
                headings.append(Color.column_header(Text(label)))
            else:
                headings.append(
                    ('fixed', width, Color.column_header(Text(label))))
        self.table.addHeadings(headings)
        super().__init__(self.table.render())

        self.refresh_nodes(self.nodes)

    def refresh_nodes(self, nodes):
        """ Adds services to the view if they don't already exist
        """
        for node in nodes:
            services_list = []
            charm_class, service = node
            if len(service.units) > 0:
                for u in sorted(service.units, key=attrgetter('unit_name')):
                    # Refresh any state changes
                    try:
                        unit_w = self.deployed[u.unit_name]
                    except:
                        hwinfo = self._get_hardware_info(u)
                        self.deployed[u.unit_name] = UnitInfoWidget(
                            u, charm_class, hwinfo)
                        unit_w = self.deployed[u.unit_name]
                        for k, label, width in self.view_columns:
                            if width == 0:
                                services_list.append(getattr(unit_w, k))
                            else:
                                services_list.append(
                                    ('fixed', width, getattr(unit_w, k)))

                        self.table.addColumns(u.unit_name, services_list)
                        self.table.addColumns(
                            u.unit_name,
                            [('fixed', 5, Text("")),
                             Color.frame_subheader(unit_w.workload_info)],
                            force=True)
                    self.update_ui_state(charm_class, u, unit_w)

    def status_icon_state(self, charm_class, unit):
        # unit.agent_state may be "pending" despite errors elsewhere,
        # so we check for error_info first.
        # if the agent_state is "error", _detect_errors returns that.
        error_info = self._detect_errors(unit, charm_class)

        if error_info:
            status = ("error_icon", "\N{TETRAGRAM FOR FAILURE}")
        elif unit.agent_state == "pending":
            pending_status = [("pending_icon", "\N{CIRCLED BULLET}"),
                              ("pending_icon", "\N{CIRCLED WHITE BULLET}"),
                              ("pending_icon", "\N{FISHEYE}")]
            status = random.choice(pending_status)
        elif unit.agent_state == "installed":
            status = ("pending_icon", "\N{HOURGLASS}")
        elif unit.agent_state == "started":
            status = ("success_icon", "\u2713")
        elif unit.agent_state == "stopped":
            status = ("error_icon", "\N{BLACK FLAG}")
        elif unit.agent_state == "down":
            status = ("error_icon", "\N{DOWNWARDS BLACK ARROW}")
        else:
            # NOTE: Should not get here, if we do make sure we account
            # for that error type above.
            status = ("error_icon", "?")
        return status

    def update_ui_state(self, charm_class, unit, unit_w):
        """ Updates individual machine information
        """
        unit_w.public_address.set_text(unit.public_address)
        unit_w.agent_state.set_text(unit.agent_state)
        unit_w.icon.set_text(self.status_icon_state(charm_class, unit))
        # Special additional status text for these services
        if 'glance-simplestreams-sync' in unit.unit_name:
            status_oneline = get_sync_status().replace("\n", " - ")
            unit_w.workload_info.set_text(status_oneline)

        elif unit.is_horizon and unit.agent_state == "started":
            unit_w.workload_info.set_text(
                "Login: https://{}/horizon "
                "l:{} p:{}".format(unit.public_address, 'ubuntu',
                                   self.config.getopt('openstack_password')))

        elif unit.is_jujugui and unit.agent_state == "started":
            unit_w.workload_info.set_text("Login: https://{}/".format(
                unit.public_address))
        else:
            unit_w.workload_info.set_text(" {} - {}".format(
                unit.extended_agent_state, unit.workload_info))

    def _get_hardware_info(self, unit):
        """Get hardware info from juju or maas

        Returns list of text and formatting tuples
        """
        juju_machine = self.juju_state.machine(unit.machine_id)
        maas_machine = None
        if self.maas_state:
            maas_machine = self.maas_state.machine(juju_machine.instance_id)

        m = juju_machine
        if juju_machine.arch == "N/A":
            if maas_machine:
                m = maas_machine
            else:
                try:
                    return self._get_container_info(unit)
                except:
                    log.exception(
                        "failed to get container info for unit {}.".format(
                            unit))

        hw_info = self._hardware_info_for_machine(m)
        hw_info['machine'] = juju_machine.machine_id
        return hw_info

    def _get_container_info(self, unit):
        """Attempt to get hardware info of host machine for a unit that looks
        like a container.

        """
        base_machine = self.juju_state.base_machine(unit.machine_id)

        if base_machine.arch == "N/A" and self.maas_state is not None:
            m = self.maas_state.machine(base_machine.instance_id)
        else:
            m = base_machine

        # FIXME: Breaks single install status display
        # base_id, container_type, container_id = unit.machine_id.split('/')
        # ctypestr = dict(kvm="VM", lxc="Container")[container_type]

        # rl = ["{} {} (Machine {}".format(ctypestr, container_id,
        #                                  base_id)]
        try:
            container_id = unit.machine_id.split('/')[-1]
        except:
            log.exception("ERROR: base_machine is {} and m is {}, "
                          "and unit.machine_id is {}".format(
                              base_machine, m, unit.machine_id))
            return "?"

        base_id = base_machine.machine_id
        hw_info = self._hardware_info_for_machine(m)
        hw_info['machine'] = base_id
        hw_info['container'] = container_id
        return hw_info

    def _hardware_info_for_machine(self, m):
        return {
            "arch": m.arch,
            "cpu_cores": m.cpu_cores,
            "mem": m.mem,
            "storage": m.storage,
            "container": '-',
            "machine": 0
        }

    def _detect_errors(self, unit, charm_class):
        """Look in multiple places for an error.

        Return error info string if present,
        or None if no error is found
        """
        unit_machine = self.juju_state.machine(unit.machine_id)

        if unit.agent_state == "error":
            return unit.agent_state_info.lstrip()

        err_info = ""

        if unit.agent_state == 'pending' and \
           unit_machine.agent_state is '' and \
           unit_machine.agent_state_info is not None:

            # detect MAAS API errors, returned as 409 conflict:
            if "409" in unit_machine.agent_state_info:
                if charm_class.constraints is not None:
                    err_info = "Found no machines meeting constraints: "
                    err_info += ', '.join([
                        "{}='{}'".format(k, v)
                        for k, v in charm_class.constraints.items()
                    ])
                else:
                    err_info += "No machines available for unit."
            else:
                err_info += unit_machine.agent_state_info
            return err_info
        return None

    def get_log_text(self, unit_name):
        name = '-'.join(unit_name.split('/'))
        cmd = ("sudo grep {unit} /var/log/juju-ubuntu-local/all-machines.log "
               " | tail -n 2")
        cmd = cmd.format(unit=name)
        out = utils.get_command_output(cmd)
        if out['status'] == 0 and len(out['output']) > 0:
            return out['output']
        else:
            return "No log matches for {}".format(name)
示例#6
0
class ServicesView(WidgetWrap):

    view_columns = [
        ('Icon', "", 2),
        ('Name', "Service", 0),
        ('AgentStatus', "Status", 20),
        ('PublicAddress', "IP", 20),
        ('Machine', "Machine", 20),
    ]

    def __init__(self, app):
        self.app = app
        self.deployed = {}
        self.unit_w = None
        self.table = Table()

        headings = []
        for key, label, width in self.view_columns:
            # If no width assume ('weight', 1, widget)
            if width == 0:
                headings.append(Color.column_header(Text(label)))
            else:
                headings.append(
                    ('fixed', width, Color.column_header(Text(label))))
        self.table.addHeadings(headings)
        super().__init__(self.table.render())

        self.refresh_nodes()

    def refresh_nodes(self):
        """ Adds services to the view if they don't already exist
        """
        status = model_status()
        for name, service in sorted(status['applications'].items()):
            service_w = ServiceWidget(name, service)
            for unit in service_w.Units:
                services_list = []
                try:
                    unit_w = self.deployed[unit._name]
                except:
                    self.deployed[unit._name] = unit
                    unit_w = self.deployed[unit._name]
                    for k, label, width in self.view_columns:
                        if width == 0:
                            services_list.append(getattr(unit_w, k))
                        else:
                            if not hasattr(unit_w, k):
                                continue
                            services_list.append(('fixed', width,
                                                  getattr(unit_w, k)))

                    self.table.addColumns(unit._name, services_list)
                    if not hasattr(unit_w, 'WorkloadInfo'):
                        continue
                    self.table.addColumns(
                        unit._name,
                        [
                            ('fixed', 5, Text("")),
                            Color.info_context(
                                unit_w.WorkloadInfo)
                        ],
                        force=True)
                self.update_ui_state(unit_w, unit._unit)

    def status_icon_state(self, agent_state):
        if agent_state == "maintenance" \
           or agent_state == "allocating" \
           or agent_state == "executing":
            pending_status = [("pending_icon", "\N{CIRCLED BULLET}"),
                              ("pending_icon", "\N{CIRCLED WHITE BULLET}"),
                              ("pending_icon", "\N{FISHEYE}")]
            status = random.choice(pending_status)
        elif agent_state == "waiting":
            status = ("pending_icon", "\N{HOURGLASS}")
        elif agent_state == "idle" \
                or agent_state == "active":
            status = ("success_icon", "\u2713")
        elif agent_state == "blocked":
            status = ("error_icon", "\N{BLACK FLAG}")
        elif agent_state == "unknown":
            status = ("error_icon", "\N{DOWNWARDS BLACK ARROW}")
        else:
            # NOTE: Should not get here, if we do make sure we account
            # for that error type above.
            status = ("error_icon", "?")
        return status

    def update_ui_state(self, unit_w, unit):
        """ Updates individual machine information

        Arguments:
        service: current service
        unit_w: UnitInfo widget
        unit: current unit for service
        """
        try:
            unit_w.Machine.set_text(unit.get('machine', '-'))
            unit_w.PublicAddress.set_text(unit['public-address'])
            unit_w.WorkloadInfo.set_text(unit['workload-status']['info'])
            if unit['workload-status']['status'] != 'unknown':
                unit_w.AgentStatus.set_text(unit['workload-status']['status'])
                unit_w.Icon.set_text(
                    self.status_icon_state(unit['workload-status']['status']))
            else:
                unit_w.AgentStatus.set_text(unit['agent-status']['status'])
                unit_w.Icon.set_text(
                    self.status_icon_state(unit['agent-status']['status']))
        except Exception as e:
            self.app.log.exception(e)
            self.app.ui.show_exception_message(e)
class ServicesView(WidgetWrap):

    view_columns = [
        ('icon', "", 2),
        ('display_name', "Service", 0),
        ('agent_state', "Status", 12),
        ('public_address', "IP", 12),
        ('machine', "Machine", 12),
        ('container', "Container", 12),
        ('arch', "Arch ", 12),
        ('cpu_cores', "Cores", 12),
        ('mem', "Mem ", 12),
        ('storage', "Storage", 12)
    ]

    def __init__(self, nodes, juju_state, maas_state, config):
        self.deployed = {}
        self.nodes = [] if nodes is None else nodes
        self.juju_state = juju_state
        self.maas_state = maas_state
        self.config = config
        self.unit_w = None
        self.log_cache = None
        self.table = Table()

        headings = []
        for key, label, width in self.view_columns:
            # If no width assume ('weight', 1, widget)
            if width == 0:
                headings.append(Color.column_header(Text(label)))
            else:
                headings.append(
                    ('fixed', width, Color.column_header(Text(label))))
        self.table.addHeadings(headings)
        super().__init__(self.table.render())

        self.refresh_nodes(self.nodes)

    def refresh_nodes(self, nodes):
        """ Adds services to the view if they don't already exist
        """
        for node in nodes:
            services_list = []
            charm_class, service = node
            if len(service.units) > 0:
                for u in sorted(service.units, key=attrgetter('unit_name')):
                    # Refresh any state changes
                    try:
                        unit_w = self.deployed[u.unit_name]
                    except:
                        hwinfo = self._get_hardware_info(u)
                        self.deployed[u.unit_name] = UnitInfoWidget(
                            u,
                            charm_class,
                            hwinfo)
                        unit_w = self.deployed[u.unit_name]
                        for k, label, width in self.view_columns:
                            if width == 0:
                                services_list.append(getattr(unit_w, k))
                            else:
                                services_list.append(('fixed', width,
                                                      getattr(unit_w, k)))

                        self.table.addColumns(u.unit_name, services_list)
                        self.table.addColumns(
                            u.unit_name,
                            [
                                ('fixed', 5, Text("")),
                                Color.frame_subheader(unit_w.workload_info)
                            ],
                            force=True)
                    self.update_ui_state(charm_class, u,
                                         unit_w)

    def status_icon_state(self, charm_class, unit):
        # unit.agent_state may be "pending" despite errors elsewhere,
        # so we check for error_info first.
        # if the agent_state is "error", _detect_errors returns that.
        error_info = self._detect_errors(unit, charm_class)

        if error_info:
            status = ("error_icon", "\N{TETRAGRAM FOR FAILURE}")
        elif unit.agent_state == "pending":
            pending_status = [("pending_icon", "\N{CIRCLED BULLET}"),
                              ("pending_icon", "\N{CIRCLED WHITE BULLET}"),
                              ("pending_icon", "\N{FISHEYE}")]
            status = random.choice(pending_status)
        elif unit.agent_state == "installed":
            status = ("pending_icon", "\N{HOURGLASS}")
        elif unit.agent_state == "started":
            status = ("success_icon", "\u2713")
        elif unit.agent_state == "stopped":
            status = ("error_icon", "\N{BLACK FLAG}")
        elif unit.agent_state == "down":
            status = ("error_icon", "\N{DOWNWARDS BLACK ARROW}")
        else:
            # NOTE: Should not get here, if we do make sure we account
            # for that error type above.
            status = ("error_icon", "?")
        return status

    def update_ui_state(self, charm_class, unit, unit_w):
        """ Updates individual machine information
        """
        unit_w.public_address.set_text(unit.public_address)
        unit_w.agent_state.set_text(unit.agent_state)
        unit_w.icon.set_text(self.status_icon_state(charm_class, unit))
        # Special additional status text for these services
        if 'glance-simplestreams-sync' in unit.unit_name:
            status_oneline = get_sync_status().replace("\n", " - ")
            unit_w.workload_info.set_text(status_oneline)

        elif unit.is_horizon and unit.agent_state == "started":
            unit_w.workload_info.set_text(
                "Login: https://{}/horizon "
                "l:{} p:{}".format(
                    unit.public_address,
                    'ubuntu',
                    self.config.getopt('openstack_password')))

        elif unit.is_jujugui and unit.agent_state == "started":
            unit_w.workload_info.set_text(
                "Login: https://{}/".format(
                    unit.public_address))
        else:
            unit_w.workload_info.set_text(
                " {} - {}".format(unit.extended_agent_state,
                                  unit.workload_info))

    def _get_hardware_info(self, unit):
        """Get hardware info from juju or maas

        Returns list of text and formatting tuples
        """
        juju_machine = self.juju_state.machine(unit.machine_id)
        maas_machine = None
        if self.maas_state:
            maas_machine = self.maas_state.machine(juju_machine.instance_id)

        m = juju_machine
        if juju_machine.arch == "N/A":
            if maas_machine:
                m = maas_machine
            else:
                try:
                    return self._get_container_info(unit)
                except:
                    log.exception(
                        "failed to get container info for unit {}.".format(
                            unit))

        hw_info = self._hardware_info_for_machine(m)
        hw_info['machine'] = juju_machine.machine_id
        return hw_info

    def _get_container_info(self, unit):
        """Attempt to get hardware info of host machine for a unit that looks
        like a container.

        """
        base_machine = self.juju_state.base_machine(unit.machine_id)

        if base_machine.arch == "N/A" and self.maas_state is not None:
            m = self.maas_state.machine(base_machine.instance_id)
        else:
            m = base_machine

        # FIXME: Breaks single install status display
        # base_id, container_type, container_id = unit.machine_id.split('/')
        # ctypestr = dict(kvm="VM", lxc="Container")[container_type]

        # rl = ["{} {} (Machine {}".format(ctypestr, container_id,
        #                                  base_id)]
        try:
            container_id = unit.machine_id.split('/')[-1]
        except:
            log.exception("ERROR: base_machine is {} and m is {}, "
                          "and unit.machine_id is {}".format(
                              base_machine, m, unit.machine_id))
            return "?"

        base_id = base_machine.machine_id
        hw_info = self._hardware_info_for_machine(m)
        hw_info['machine'] = base_id
        hw_info['container'] = container_id
        return hw_info

    def _hardware_info_for_machine(self, m):
        return {"arch": m.arch,
                "cpu_cores": m.cpu_cores,
                "mem": m.mem,
                "storage": m.storage,
                "container": '-',
                "machine": 0}

    def _detect_errors(self, unit, charm_class):
        """Look in multiple places for an error.

        Return error info string if present,
        or None if no error is found
        """
        unit_machine = self.juju_state.machine(unit.machine_id)

        if unit.agent_state == "error":
            return unit.agent_state_info.lstrip()

        err_info = ""

        if unit.agent_state == 'pending' and \
           unit_machine.agent_state is '' and \
           unit_machine.agent_state_info is not None:

            # detect MAAS API errors, returned as 409 conflict:
            if "409" in unit_machine.agent_state_info:
                if charm_class.constraints is not None:
                    err_info = "Found no machines meeting constraints: "
                    err_info += ', '.join(["{}='{}'".format(k, v) for k, v
                                           in charm_class.constraints.items()])
                else:
                    err_info += "No machines available for unit."
            else:
                err_info += unit_machine.agent_state_info
            return err_info
        return None

    def get_log_text(self, unit_name):
        name = '-'.join(unit_name.split('/'))
        cmd = ("sudo grep {unit} /var/log/juju-ubuntu-local/all-machines.log "
               " | tail -n 2")
        cmd = cmd.format(unit=name)
        out = utils.get_command_output(cmd)
        if out['status'] == 0 and len(out['output']) > 0:
            return out['output']
        else:
            return "No log matches for {}".format(name)