~harlowja/cloud-init/ds-openstack

« back to all changes in this revision

Viewing changes to cloudinit/distros/freebsd.py

  • Committer: Joshua Harlow
  • Date: 2014-02-07 23:14:26 UTC
  • mfrom: (913.1.22 trunk)
  • Revision ID: harlowja@yahoo-inc.com-20140207231426-2natgf64l4o055du
Remerged with trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vi: ts=4 expandtab
 
2
#
 
3
#    Copyright (C) 2014 Harm Weites
 
4
#
 
5
#    Author: Harm Weites <harm@weites.com>
 
6
#
 
7
#    This program is free software: you can redistribute it and/or modify
 
8
#    it under the terms of the GNU General Public License version 3, as
 
9
#    published by the Free Software Foundation.
 
10
#
 
11
#    This program is distributed in the hope that it will be useful,
 
12
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
#    GNU General Public License for more details.
 
15
#
 
16
#    You should have received a copy of the GNU General Public License
 
17
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 
 
19
from StringIO import StringIO
 
20
 
 
21
import re
 
22
 
 
23
from cloudinit import distros
 
24
from cloudinit import helpers
 
25
from cloudinit import log as logging
 
26
from cloudinit import ssh_util
 
27
from cloudinit import util
 
28
 
 
29
LOG = logging.getLogger(__name__)
 
30
 
 
31
 
 
32
class Distro(distros.Distro):
 
33
    rc_conf_fn = "/etc/rc.conf"
 
34
    login_conf_fn = '/etc/login.conf'
 
35
    login_conf_fn_bak = '/etc/login.conf.orig'
 
36
 
 
37
    def __init__(self, name, cfg, paths):
 
38
        distros.Distro.__init__(self, name, cfg, paths)
 
39
        # This will be used to restrict certain
 
40
        # calls from repeatly happening (when they
 
41
        # should only happen say once per instance...)
 
42
        self._runner = helpers.Runners(paths)
 
43
        self.osfamily = 'freebsd'
 
44
 
 
45
    # Updates a key in /etc/rc.conf.
 
46
    def updatercconf(self, key, value):
 
47
        LOG.debug("updatercconf: %s => %s", key, value)
 
48
        conf = self.loadrcconf()
 
49
        config_changed = False
 
50
        for item in conf:
 
51
            if item == key and conf[item] != value:
 
52
                conf[item] = value
 
53
                LOG.debug("[rc.conf]: Value %s for key %s needs to be changed",
 
54
                          value, key)
 
55
                config_changed = True
 
56
 
 
57
        if config_changed:
 
58
            LOG.debug("Writing new %s file", self.rc_conf_fn)
 
59
            buf = StringIO()
 
60
            for keyval in conf.items():
 
61
                buf.write("%s=%s\n" % keyval)
 
62
            util.write_file(self.rc_conf_fn, buf.getvalue())
 
63
 
 
64
    # Load the contents of /etc/rc.conf and store all keys in a dict.
 
65
    def loadrcconf(self):
 
66
        conf = {}
 
67
        lines = util.load_file(self.rc_conf_fn).splitlines()
 
68
        for line in lines:
 
69
            tok = line.split('=')
 
70
            conf[tok[0]] = tok[1].rstrip()
 
71
        return conf
 
72
 
 
73
    def readrcconf(self, key):
 
74
        conf = self.loadrcconf()
 
75
        try:
 
76
            val = conf[key]
 
77
        except KeyError:
 
78
            val = None
 
79
        return val
 
80
 
 
81
    def _read_system_hostname(self):
 
82
        sys_hostname = self._read_hostname()
 
83
        return ('rc.conf', sys_hostname)
 
84
 
 
85
    def _read_hostname(self, filename, default=None):
 
86
        hostname = None
 
87
        try:
 
88
            hostname = self.readrcconf('hostname')
 
89
        except IOError:
 
90
            pass
 
91
        if not hostname:
 
92
            return default
 
93
        return hostname
 
94
 
 
95
    def _select_hostname(self, hostname, fqdn):
 
96
        if not hostname:
 
97
            return fqdn
 
98
        return hostname
 
99
 
 
100
    def _write_hostname(self, hostname, filename):
 
101
        self.updatercconf('hostname', hostname)
 
102
 
 
103
    def create_group(self, name, members):
 
104
        group_add_cmd = ['pw', '-n', name]
 
105
        if util.is_group(name):
 
106
            LOG.warn("Skipping creation of existing group '%s'", name)
 
107
        else:
 
108
            try:
 
109
                util.subp(group_add_cmd)
 
110
                LOG.info("Created new group %s", name)
 
111
            except Exception as e:
 
112
                util.logexc(LOG, "Failed to create group %s", name)
 
113
                raise e
 
114
 
 
115
        if len(members) > 0:
 
116
            for member in members:
 
117
                if not util.is_user(member):
 
118
                    LOG.warn("Unable to add group member '%s' to group '%s'"
 
119
                             "; user does not exist.", member, name)
 
120
                    continue
 
121
                try:
 
122
                    util.subp(['pw', 'usermod', '-n', name, '-G', member])
 
123
                    LOG.info("Added user '%s' to group '%s'", member, name)
 
124
                except Exception:
 
125
                    util.logexc(LOG, "Failed to add user '%s' to group '%s'",
 
126
                                member, name)
 
127
 
 
128
    def add_user(self, name, **kwargs):
 
129
        if util.is_user(name):
 
130
            LOG.info("User %s already exists, skipping.", name)
 
131
            return False
 
132
 
 
133
        adduser_cmd = ['pw', 'useradd', '-n', name]
 
134
        log_adduser_cmd = ['pw', 'useradd', '-n', name]
 
135
 
 
136
        adduser_opts = {
 
137
                "homedir": '-d',
 
138
                "gecos": '-c',
 
139
                "primary_group": '-g',
 
140
                "groups": '-G',
 
141
                "passwd": '-h',
 
142
                "shell": '-s',
 
143
                "inactive": '-E',
 
144
        }
 
145
        adduser_flags = {
 
146
                "no_user_group": '--no-user-group',
 
147
                "system": '--system',
 
148
                "no_log_init": '--no-log-init',
 
149
        }
 
150
 
 
151
        redact_opts = ['passwd']
 
152
 
 
153
        for key, val in kwargs.iteritems():
 
154
            if key in adduser_opts and val and isinstance(val, basestring):
 
155
                adduser_cmd.extend([adduser_opts[key], val])
 
156
 
 
157
                # Redact certain fields from the logs
 
158
                if key in redact_opts:
 
159
                    log_adduser_cmd.extend([adduser_opts[key], 'REDACTED'])
 
160
                else:
 
161
                    log_adduser_cmd.extend([adduser_opts[key], val])
 
162
 
 
163
            elif key in adduser_flags and val:
 
164
                adduser_cmd.append(adduser_flags[key])
 
165
                log_adduser_cmd.append(adduser_flags[key])
 
166
 
 
167
        if 'no_create_home' in kwargs or 'system' in kwargs:
 
168
            adduser_cmd.append('-d/nonexistent')
 
169
            log_adduser_cmd.append('-d/nonexistent')
 
170
        else:
 
171
            adduser_cmd.append('-d/usr/home/%s' % name)
 
172
            adduser_cmd.append('-m')
 
173
            log_adduser_cmd.append('-d/usr/home/%s' % name)
 
174
            log_adduser_cmd.append('-m')
 
175
 
 
176
        # Run the command
 
177
        LOG.info("Adding user %s", name)
 
178
        try:
 
179
            util.subp(adduser_cmd, logstring=log_adduser_cmd)
 
180
        except Exception as e:
 
181
            util.logexc(LOG, "Failed to create user %s", name)
 
182
            raise e
 
183
 
 
184
    # TODO:
 
185
    def set_passwd(self, user, passwd, hashed=False):
 
186
        return False
 
187
 
 
188
    def lock_passwd(self, name):
 
189
        try:
 
190
            util.subp(['pw', 'usermod', name, '-h', '-'])
 
191
        except Exception as e:
 
192
            util.logexc(LOG, "Failed to lock user %s", name)
 
193
            raise e
 
194
 
 
195
    # TODO:
 
196
    def write_sudo_rules(self, name, rules, sudo_file=None):
 
197
        LOG.debug("[write_sudo_rules] Name: %s", name)
 
198
 
 
199
    def create_user(self, name, **kwargs):
 
200
        self.add_user(name, **kwargs)
 
201
 
 
202
        # Set password if plain-text password provided and non-empty
 
203
        if 'plain_text_passwd' in kwargs and kwargs['plain_text_passwd']:
 
204
            self.set_passwd(name, kwargs['plain_text_passwd'])
 
205
 
 
206
        # Default locking down the account. 'lock_passwd' defaults to True.
 
207
        # lock account unless lock_password is False.
 
208
        if kwargs.get('lock_passwd', True):
 
209
            self.lock_passwd(name)
 
210
 
 
211
        # Configure sudo access
 
212
        if 'sudo' in kwargs:
 
213
            self.write_sudo_rules(name, kwargs['sudo'])
 
214
 
 
215
        # Import SSH keys
 
216
        if 'ssh_authorized_keys' in kwargs:
 
217
            keys = set(kwargs['ssh_authorized_keys']) or []
 
218
            ssh_util.setup_user_keys(keys, name, options=None)
 
219
 
 
220
    def _write_network(self, settings):
 
221
        return
 
222
 
 
223
    def apply_locale(self, locale, out_fn=None):
 
224
        # Adjust the locals value to the new value
 
225
        newconf = StringIO()
 
226
        for line in util.load_file(self.login_conf_fn).splitlines():
 
227
            newconf.write(re.sub(r'^default:',
 
228
                                 r'default:lang=%s:' % locale, line))
 
229
            newconf.write("\n")
 
230
 
 
231
        # Make a backup of login.conf.
 
232
        util.copy(self.login_conf_fn, self.login_conf_fn_bak)
 
233
 
 
234
        # And write the new login.conf.
 
235
        util.write_file(self.login_conf_fn, newconf.getvalue())
 
236
 
 
237
        try:
 
238
            LOG.debug("Running cap_mkdb for %s", locale)
 
239
            util.subp(['cap_mkdb', self.login_conf_fn])
 
240
        except util.ProcessExecutionError:
 
241
            # cap_mkdb failed, so restore the backup.
 
242
            util.logexc(LOG, "Failed to apply locale %s", locale)
 
243
            try:
 
244
                util.copy(self.login_conf_fn_bak, self.login_conf_fn)
 
245
            except IOError:
 
246
                util.logexc(LOG, "Failed to restore %s backup",
 
247
                            self.login_conf_fn)
 
248
 
 
249
    def install_packages(self, pkglist):
 
250
        return
 
251
 
 
252
    def package_command(self, cmd, args=None, pkgs=None):
 
253
        return
 
254
 
 
255
    def set_timezone(self, tz):
 
256
        return
 
257
 
 
258
    def update_package_sources(self):
 
259
        return