aboutsummaryrefslogtreecommitdiffstats
path: root/tools/python/xen/xend/XendRoot.py
blob: d1bd503f8a20907486eb03d9db13e84014cdf5ca (plain)
1
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>

"""Xend root class.
Creates the event server and handles configuration.

Other classes get config variables by importing this module,
using instance() to get a XendRoot instance, and then
the config functions (e.g. get_xend_port()) to get
configured values.
"""

import os
import os.path
import sys

import EventServer
from XendLogging import XendLogging
from XendError import XendError

# Initial create of the event server.
eserver = EventServer.instance()

import sxp

class XendRoot:
    """Root of the management classes."""

    """Default path to the root of the database."""
    dbroot_default = "/var/lib/xen/xend-db"

    """Default path to the config file."""
    config_default = "/etc/xen/xend-config.sxp"

    """Environment variable used to override config_default."""
    config_var     = "XEND_CONFIG"

    """Where network control scripts live."""
    network_script_dir = "/etc/xen/scripts"

    """Where block control scripts live."""
    block_script_dir = "/etc/xen/scripts"

    """Default path to the log file. """
    logfile_default = "/var/log/xend.log"

    """Default level of information to be logged."""
    loglevel_default = 'DEBUG'

    """Default for the flag indicating whether xend should run an http server."""
    xend_http_server_default = 'no'

    """Default interface address xend listens at. """
    xend_address_default      = ''

    """Default for the flag indicating whether xend should run a relocation server."""
    xend_relocation_server_default = 'yes'

    """Default interface address the xend relocation server listens at. """
    xend_relocation_address_default = ''

    """Default port xend serves HTTP at. """
    xend_port_default         = '8000'

    """Default port xend serves events at. """
    xend_event_port_default   = '8001'

    """Default port xend serves relocation at. """
    xend_relocation_port_default = '8002'

    """Default for the flag indicating whether xend should run a unix-domain server."""
    xend_unix_server_default = 'yes'

    """Default path the unix-domain server listens at."""
    xend_unix_path_default = '/var/lib/xend/xend-socket'

    """Default interface address xend listens at for consoles."""
    console_address_default   = 'localhost'

    """Default port xend serves consoles at. """
    console_port_base_default = '9600'

    components = {}

    def __init__(self):
        self.dbroot = None
        self.config_path = None
        self.config = None
        self.logging = None
        self.configure()
        eserver.subscribe('xend.*', self.event_handler)
        #eserver.subscribe('xend.domain.created', self.event_handler)
        #eserver.subscribe('xend.domain.died', self.event_handler)

    def add_component(self, name, val):
        """Add a xend component.

        @param name: component name
        @param val:  component object
        """
        self.components[name] = val

    def get_component(self, name):
        """Get a xend component from its name.
        This is used as a work-round for problems caused by mutually
        recursive imports.

        @param name: component name
        @return: component object (or None)
        """
        return self.components.get(name)

    def start(self):
        eserver.inject('xend.start', 0)

    def _format(self, msg, args):
        if args:
            return str(msg) % args
        else:
            return str(msg)

    def _log(self, mode, fmt, args):
        """Logging function that uses the logger if it exists, otherwise
        logs to stderr. We use this for XendRoot log messages because
        they may be logged before the logger has been configured.
        Other components can safely use the logger.
        """
        log = self.get_logger()
        if mode not in ['warning', 'info', 'debug', 'error']:
            mode = 'info'
        level = mode.upper()
        if log:
            getattr(log, mode)(fmt, *args)
        else:
            print >>sys.stderr, "xend", "[%s]" % level, self._format(fmt, args)

    def logDebug(self, fmt, *args):
        """Log a debug message.

        @param fmt: message format
        @param args: arguments
        """
        self._log('debug', fmt, args)
        
    def logInfo(self, fmt, *args):
        """Log an info message.

        @param fmt: message format
        @param args: arguments
        """
        self._log('info', fmt, args)

    def logWarning(self, fmt, *args):
        """Log a warning message.

        @param fmt: message format
        @param args: arguments
        """
        self._log('warning', fmt, args)
        
    def logError(self, fmt, *args):
        """Log an error message.

        @param fmt: message format
        @param args: arguments
        """
        self._log('error', fmt, args)
        
    def event_handler(self, event, val):
        self.logInfo("EVENT> %s %s", str(event), str(val))

    def configure(self):
        self.set_config()
        self.configure_logger()
        self.dbroot = self.get_config_value("dbroot", self.dbroot_default)

    def configure_logger(self):
        logfile = self.get_config_value("logfile", self.logfile_default)
        loglevel = self.get_config_value("loglevel", self.loglevel_default)
        self.logging = XendLogging(logfile, level=loglevel)
        #self.logging.addLogStderr()

    def get_logging(self):
        """Get the XendLogging instance.
        """
        return self.logging

    def get_logger(self):
        """Get the logger.
        """
        return self.logging and self.logging.getLogger()

    def get_dbroot(self):
        """Get the path to the database root.
        """
        return self.dbroot

    def set_config(self):
        """If the config file exists, read it. If not, ignore it.

        The config file is a sequence of sxp forms.
        """
        self.config_path = os.getenv(self.config_var, self.config_default)
        if os.path.exists(self.config_path):
            #self.logInfo('Reading config file %s', self.config_path)
            try:
                fin = file(self.config_path, 'rb')
                try:
                    config = sxp.parse(fin)
                finally:
                    fin.close()
                config.insert(0, 'xend-config')
                self.config = config
            except Exception, ex:
                self.logError('Reading config file %s: %s', self.config_path, str(ex))
                raise
        else:
            self.logError('Config file does not exist: %s', self.config_path)
            self.config = ['xend-config']

    def get_config(self, name=None):
        """Get the configuration element with the given name, or
        the whole configuration if no name is given.

        @param name: element name (optional)
        @return: config or none
        """
        if name is None:
            val = self.config
        else:
            val = sxp.child(self.config, name)
        return val

    def get_config_value(self, name, val=None):
        """Get the value of an atomic configuration element.

        @param name: element name
        @param val:  default value (optional, defaults to None)
        @return: value
        """
        return sxp.child_value(self.config, name, val=val)

    def get_config_bool(self, name, val=None):
        v = self.get_config_value(name, val)
        if v in ['yes', '1', 'on', 1, True]:
            return True
        if v in ['no', '0', 'off', 0, False]:
            return False
        raise XendError("invalid xend config %s: expected bool: %s" % (name, v))

    def get_config_int(self, name, val=None):
        v = self.get_config_value(name, val)
        try:
            return int(v)
        except Exception, ex:
            raise XendError("invalid xend config %s: expected int: %s" % (name, v))

    def get_xend_http_server(self):
        """Get the flag indicating whether xend should run an http server.
        """
        return self.get_config_bool("xend-http-server", self.xend_http_server_default)

    def get_xend_relocation_server(self):
        """Get the flag indicating whether xend should run a relocation server.
        """
        return self.get_config_bool("xend-relocation-server", self.xend_relocation_server_default)

    def get_xend_port(self):
        """Get the port xend listens at for its HTTP interface.
        """
        return self.get_config_int('xend-port', self.xend_port_default)

    def get_xend_event_port(self):
        """Get the port xend listens at for connection to its event server.
        """
        return self.get_config_int('xend-event-port', self.xend_event_port_default)

    def get_xend_relocation_port(self):
        """Get the port xend listens at for connection to its relocation server.
        """
        return self.get_config_int('xend-relocation-port', self.xend_relocation_port_default)

    def get_xend_address(self):
        """Get the address xend listens at for its HTTP and event ports.
        This defaults to the empty string which allows all hosts to connect.
        If this is set to 'localhost' only the localhost will be able to connect
        to the HTTP and event ports.
        """
        return self.get_config_value('xend-address', self.xend_address_default)

    def get_xend_relocation_address(self):
        """Get the address xend listens at for its relocation server port.
        This defaults to the empty string which allows all hosts to connect.
        If this is set to 'localhost' only the localhost will be able to connect
        to the HTTP and event ports.
        """
        return self.get_config_value('xend-relocation-address', self.xend_relocation_address_default)

    def get_xend_unix_server(self):
        """Get the flag indicating whether xend should run a unix-domain server.
        """
        return self.get_config_bool("xend-unix-server", self.xend_unix_server_default)

    def get_xend_unix_path(self):
        """Get the path the xend unix-domain server listens at.
        """
        return self.get_config_value("xend-unix-path", self.xend_unix_path_default)

    def get_console_address(self):
        """Get the address xend listens at for its console ports.
        This defaults to 'localhost', allowing only the localhost to connect
        to the console ports.  Setting this to the empty string, allows all
        hosts to connect.
        """
        return self.get_config_value('console-address', self.console_address_default)

    def get_console_port_base(self):
        """Get the base port number used to generate console ports for domains.
        """
        return self.get_config_int('console-port-base', self.console_port_base_default)

    def get_block_script(self, type):
        return self.get_config_value('block-%s' % type, '')

    def get_network_script(self):
        return self.get_config_value('network-script', 'network')

    def get_enable_dump(self):
        return self.get_config_value('enable-dump', 'false')

    def get_vif_bridge(self):
        return self.get_config_value('vif-bridge', 'xen-br0')

    def get_vif_script(self):
        return self.get_config_value('vif-script', 'vif-bridge')

    def get_vif_antispoof(self):
        return self.get_config_bool('vif-antispoof', 'yes')

def instance():
    """Get an instance of XendRoot.
    Use this instead of the constructor.
    """
    global inst
    try:
        inst
    except:
        inst = XendRoot()
    return inst

def logger():
    """Get the logger.
    """
    return instance().get_logger()

def add_component(name, val):
    """Register a component with XendRoot.
    This is used to work-round import cycles.

    @param name: component name
    @param val:  component value (often a module)
    """
    return instance().add_component(name, val)

def get_component(name):
    """Get a component.
    This is used to work-round import cycles.

    @param name: component name
    @return component or None
    """
    return instance().get_component(name)