~ubuntu-branches/ubuntu/raring/maas/raring-proposed

« back to all changes in this revision

Viewing changes to src/provisioningserver/config.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez
  • Date: 2012-07-17 08:28:36 UTC
  • mfrom: (1.1.16)
  • Revision ID: package-import@ubuntu.com-20120717082836-ucb2vou8tqg353eq
Tags: 0.1+bzr777+dfsg-0ubuntu1
* New upstream release
* Only run 'maas' command as root. (LP: #974046)
  - debian/extras/maas: Check id.
  - debian/maas.install: Install in 'sbin'.
* debian/maas.postinst:
  - restart apache2 after everything gets processed.
  - Update version to handle upgrades.
* debian/extras/maas-provision: Add wrapper to access 'maasprovisiong'
  command line.
* debian/patches/99_temporary_fix_path.patch: Dropped. No longer needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2012 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
"""MAAS Provisioning Configuration."""
 
5
 
 
6
from __future__ import (
 
7
    absolute_import,
 
8
    print_function,
 
9
    unicode_literals,
 
10
    )
 
11
 
 
12
__metaclass__ = type
 
13
__all__ = [
 
14
    "Config",
 
15
    ]
 
16
 
 
17
from getpass import getuser
 
18
from os import (
 
19
    environ,
 
20
    urandom,
 
21
    )
 
22
from os.path import abspath
 
23
from threading import RLock
 
24
 
 
25
from formencode import Schema
 
26
from formencode.declarative import DeclarativeMeta
 
27
from formencode.validators import (
 
28
    Int,
 
29
    RequireIfPresent,
 
30
    String,
 
31
    URL,
 
32
    )
 
33
import yaml
 
34
 
 
35
 
 
36
class ConfigOops(Schema):
 
37
    """Configuration validator for OOPS options."""
 
38
 
 
39
    if_key_missing = None
 
40
 
 
41
    directory = String(if_missing=b"")
 
42
    reporter = String(if_missing=b"")
 
43
 
 
44
    chained_validators = (
 
45
        RequireIfPresent("reporter", present="directory"),
 
46
        )
 
47
 
 
48
 
 
49
class ConfigBroker(Schema):
 
50
    """Configuration validator for message broker options."""
 
51
 
 
52
    if_key_missing = None
 
53
 
 
54
    host = String(if_missing=b"localhost")
 
55
    port = Int(min=1, max=65535, if_missing=5673)
 
56
    username = String(if_missing=getuser())
 
57
    password = String(if_missing=b"test")
 
58
    vhost = String(if_missing="/")
 
59
 
 
60
 
 
61
class ConfigCobbler(Schema):
 
62
    """Configuration validator for connecting to Cobbler."""
 
63
 
 
64
    if_key_missing = None
 
65
 
 
66
    url = URL(
 
67
        add_http=True, require_tld=False,
 
68
        if_missing=b"http://localhost/cobbler_api",
 
69
        )
 
70
    username = String(if_missing=getuser())
 
71
    password = String(if_missing=b"test")
 
72
 
 
73
 
 
74
class ConfigTFTP(Schema):
 
75
    """Configuration validator for the TFTP service."""
 
76
 
 
77
    if_key_missing = None
 
78
 
 
79
    root = String(if_missing="/var/lib/tftpboot")
 
80
    port = Int(min=1, max=65535, if_missing=5244)
 
81
    generator = URL(
 
82
        add_http=True, require_tld=False,
 
83
        if_missing=b"http://localhost:5243/api/1.0/pxeconfig",
 
84
        )
 
85
 
 
86
 
 
87
class ConfigMeta(DeclarativeMeta):
 
88
    """Metaclass for the root configuration schema."""
 
89
 
 
90
    def _get_default_filename(cls):
 
91
        # Get the configuration filename from the environment. Failing that,
 
92
        # return a hard-coded default.
 
93
        return environ.get(
 
94
            "MAAS_PROVISIONING_SETTINGS",
 
95
            "/etc/maas/pserv.yaml")
 
96
 
 
97
    def _set_default_filename(cls, filename):
 
98
        # Set the configuration filename in the environment.
 
99
        environ["MAAS_PROVISIONING_SETTINGS"] = filename
 
100
 
 
101
    def _delete_default_filename(cls):
 
102
        # Remove any setting of the configuration filename from the
 
103
        # environment.
 
104
        environ.pop("MAAS_PROVISIONING_SETTINGS", None)
 
105
 
 
106
    DEFAULT_FILENAME = property(
 
107
        _get_default_filename, _set_default_filename,
 
108
        _delete_default_filename, doc=(
 
109
            "The default config file to load. Refers to "
 
110
            "MAAS_PROVISIONING_SETTINGS in the environment."))
 
111
 
 
112
 
 
113
class Config(Schema):
 
114
    """Configuration validator."""
 
115
 
 
116
    __metaclass__ = ConfigMeta
 
117
 
 
118
    if_key_missing = None
 
119
 
 
120
    interface = String(if_empty=b"", if_missing=b"127.0.0.1")
 
121
    port = Int(min=1, max=65535, if_missing=5241)
 
122
    username = String(not_empty=True, if_missing=getuser())
 
123
    password = String(not_empty=True, if_missing=urandom(12))
 
124
    logfile = String(if_empty=b"pserv.log", if_missing=b"pserv.log")
 
125
    oops = ConfigOops
 
126
    broker = ConfigBroker
 
127
    cobbler = ConfigCobbler
 
128
    tftp = ConfigTFTP
 
129
 
 
130
    @classmethod
 
131
    def parse(cls, stream):
 
132
        """Load a YAML configuration from `stream` and validate."""
 
133
        return cls.to_python(yaml.safe_load(stream))
 
134
 
 
135
    @classmethod
 
136
    def load(cls, filename=None):
 
137
        """Load a YAML configuration from `filename` and validate."""
 
138
        if filename is None:
 
139
            filename = cls.DEFAULT_FILENAME
 
140
        with open(filename, "rb") as stream:
 
141
            return cls.parse(stream)
 
142
 
 
143
    _cache = {}
 
144
    _cache_lock = RLock()
 
145
 
 
146
    @classmethod
 
147
    def load_from_cache(cls, filename=None):
 
148
        """Load or return a previously loaded configuration.
 
149
 
 
150
        This is thread-safe, so is okay to use from Django, for example.
 
151
        """
 
152
        if filename is None:
 
153
            filename = cls.DEFAULT_FILENAME
 
154
        filename = abspath(filename)
 
155
        with cls._cache_lock:
 
156
            if filename not in cls._cache:
 
157
                with open(filename, "rb") as stream:
 
158
                    cls._cache[filename] = cls.parse(stream)
 
159
            return cls._cache[filename]
 
160
 
 
161
    @classmethod
 
162
    def field(target, *steps):
 
163
        """Obtain a field by following `steps`."""
 
164
        for step in steps:
 
165
            target = target.fields[step]
 
166
        return target