~smoser/ubuntu/quantal/cloud-init/sru

1.1.7 by Scott Moser
Import upstream version 0.5.12
1
# vi: ts=4 expandtab
2
#
3
#    Copyright (C) 2009-2010 Canonical Ltd.
4
#
5
#    Author: Scott Moser <scott.moser@canonical.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/>.
1.1.6 by Scott Moser
Import upstream version 0.5.11
18
import cloudinit.util as util
19
import os
20
import re
21
import string
22
1.1.8 by Scott Moser
Import upstream version 0.5.13
23
def is_mdname(name):
24
    # return true if this is a metadata service name
25
    if name in [ "ami", "root", "swap" ]:
26
        return True
27
    # names 'ephemeral0' or 'ephemeral1'
28
    # 'ebs[0-9]' appears when '--block-device-mapping sdf=snap-d4d90bbc'
29
    for enumname in ( "ephemeral", "ebs" ):
30
        if name.startswith(enumname) and name.find(":") == -1:
31
            return True
32
    return False
33
1.1.16 by Scott Moser
Import upstream version 0.6.3~bzr502
34
def handle(_name,cfg,cloud,log,_args):
1.1.13 by Scott Moser
Import upstream version 0.6.2
35
    # fs_spec, fs_file, fs_vfstype, fs_mntops, fs-freq, fs_passno
36
    defvals = [ None, None, "auto", "defaults,nobootwait", "0", "2" ]
37
    defvals = cfg.get("mount_default_fields", defvals)
38
1.1.6 by Scott Moser
Import upstream version 0.5.11
39
    # these are our default set of mounts
1.1.13 by Scott Moser
Import upstream version 0.6.2
40
    defmnts = [ [ "ephemeral0", "/mnt", "auto", defvals[3], "0", "2" ],
1.1.6 by Scott Moser
Import upstream version 0.5.11
41
                [ "swap", "none", "swap", "sw", "0", "0" ] ]
42
43
    cfgmnt = [ ]
44
    if cfg.has_key("mounts"):
45
        cfgmnt = cfg["mounts"]
46
1.1.9 by Scott Moser
Import upstream version 0.5.14
47
    # shortname matches 'sda', 'sda1', 'xvda', 'hda', 'sdb', xvdb, vda, vdd1
1.1.8 by Scott Moser
Import upstream version 0.5.13
48
    shortname_filter = r"^[x]{0,1}[shv]d[a-z][0-9]*$"
49
    shortname = re.compile(shortname_filter)
50
1.1.6 by Scott Moser
Import upstream version 0.5.11
51
    for i in range(len(cfgmnt)):
52
        # skip something that wasn't a list
53
        if not isinstance(cfgmnt[i],list): continue
54
55
        # workaround, allow user to specify 'ephemeral'
56
        # rather than more ec2 correct 'ephemeral0'
57
        if cfgmnt[i][0] == "ephemeral":
58
            cfgmnt[i][0] = "ephemeral0"
59
1.1.8 by Scott Moser
Import upstream version 0.5.13
60
        if is_mdname(cfgmnt[i][0]):
1.1.6 by Scott Moser
Import upstream version 0.5.11
61
            newname = cloud.device_name_to_device(cfgmnt[i][0])
1.1.8 by Scott Moser
Import upstream version 0.5.13
62
            if not newname:
63
                log.debug("ignoring nonexistant named mount %s" % cfgmnt[i][0])
1.1.6 by Scott Moser
Import upstream version 0.5.11
64
                cfgmnt[i][1] = None
1.1.8 by Scott Moser
Import upstream version 0.5.13
65
            else:
66
                if newname.startswith("/"):
67
                    cfgmnt[i][0] = newname
68
                else:
69
                    cfgmnt[i][0] = "/dev/%s" % newname
70
        else:
71
            if shortname.match(cfgmnt[i][0]):
72
                cfgmnt[i][0] = "/dev/%s" % cfgmnt[i][0]
1.1.6 by Scott Moser
Import upstream version 0.5.11
73
1.1.10 by Scott Moser
Import upstream version 0.5.15
74
        # in case the user did not quote a field (likely fs-freq, fs_passno)
1.1.15 by Scott Moser
Import upstream version 0.6.3~bzr497
75
        # but do not convert None to 'None' (LP: #898365)
1.1.10 by Scott Moser
Import upstream version 0.5.15
76
        for j in range(len(cfgmnt[i])):
1.1.15 by Scott Moser
Import upstream version 0.6.3~bzr497
77
            if isinstance(cfgmnt[i][j], int):
78
                cfgmnt[i][j]=str(cfgmnt[i][j])
1.1.10 by Scott Moser
Import upstream version 0.5.15
79
1.1.6 by Scott Moser
Import upstream version 0.5.11
80
    for i in range(len(cfgmnt)):
1.1.9 by Scott Moser
Import upstream version 0.5.14
81
        # fill in values with defaults from defvals above
1.1.6 by Scott Moser
Import upstream version 0.5.11
82
        for j in range(len(defvals)):
83
            if len(cfgmnt[i]) <= j:
84
                cfgmnt[i].append(defvals[j])
85
            elif cfgmnt[i][j] is None:
86
                cfgmnt[i][j] = defvals[j]
87
88
        # if the second entry in the list is 'None' this
89
        # clears all previous entries of that same 'fs_spec'
90
        # (fs_spec is the first field in /etc/fstab, ie, that device)
91
        if cfgmnt[i][1] is None:
92
            for j in range(i):
93
                if cfgmnt[j][0] == cfgmnt[i][0]:
94
                    cfgmnt[j][1] = None
95
96
97
    # for each of the "default" mounts, add them only if no other
98
    # entry has the same device name
99
    for defmnt in defmnts:
100
        devname = cloud.device_name_to_device(defmnt[0])
101
        if devname is None: continue
102
        if devname.startswith("/"):
103
            defmnt[0] = devname
104
        else:
105
            defmnt[0] = "/dev/%s" % devname
106
107
        cfgmnt_has = False
108
        for cfgm in cfgmnt:
109
            if cfgm[0] == defmnt[0]:
110
                cfgmnt_has = True
111
                break
112
        
113
        if cfgmnt_has: continue
114
        cfgmnt.append(defmnt)
115
116
117
    # now, each entry in the cfgmnt list has all fstab values
118
    # if the second field is None (not the string, the value) we skip it
1.1.16 by Scott Moser
Import upstream version 0.6.3~bzr502
119
    actlist = [x for x in cfgmnt if x[1] is not None]
1.1.6 by Scott Moser
Import upstream version 0.5.11
120
121
    if len(actlist) == 0: return
122
123
    comment="comment=cloudconfig"
124
    cc_lines = [ ]
125
    needswap = False
126
    dirs = [ ]
127
    for line in actlist:
128
        # write 'comment' in the fs_mntops, entry,  claiming this
129
        line[3]="%s,comment=cloudconfig" % line[3]
130
        if line[2] == "swap": needswap = True
131
        if line[1].startswith("/"): dirs.append(line[1])
132
        cc_lines.append('\t'.join(line))
133
134
    fstab_lines = [ ]
135
    fstab=open("/etc/fstab","r+")
136
    ws = re.compile("[%s]+" % string.whitespace)
137
    for line in fstab.read().splitlines():
138
        try:
139
            toks = ws.split(line)
140
            if toks[3].find(comment) != -1: continue
141
        except:
142
            pass
143
        fstab_lines.append(line)
144
145
    fstab_lines.extend(cc_lines)
146
        
147
    fstab.seek(0)
148
    fstab.write("%s\n" % '\n'.join(fstab_lines))
149
    fstab.truncate()
150
    fstab.close()
151
152
    if needswap:
153
        try: util.subp(("swapon", "-a"))
154
        except: log.warn("Failed to enable swap")
155
156
    for d in dirs:
157
        if os.path.exists(d): continue
158
        try: os.makedirs(d)
159
        except: log.warn("Failed to make '%s' config-mount\n",d)
160
161
    try: util.subp(("mount","-a"))
1.1.8 by Scott Moser
Import upstream version 0.5.13
162
    except: log.warn("'mount -a' failed")