proxy_show.py 7 KB
Newer Older
1
# -*- coding: utf-8 -*-
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
##############################################################################
#
# Copyright (c) 2010-2014 Vifib SARL and Contributors.
# All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################
29 30

import collections
31
import hashlib
32

33
import lxml.etree
Marco Mariani's avatar
Marco Mariani committed
34
import prettytable
35 36
import sqlite3

Marco Mariani's avatar
Marco Mariani committed
37 38
from slapos.cli.config import ConfigCommand
from slapos.proxy import ProxyConfig
39 40 41
from slapos.proxy.db_version import DB_VERSION


42
class ProxyShowCommand(ConfigCommand):
43
    """
44
    display proxy instances and parameters
45 46
    """

47 48 49 50 51 52
    def get_parser(self, prog_name):
        ap = super(ProxyShowCommand, self).get_parser(prog_name)

        ap.add_argument('-u', '--database-uri',
                        help='URI for sqlite database')

53 54 55 56 57 58 59 60 61 62 63 64 65 66
        ap.add_argument('--computers',
                        help='view computer information',
                        action='store_true')

        ap.add_argument('--software',
                        help='view software releases',
                        action='store_true')

        ap.add_argument('--partitions',
                        help='view partitions',
                        action='store_true')

        ap.add_argument('--slaves',
                        help='view slave instances',
67 68 69 70 71 72 73
                        action='store_true')

        ap.add_argument('--params',
                        help='view published parameters',
                        action='store_true')

        ap.add_argument('--network',
74
                        help='view network settings',
75 76 77 78 79 80
                        action='store_true')

        return ap

    def take_action(self, args):
        configp = self.fetch_config(args)
81
        conf = ProxyConfig(logger=self.app.log)
82 83 84
        conf.mergeConfig(args, configp)
        conf.setConfig()
        do_show(conf=conf)
85 86 87 88


tbl_partition = 'partition' + DB_VERSION

Marco Mariani's avatar
Marco Mariani committed
89 90 91 92 93 94 95

def coalesce(*seq):
    el = None
    for el in seq:
        if el is not None:
            return el
    return el
96 97


Marco Mariani's avatar
Marco Mariani committed
98
def log_table(logger, qry, tablename, skip=None):
99 100 101 102
    if skip is None:
        skip = set()

    columns = [c[0] for c in qry.description if c[0] not in skip]
Marco Mariani's avatar
Marco Mariani committed
103

104 105
    rows = []
    for row in qry.fetchall():
Marco Mariani's avatar
Marco Mariani committed
106
        rows.append([coalesce(row[col], '-') for col in columns])
107

Marco Mariani's avatar
Marco Mariani committed
108 109
    pt = prettytable.PrettyTable(columns)
    # https://code.google.com/p/prettytable/wiki/Tutorial
110

Marco Mariani's avatar
Marco Mariani committed
111 112
    for row in rows:
        pt.add_row(row)
113 114

    if rows:
115
        if skip:
Marco Mariani's avatar
Marco Mariani committed
116
            logger.info('table %s: skipping %s', tablename, ', '.join(skip))
117
        else:
Marco Mariani's avatar
Marco Mariani committed
118
            logger.info('table %s', tablename)
119
    else:
Marco Mariani's avatar
Marco Mariani committed
120
        logger.info('table %s: empty', tablename)
121 122
        return

Marco Mariani's avatar
Marco Mariani committed
123 124
    for line in pt.get_string(border=True, padding_width=0, vrules=prettytable.NONE).split('\n'):
        logger.info(line)
125 126


Marco Mariani's avatar
Marco Mariani committed
127
def log_params(logger, conn):
128 129 130 131 132 133 134 135
    cur = conn.cursor()

    qry = cur.execute("SELECT reference, partition_reference, software_type, connection_xml FROM %s" % tbl_partition)
    for row in qry.fetchall():
        if not row['connection_xml']:
            continue

        xml = str(row['connection_xml'])
Marco Mariani's avatar
Marco Mariani committed
136
        logger.info('%s: %s (type %s)', row['reference'], row['partition_reference'], row['software_type'])
137 138 139 140 141 142
        instance = lxml.etree.fromstring(xml)
        for parameter in list(instance):
            name = parameter.get('id')
            text = parameter.text
            if text and name in ('ssh-key', 'ssh-public-key'):
                text = text[:20] + '...' + text[-20:]
Marco Mariani's avatar
Marco Mariani committed
143
            logger.info('    %s = %s', name, text)
144 145


Marco Mariani's avatar
Marco Mariani committed
146
def log_computer_table(logger, conn):
147
    tbl_computer = 'computer' + DB_VERSION
148 149
    cur = conn.cursor()
    qry = cur.execute("SELECT * FROM %s" % tbl_computer)
Marco Mariani's avatar
Marco Mariani committed
150
    log_table(logger, qry, tbl_computer)
151 152


Marco Mariani's avatar
Marco Mariani committed
153
def log_software_table(logger, conn):
154
    tbl_software = 'software' + DB_VERSION
155
    cur = conn.cursor()
156
    qry = cur.execute("SELECT *, md5(url) as md5 FROM %s" % tbl_software)
Marco Mariani's avatar
Marco Mariani committed
157
    log_table(logger, qry, tbl_software)
158 159


Marco Mariani's avatar
Marco Mariani committed
160
def log_partition_table(logger, conn):
161 162
    cur = conn.cursor()
    qry = cur.execute("SELECT * FROM %s WHERE slap_state<>'free'" % tbl_partition)
Marco Mariani's avatar
Marco Mariani committed
163
    log_table(logger, qry, tbl_partition, skip=['xml', 'connection_xml', 'slave_instance_list'])
164

165

Marco Mariani's avatar
Marco Mariani committed
166
def log_slave_table(logger, conn):
167
    tbl_slave = 'slave' + DB_VERSION
168 169
    cur = conn.cursor()
    qry = cur.execute("SELECT * FROM %s" % tbl_slave)
Marco Mariani's avatar
Marco Mariani committed
170
    log_table(logger, qry, tbl_slave, skip=['connection_xml'])
171 172


Marco Mariani's avatar
Marco Mariani committed
173
def log_network(logger, conn):
174
    tbl_partition_network = 'partition_network' + DB_VERSION
175 176 177 178 179 180 181 182 183 184 185 186 187 188
    cur = conn.cursor()
    addr = collections.defaultdict(list)
    qry = cur.execute("""
                      SELECT * FROM %s
                       WHERE partition_reference NOT IN (
                                                SELECT reference
                                                  FROM %s
                                                 WHERE slap_state='free')
                        """ % (tbl_partition_network, tbl_partition))
    for row in qry:
        addr[row['partition_reference']].append(row['address'])

    for partition_reference in sorted(addr.keys()):
        addresses = addr[partition_reference]
Marco Mariani's avatar
Marco Mariani committed
189
        logger.info('%s: %s', partition_reference, ', '.join(addresses))
190 191


192
def do_show(conf):
Marco Mariani's avatar
Marco Mariani committed
193
    conf.logger.debug('Using database: %s', conf.database_uri)
194
    conn = sqlite3.connect(conf.database_uri)
195 196
    conn.row_factory = sqlite3.Row

197 198
    conn.create_function('md5', 1, lambda s: hashlib.md5(s).hexdigest())

Marco Mariani's avatar
Marco Mariani committed
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    call_table = [
        (conf.computers, log_computer_table),
        (conf.software, log_software_table),
        (conf.partitions, log_partition_table),
        (conf.slaves, log_slave_table),
        (conf.params, log_params),
        (conf.network, log_network)
    ]

    if not any(flag for flag, func in call_table):
        to_call = [func for flag, func in call_table]
    else:
        to_call = [func for flag, func in call_table if flag]

    for idx, func in enumerate(to_call):
        func(conf.logger, conn)
        if idx < len(to_call) - 1:
            conf.logger.info(' ')