Ejemplo n.º 1
0
def update_hardware_info(machine, new_cpus, new_ram):
    """updates cpus and ram of machines"""

    results = query_machines(machine)
    if not results:
        exit_with_error(f'[INFO] No matching machines found.')

    # update machines, one by one
    for r in results:
        try:
            update = {}
            if new_cpus is not None:
                update['cpu_count'] = new_cpus

            if new_ram is not None:
                update['memory'] = new_ram * 1024

            session().Machine.update(system_id=r.system_id, **update)
            print(f'[{r.system_id}] [{r.hostname}]'
                  f' [OK] Updated hardware information: {update}')

        except MaaSError as e:
            exit_with_error(
                f'[{r.system_id}] [{r.hostname}] [ERROR] MaaS: {e}')

    print('Done. Refresh machine list with "jmt_refresh".')
Ejemplo n.º 2
0
def get_juju_status(f_name):
    """parses Juju status JSON and returns as dict"""
    try:
        with open(f_name, 'r') as fin:
            return json.load(fin)

    except json.JSONDecodeError as e:
        exit_with_error(f'[EXCEPTION] Invalid input file: {e}')
Ejemplo n.º 3
0
def update_domain_name(machines, new_domain):
    """updates domain name of machines"""

    if not machines:
        exit_with_error('[ERROR] You did not specify any machines.')

    results = query_machines(machines)
    if not results:
        exit_with_error(f'[INFO] No matching machines found.')

    try:
        # create domain name if needed
        all_domains = session().Domains.read()
        names = [d['name'] for d in all_domains]

        if new_domain not in names:
            print(f'[INFO] Domain {new_domain} does not exist, creating...')
            session().Domains.create(name=new_domain, authoritative=True)

    except MaaSError as e:
        exit_with_error(f'[ERROR] MaaS: {e}')

    # update machines, one by one
    for r in results:
        try:
            session().Machine.update(system_id=r.system_id, domain=new_domain)
            print(f'[{r.system_id}] [{r.hostname}] [OK] Set to {new_domain}')

        except MaaSError as e:
            exit_with_error(
                f'[{r.system_id}] [{r.hostname}] [ERROR] MaaS: {e}')

    print('Done. Refresh machine list with "mjt_refresh".')
Ejemplo n.º 4
0
def add_tags(new_tag, machines):
    """adds tags to machines"""

    if not machines:
        exit_with_error('[ERROR] You did not specify any machines.')

    results = query_machines(machines)
    if not results:
        exit_with_error(f'[INFO] No matching machines found.')

    try:
        # create tag name if needed
        all_tags = session().Tags.read()
        names = [t['name'] for t in all_tags]

        if new_tag not in names:
            print(f'[INFO] Tag {new_tag} does not exist, creating...')
            session().Tags.create(name=new_tag,
                                  description='Helper tag for nagios checks')

    except MaaSError as e:
        exit_with_error(f'[ERROR] MaaS: {e}')

    # updates machines, one by one
    for r in results:
        try:
            session().Tag.update_nodes(name=new_tag, system_id=r.system_id)
            print(f'[{r.system_id}] [{r.hostname}] [OK] Added tag {new_tag}')

        except MaaSError as e:
            exit_with_error(
                f'[{r.system_id}] [{r.hostname}] [ERROR] MaaS: {e}')

    print('Done. Refresh machine list with "mjt_refresh".')
Ejemplo n.º 5
0
def refresh_db():
    """gets data from server and update cache"""
    print('Getting information from MaaS.')

    # Retrieves list of machines
    try:
        s = session()
        machines = s.Machines.read()
        powers = s.Machines.power_parameters()

    except MaaSError as e:
        exit_with_error(f'Could not GET machines: {e}')

    # Updates database info
    new_data = []
    for m in machines:
        try:
            system_id = m.get('system_id', 'UNKNOWN')
            m_power = powers[system_id]

            if is_virtual_machine(m_power):
                print(f'[{system_id}] [{m.get("hostname")}]'
                      f' [INFO] skipping, virtual machine')
                continue

            new_data.append(
                dict(power_address=m_power.get('power_address', ''),
                     power_user=m_power.get('power_user', ''),
                     power_pass=m_power.get('power_pass', ''),
                     fqdn=m['fqdn'],
                     domain=m['domain']['name'],
                     hostname=m['hostname'],
                     system_id=system_id,
                     ip_addresses=', '.join(m['ip_addresses']),
                     cpus=m['cpu_count'],
                     ram=m['memory'] // 1024,
                     tags=','.join(m['tag_names'])))

        except KeyError as e:
            print(f'[{system_id}] [ERROR] Missing information: {e}')

    # Adds new data to the database
    print(f'Updating the database: "{Config.sqlite_db}"')
    MaaSCache.insert(new_data).on_conflict_replace().execute()
    db.commit()

    print('Done.')
Ejemplo n.º 6
0
def get_machine(system_id):
    """asks MaaS for information and print it out"""

    try:
        m = session().Machine.read(system_id=system_id)
    except MaaSError as e:
        exit_with_error(f'[{system_id}] [ERROR] {e}')

    print(json.dumps({
        'system_id': system_id,
        'ip_addresses': ','.join(m['ip_addresses']),
        'tags': ','.join(m['tag_names']),
        'hostname': m['hostname'],
        'domain': m['domain']['name'],
        'fqdn': m['fqdn'],
        'status': m['status_name']
    }, indent=2))
Ejemplo n.º 7
0
def update_host_name(machine, new_hostname):
    """updates host name of machine"""

    results = query_machines([machine])
    if not results:
        exit_with_error(f'[INFO] No matching machines found.')

    # update machines, one by one
    r = results[0]
    try:
        session().Machine.update(system_id=r.system_id, hostname=new_hostname)
        print(f'[{r.system_id}] [{r.hostname}] [OK]'
              f' Updated hostname to {new_hostname}')

    except MaaSError as e:
        exit_with_error(f'[{r.system_id}] [{r.hostname}] [ERROR] MaaS: {e}')

    print('Done. Refresh machine list with "mjt_refresh".')
Ejemplo n.º 8
0
def parse_pynag_services(f_name):
    """parses Nagios hosts. Returns them as a {'ip_address': 'host_name'}
    dict"""

    with open(f_name, 'r') as fin:
        pynag = fin.read()

    result = defaultdict(lambda: [])
    try:
        for line in pynag.split('\n'):
            if not line:
                continue

            hostname, service = line.split('|')
            result[hostname].append(service)

    except (TypeError, ValueError) as e:
        exit_with_error(f'[EXCEPTION] Invalid Nagios hosts format: {e}')

    return result
Ejemplo n.º 9
0
def parse_pynag_hosts(f_name):
    """parses Nagios hosts. Returns them as a {'ip_address': 'host_name'}
    dict"""

    with open(f_name, 'r') as fin:
        pynag = fin.read()

    result = {}
    try:
        for line in pynag.split('\n'):
            if not line:
                continue

            address, hostname = line.split('|')
            result[address] = hostname

    except (TypeError, ValueError) as e:
        exit_with_error(f'[EXCEPTION] Invalid Nagios hosts format: {e}')

    return result
Ejemplo n.º 10
0
def ipmi_sel(cmd, machines):
    """lists or clear SEL of @machines"""

    results = query_machines(machines)
    if not results:
        exit_with_error(f'[INFO] No matching machines found.')

    # update machines, one by one
    for r in results:
        print(f'## [{r.system_id}] [{r.hostname}]')

        command_line = [
            'ipmi-sel', '-h', r.power_address, '-u', r.power_user, '-p',
            r.power_pass
        ]

        if cmd == 'clear':
            command_line.append('--clear')

        subprocess.run(command_line)
Ejemplo n.º 11
0
def main():
    """parses arguments and run proper command"""

    parser = argparse.ArgumentParser(
        description='Manage node script results. '
                    'See maasjuju_toolkit/maas/script_results.py for examples'
    )
    parser.add_argument(
        'command',
        choices=['list', 'suppress', 'delete', 'unsuppress',
                 'suppress_id', 'delete_id', 'unsuppress_id'],
        help='What to do'
    )
    parser.add_argument(
        'machines', type=str, default=[], nargs='*'
    )
    parser.add_argument(
        '--script-id', type=str
    )
    for x in ['Installation', 'Passed', 'Commissioning',
              'Testing', 'Skipped', 'Aborted']:
        parser.add_argument(
            f'--no-{x.lower()}',
            const=x,
            action='append_const',
            dest='skip',
            help=f'Ignore {x} script results'
        )

    # set skip categories, always skip running tests
    args = parser.parse_args()
    if args.skip is None:
        skip = {'Running'}
    else:
        skip = {'Running', *args.skip}

    # check if script id is required
    if args.command.endswith('_id') and args.script_id is None:
        exit_with_error('[ERROR] No script id passed')

    script_results(args.command, args.machines, args.script_id, skip)
Ejemplo n.º 12
0
def get_script_results(machine, skip):
    """returns all script group results, along with result status"""

    if isinstance(machine, str):
        query = [machine]
    else:
        query = machine

    machines = query_machines(query)
    if not machines:
        exit_with_error(f'UNKNOWN: No matching machine: {machine}', code=3)

    api = session()

    results = {}
    for m in machines:
        scripts = api.NodeScriptResults.read(system_id=m.system_id)
        for s in scripts:
            if s['type_name'] in skip or s['status_name'] in skip:
                continue

            if m.system_id not in results:
                results[m.system_id] = {}

            suppressed = [r for r in s['results'] if r['suppressed']]
            ids = ','.join([str(r['id']) for r in s['results']])
            results[m.system_id].update({
                s['id']: {
                    'type': s['type_name'],
                    'status': s['status_name'],
                    'total': len(s['results']),
                    'suppressed': len(suppressed),
                    'individual_ids': ids
                }
            })

    return results
Ejemplo n.º 13
0
def script_results(command, machine, script_id, skip):
    """calls appropriate command"""
    if command == 'list':
        print(json.dumps(get_script_results(machine, skip), indent=2))

    elif command in ['suppress', 'unsuppress']:
        set_suppressed(machine, skip, bool(command == 'suppress'))

    elif command in ['suppress_id', 'unsuppress_id']:
        if machine == '':
            exit_with_error('ERROR: No machine name')
        if script_id == '':
            exit_with_error('ERROR: No script id')

        set_suppressed_id(machine, script_id, bool(command == 'suppress_id'))

    elif command == 'delete':
        delete_results(machine, skip)

    elif command == 'delete_id':
        delete_result_id(machine, script_id)

    else:
        exit_with_error(f'Unknown command: {command}')
Ejemplo n.º 14
0
def nagios_juju_deps(juju_status, pynag_hosts, pynag_services, subnet,
                     outfile):
    """generates Nagios host and service dependencies and writes to outfile"""
    hosts = parse_pynag_hosts(pynag_hosts)
    services = parse_pynag_services(pynag_services)
    juju = get_juju_status(juju_status)

    output = ''
    try:
        # p_address, p_host:  IP address and hostname of parent host
        # d_address, d_host:  IP address and hostname of dependent host

        for machine in juju['machines'].values():

            p_host = None
            for p_address in machine['ip-addresses']:
                p_host = hosts.get(p_address)
                if p_host is not None:
                    break

            if p_host is None:
                print('[WARN] [{}] Unknown Nagios host: ({})'.format(
                    machine['display-name'], machine['ip-addresses']))

                cons = machine.get('containers')
                if cons:
                    print('[WARN] [{}] Has {} containers. Will create'.format(
                        machine['display-name'], len(cons)))

                    ip_address = None
                    for ip in machine['ip-addresses']:
                        if IPAddress(ip_address) in IPNetwork(subnet):
                            ip_address = ip
                            print(f'Will use IP address {ip_address}')
                            break

                    if not ip_address:
                        print('[WARN] [{}] No IPs in {}'.format(
                            machine['display-name'], subnet))
                        print('Choose which IP address to use:')

                        while ip_address not in machine['ip-addresses']:
                            ip_address = input('> ')

                    output += (HOST_TEMPLATE.replace(
                        '{COMMENT}',
                        'Auto created by mjt_juju_nagios_deps').replace(
                            '{DISPLAY_NAME}', machine['display-name']).replace(
                                '{IP_ADDRESS}', ip_address))

                    p_host = machine['display-name']
                else:
                    print('[WARN] [{}] has no containers, skipping'.format(
                        machine['display-name']))

            if WELL_KNOWN_SERVICE not in services.get(p_host, []):
                print('[WARN] [{}] Service {} does not exist'.format(
                    p_host, WELL_KNOWN_SERVICE))

            try:
                containers = machine['containers']
            except KeyError:
                continue

            for name, container in containers.items():
                d_host = None
                for d_address in container['ip-addresses']:
                    d_host = hosts.get(d_address)
                    if d_host is not None:
                        break

                if d_host is None:
                    print('[WARN] [{}] Unknown Nagios host ({})'.format(
                        container['instance-id'], container['ip-addresses']))
                    continue

                # adds host dependencies
                output += (HOST_DEPENDENCY_TEMPLATE.replace(
                    '{COMMENT}', f'({container["instance-id"]}) '
                    f'-> {machine["display-name"]}').replace(
                        '{PARENT}', p_host).replace('{CHILD}', d_host))

                for service in services.get(d_host, []):
                    output += (SERVICE_DEPENDENCY_TEMPLATE.replace(
                        '{COMMENT}',
                        f'({container["instance-id"]}/{service}) -> '
                        f'{machine["display-name"]}/{WELL_KNOWN_SERVICE}'
                    ).replace('{PARENT_HOST}', p_host).replace(
                        '{PARENT_SERVICE}', WELL_KNOWN_SERVICE).replace(
                            '{DEPENDENT_HOST}',
                            d_host).replace('{DEPENDENT_SERVICE}', service))

    except KeyError as e:
        exit_with_error(
            f'[EXCEPTION] Input data is not JSON-formatted Juju status: {e}')

    try:
        with open(outfile, 'w') as f_out:
            f_out.write(output)

        print('[SUCCESS] Configuration was written to', outfile)
    except OSError as e:
        print(f'[EXCEPTION] Writing to {outfile} failed: {e}')