~ubuntu-branches/ubuntu/saucy/cloud-init/saucy-proposed

« back to all changes in this revision

Viewing changes to debian/patches/lp-1292648-azure-format-ephemeral-new.patch

  • Committer: Scott Moser
  • Date: 2014-03-21 16:26:05 UTC
  • mfrom: (317.1.2 saucy-proposed.ben)
  • Revision ID: smoser@ubuntu.com-20140321162605-3u4kmqayg5k7agab
* debian/patches/lp-1269626-azure_new_instance.patch:
  fix handling of new instances on Windows Azure (LP: #1269626).
* debian/patches/lp-1292648-azure-format-ephemeral-new.patch:
  re-format ephemeral disk if necessary (LP: #1292648).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Author: Ben Howard <ben.howard@ubuntu.com>
 
2
Bug: https://launchpad.net/bugs/1292648
 
3
Applied-Upstream: revno 968
 
4
Description: Azure: re-format ephemeral disk if necessary
 
5
  On azure, the ephemeral disk may be destroyed and replaced with a fresh
 
6
  ephemeral disk on any reboot or stop and start cycle.
 
7
  .
 
8
  This makes the datasource able to detect that by presence of an unformatted
 
9
  and specifically labeled NTFS filesystem with no files on it.
 
10
--- a/cloudinit/sources/DataSourceAzure.py
 
11
+++ b/cloudinit/sources/DataSourceAzure.py
 
12
@@ -18,12 +18,14 @@
 
13
 
 
14
 import base64
 
15
 import crypt
 
16
+import fnmatch
 
17
 import os
 
18
 import os.path
 
19
 import time
 
20
 from xml.dom import minidom
 
21
 
 
22
 from cloudinit import log as logging
 
23
+from cloudinit.settings import PER_ALWAYS
 
24
 from cloudinit import sources
 
25
 from cloudinit import util
 
26
 
 
27
@@ -53,14 +55,15 @@ BUILTIN_CLOUD_CONFIG = {
 
28
     'disk_setup': {
 
29
         'ephemeral0': {'table_type': 'mbr',
 
30
                        'layout': True,
 
31
-                       'overwrite': False}
 
32
-         },
 
33
+                       'overwrite': False},
 
34
+        },
 
35
     'fs_setup': [{'filesystem': 'ext4',
 
36
                   'device': 'ephemeral0.1',
 
37
-                  'replace_fs': 'ntfs'}]
 
38
+                  'replace_fs': 'ntfs'}],
 
39
 }
 
40
 
 
41
 DS_CFG_PATH = ['datasource', DS_NAME]
 
42
+DEF_EPHEMERAL_LABEL = 'Temporary Storage'
 
43
 
 
44
 
 
45
 class DataSourceAzureNet(sources.DataSource):
 
46
@@ -102,7 +105,7 @@ class DataSourceAzureNet(sources.DataSou
 
47
             except BrokenAzureDataSource as exc:
 
48
                 raise exc
 
49
             except util.MountFailedError:
 
50
-                LOG.warn("%s was not mountable" % cdev)
 
51
+                LOG.warn("%s was not mountable", cdev)
 
52
                 continue
 
53
 
 
54
             (md, self.userdata_raw, cfg, files) = ret
 
55
@@ -186,11 +189,20 @@ class DataSourceAzureNet(sources.DataSou
 
56
             try:
 
57
                 self.metadata['instance-id'] = iid_from_shared_config(shcfgxml)
 
58
             except ValueError as e:
 
59
-                LOG.warn("failed to get instance id in %s: %s" % (shcfgxml, e))
 
60
+                LOG.warn("failed to get instance id in %s: %s", shcfgxml, e)
 
61
 
 
62
         pubkeys = pubkeys_from_crt_files(fp_files)
 
63
-
 
64
         self.metadata['public-keys'] = pubkeys
 
65
+
 
66
+        found_ephemeral = find_ephemeral_disk()
 
67
+        if found_ephemeral:
 
68
+            self.ds_cfg['disk_aliases']['ephemeral0'] = found_ephemeral
 
69
+            LOG.debug("using detected ephemeral0 of %s", found_ephemeral)
 
70
+
 
71
+        cc_modules_override = support_new_ephemeral(self.sys_cfg)
 
72
+        if cc_modules_override:
 
73
+            self.cfg['cloud_config_modules'] = cc_modules_override
 
74
+
 
75
         return True
 
76
 
 
77
     def device_name_to_device(self, name):
 
78
@@ -200,6 +212,92 @@ class DataSourceAzureNet(sources.DataSou
 
79
         return self.cfg
 
80
 
 
81
 
 
82
+def count_files(mp):
 
83
+    return len(fnmatch.filter(os.listdir(mp), '*[!cdrom]*'))
 
84
+
 
85
+
 
86
+def find_ephemeral_part():
 
87
+    """
 
88
+    Locate the default ephmeral0.1 device. This will be the first device
 
89
+    that has a LABEL of DEF_EPHEMERAL_LABEL and is a NTFS device. If Azure
 
90
+    gets more ephemeral devices, this logic will only identify the first
 
91
+    such device.
 
92
+    """
 
93
+    c_label_devs = util.find_devs_with("LABEL=%s" % DEF_EPHEMERAL_LABEL)
 
94
+    c_fstype_devs = util.find_devs_with("TYPE=ntfs")
 
95
+    for dev in c_label_devs:
 
96
+        if dev in c_fstype_devs:
 
97
+            return dev
 
98
+    return None
 
99
+
 
100
+
 
101
+def find_ephemeral_disk():
 
102
+    """
 
103
+    Get the ephemeral disk.
 
104
+    """
 
105
+    part_dev = find_ephemeral_part()
 
106
+    if part_dev and str(part_dev[-1]).isdigit():
 
107
+        return part_dev[:-1]
 
108
+    elif part_dev:
 
109
+        return part_dev
 
110
+    return None
 
111
+
 
112
+
 
113
+def support_new_ephemeral(cfg):
 
114
+    """
 
115
+    Windows Azure makes ephemeral devices ephemeral to boot; a ephemeral device
 
116
+    may be presented as a fresh device, or not.
 
117
+
 
118
+    Since the knowledge of when a disk is supposed to be plowed under is
 
119
+    specific to Windows Azure, the logic resides here in the datasource. When a
 
120
+    new ephemeral device is detected, cloud-init overrides the default
 
121
+    frequency for both disk-setup and mounts for the current boot only.
 
122
+    """
 
123
+    device = find_ephemeral_part()
 
124
+    if not device:
 
125
+        LOG.debug("no default fabric formated ephemeral0.1 found")
 
126
+        return None
 
127
+    LOG.debug("fabric formated ephemeral0.1 device at %s", device)
 
128
+
 
129
+    file_count = 0
 
130
+    try:
 
131
+        file_count = util.mount_cb(device, count_files)
 
132
+    except:
 
133
+        return None
 
134
+    LOG.debug("fabric prepared ephmeral0.1 has %s files on it", file_count)
 
135
+
 
136
+    if file_count >= 1:
 
137
+        LOG.debug("fabric prepared ephemeral0.1 will be preserved")
 
138
+        return None
 
139
+    else:
 
140
+        # if device was already mounted, then we need to unmount it
 
141
+        # race conditions could allow for a check-then-unmount
 
142
+        # to have a false positive. so just unmount and then check.
 
143
+        try:
 
144
+            util.subp(['umount', device])
 
145
+        except util.ProcessExecutionError as e:
 
146
+            if device in util.mounts():
 
147
+                LOG.warn("Failed to unmount %s, will not reformat.", device)
 
148
+                LOG.debug("Failed umount: %s", e)
 
149
+                return None
 
150
+
 
151
+    LOG.debug("cloud-init will format ephemeral0.1 this boot.")
 
152
+    LOG.debug("setting disk_setup and mounts modules 'always' for this boot")
 
153
+
 
154
+    cc_modules = cfg.get('cloud_config_modules')
 
155
+    if not cc_modules:
 
156
+        return None
 
157
+
 
158
+    mod_list = []
 
159
+    for mod in cc_modules:
 
160
+        if mod in ("disk_setup", "mounts"):
 
161
+            mod_list.append([mod, PER_ALWAYS])
 
162
+            LOG.debug("set module '%s' to 'always' for this boot", mod)
 
163
+        else:
 
164
+            mod_list.append(mod)
 
165
+    return mod_list
 
166
+
 
167
+
 
168
 def handle_set_hostname(enabled, hostname, cfg):
 
169
     if not util.is_true(enabled):
 
170
         return