summaryrefslogtreecommitdiffstats
path: root/cobbler/config.py
blob: 197da913a50b60351bafd711c99a8f9098e2f1b8 (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
# Abstracts out the config file format/access and holds
# reasonable default settings.
#
# Michael DeHaan <mdehaan@redhat.com>

import api
import util
from msg import *
import syck # pysyck > 0.61, so it has dump() 

import os
import traceback

global_settings_file = "/etc/cobbler.conf"
global_state_file = "/var/lib/cobbler/cobbler.conf"


class BootConfig:

    def __init__(self,api):
        """
        Constructor.  This class maintains both the logical
        configuration for Cobbler and the file representation thereof.
        Creating the config object only loads the default values,
        users of this class need to call deserialize() to load config
        file values.  See cobbler.py for how the CLI does it.
        """
        self.api = api
        self.settings_file    = global_settings_file
        self.state_file       = global_state_file
        self.set_defaults()
        self.clear()

    def files_exist(self):
        """
        Returns whether the config files exist.
        """
        return os.path.exists(self.settings_file) and os.path.exists(self.state_file)

    def clear(self):
        """
        Establish an empty list of profiles distros, and systems.
        """
        self.profiles       = api.Profiles(self.api,None)
        self.distros        = api.Distros(self.api,None)
        self.systems        = api.Systems(self.api,None)

    def set_defaults(self):
        """
        Set some reasonable defaults in case no values are available
        """
        self.server         = "localhost"
        self.tftpboot       = "/tftpboot"
        self.dhcpd_conf     = "/etc/dhcpd.conf"
        self.tftpd_conf     = "/etc/xinetd.d/tftp"
        self.pxelinux       = "/usr/lib/syslinux/pxelinux.0"
        self.tftpd_bin      = "/usr/sbin/in.tftpd"
        self.dhcpd_bin      = "/usr/sbin/dhcpd"
        self.httpd_bin      = "/usr/sbin/httpd"
        self.kernel_options = "append devfs=nomount ramdisk_size=16438 lang= vga=788 ksdevice=eth0" #initrd and ks added programmatically

    def get_profiles(self):
        """
        Access the current profiles list
        """
        return self.profiles

    def get_distros(self):
        """
        Access the current distros list
        """
        return self.distros

    def get_systems(self):
        """
        Access the current systems list
        """
        return self.systems

    def config_to_hash(self):
        """
        Save all global config options in hash form (for serialization)
        """
        data = {}
        data["server"]         = self.server
        data['tftpboot']       = self.tftpboot
        data['dhcpd_conf']     = self.dhcpd_conf
        data['tftpd_conf']     = self.tftpd_conf
        data['pxelinux']       = self.pxelinux
        data['tftpd_bin']      = self.tftpd_bin
        data['dhcpd_bin']      = self.dhcpd_bin
        data['httpd_bin']      = self.httpd_bin
        data['kernel_options'] = self.kernel_options
        return data

    def config_from_hash(self,hash):
        """
        Load all global config options from hash form (for deserialization)
        """
        try:
            self.server          = hash['server']
            self.tftpboot        = hash['tftpboot']
            self.dhcpd_conf      = hash['dhcpd_conf']
            self.tftpd_conf      = hash['tftpd_conf']
            self.pxelinux        = hash['pxelinux']
            self.tftpd_bin       = hash['tftpd_bin']
            self.dhcpd_bin       = hash['dhcpd_bin']
            self.httpd_bin       = hash['httpd_bin']
            self.kernel_options  = hash['kernel_options']
        except:
            print "WARNING: config file error: %s" % (self.settings_file)
            self.set_defaults()

    def to_hash(self,is_etc):
        """
        Convert all items cobbler knows about to a nested hash.
        There are seperate hashes for the /etc and /var portions.
        """
        world = {}
        if is_etc:
            world['config']      = self.config_to_hash()
        else:
            world['distros']     = self.get_distros().to_datastruct()
            world['profiles']    = self.get_profiles().to_datastruct()
            world['systems']     = self.get_systems().to_datastruct()
        return world


    def from_hash(self,hash,is_etc):
        """
        Convert a hash representation of a cobbler to 'reality'
        There are seperate hashes for the /etc and /var portions.
        """
        if is_etc:
            self.config_from_hash(hash['config'])
        else:
            self.distros   = api.Distros(self.api, hash['distros'])
            self.profiles  = api.Profiles(self.api,  hash['profiles'])
            self.systems   = api.Systems(self.api, hash['systems'])

    # ------------------------------------------------------
    # we don't care about file formats until below this line

    def serialize(self):
        """
        Save everything to the config file.
        This goes through an intermediate data format so we
        could use YAML later if we wanted.
        """

        settings = None
        state = None

        # ------
        # dump internal state (distros, profiles, systems...) into /var/lib/...
        # /etc is not serialized, it's packaged.

        if not os.path.isdir(os.path.dirname(self.state_file)):
            dirname = os.path.dirname(self.state_file)
            if dirname != "":
                os.makedirs(os.path.dirname(self.state_file))
        try:
            state = open(self.state_file,"w+")
        except:
            self.api.last_error = m("cant_create: %s" % self.state_file)
            return False
        data = self.to_hash(False)
        state.write(syck.dump(data))

        # all good
        return True

    def deserialize(self):
        """
        Load everything from the config file.
        This goes through an intermediate data structure format so we
        could use YAML later if we wanted.
        """

        # -----
        # load global config (pathing, urls, etc)...
        try:
            settings = syck.load(open(self.settings_file,"r").read())
            if settings is not None:
                self.from_hash(settings,True)
            else:
                self.last_error = m("parse_error")
                raise Exception("parse_error")
        except:
            self.api.last_error = m("parse_error")
            raise Exception("parse_error")

        # -----
        # load internal state(distros, systems, profiles...)
        try:
            state = syck.load(open(self.state_file,"r").read())
            if state is not None:
                self.from_hash(state,False)
            else:
                self.last_error = m("parse_error2")
                raise Exception("parse_error2")
        except:
            self.api.last_error = m("parse_error2")
            raise Exception("parse_error2")

        # all good
        return True