Skip to content

Commit a5c3d42

Browse files
committed
Import version 0.6.3-0ubuntu1.25
Imported using git-dsc-commit.
1 parent aa2bbfd commit a5c3d42

File tree

4 files changed

+325
-0
lines changed

4 files changed

+325
-0
lines changed

debian/changelog

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
cloud-init (0.6.3-0ubuntu1.25) precise; urgency=medium
2+
3+
* Microsoft Azure: Use stable VM instance ID over SharedConfig.xml
4+
(LP: #1506187)
5+
- d/patches/lp-1506187-azure_use_unique_vm_id.patch: use DMI data for
6+
the stable VM instance ID
7+
- d/cloud-init.preinst: migrate existing instances to stable VM instance
8+
ID on upgrade from prior versions of cloud-init.
9+
10+
-- Daniel Watkins <[email protected]> Mon, 25 Apr 2016 16:53:07 -0400
11+
112
cloud-init (0.6.3-0ubuntu1.24) precise; urgency=medium
213

314
* d/patches/lp-1506244-azure-ssh-key-values.patch: AZURE: Add support

debian/cloud-init.preinst

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,73 @@ convert_varlib_05x_06x() {
105105
return 0
106106
}
107107

108+
azure_apply_new_instance_id_1506187() {
109+
# With LP: #1506187, the Azure instance ID detection method was changed
110+
# to use the DMI data. In order to prevent existing instances from thinking
111+
# they are new instances, the instance ID needs to be updated here.
112+
113+
if grep DataSourceAzure /var/lib/cloud/instance/datasource > /dev/null 2>&1; then
114+
115+
product_id_f="/sys/devices/virtual/dmi/id/product_uuid"
116+
instance_id_link="/var/lib/cloud/instance"
117+
118+
if [ ! -e "${product_id_f}" -o ! -e "${instance_id_link}" ]; then
119+
return 0
120+
fi
121+
122+
# Get the current instance ID's (new and old)
123+
new_instance_id="$(cat ${product_id_f})"
124+
old_instance_id="$(basename "$(readlink -f "${instance_id_link}")")"
125+
126+
if [ "${new_instance_id}" = "${old_instance_id}" ]; then
127+
# this may have been applied for a prior version, i.e. upgrading
128+
# from 14.04 to 16.04
129+
return 0
130+
131+
elif [ -z "${new_instance_id}" -o -z "${old_instance_id}" ]; then
132+
cat <<EOM
133+
134+
WARNING: Failed to migrate old instance ID to new instance ID.
135+
Cloud-init may detect this instance as a new instance upon reboot.
136+
Please see: https://bugs.launchpad.net/bug/1506187
137+
138+
EOM
139+
140+
elif [ "${new_instance_id}" != "${old_instance_id}" ]; then
141+
cat <<EOM
142+
143+
AZURE: this instance uses an unstable instance ID. Cloud-init will
144+
migrate the instance ID from:
145+
${old_instance_id}
146+
to:
147+
${new_instance_id}
148+
For more information about this change, please see:
149+
https://bugs.launchpad.net/bug/1506187
150+
https://azure.microsoft.com/en-us/blog/accessing-and-using-azure-vm-unique-id
151+
152+
EOM
153+
154+
# Write the new instance id
155+
echo "${new_instance_id}" > /var/lib/cloud/data/instance-id
156+
157+
# Remove the symlink for the instance
158+
rm /var/lib/cloud/instance
159+
160+
# Rename the old instance id to the new one
161+
mv /var/lib/cloud/instances/${old_instance_id} \
162+
/var/lib/cloud/instances/${new_instance_id}
163+
164+
# Link the old id to the new one, just incase
165+
ln -s /var/lib/cloud/instances/${new_instance_id} \
166+
/var/lib/cloud/instances/${old_instance_id}
167+
168+
# Make the active instance the new id
169+
ln -s /var/lib/cloud/instances/${new_instance_id} \
170+
/var/lib/cloud/instance
171+
fi
172+
fi
173+
}
174+
108175
case "$1" in
109176
install|upgrade)
110177
# removing obsolete conffiles from the 'ec2-init' package
@@ -160,6 +227,11 @@ case "$1" in
160227
ln -sf user-scripts /var/lib/cloud/instance/sem/config-scripts-user
161228
fi
162229

230+
# 0.6.3-0ubuntu1.25 introduced new instance ID source for Azure
231+
if dpkg --compare-versions "$2" le "0.6.3-0ubuntu1.25"; then
232+
azure_apply_new_instance_id_1506187
233+
fi
234+
163235
d=/etc/cloud/
164236
if [ -f "$d/distro.cfg" ] && [ ! -f "$d/cloud.cfg.d/90_dpkg.cfg" ]; then
165237
echo "moving $d/distro.cfg -> $d/cloud.cfg.d/90_dpkg.cfg"
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
Author: Daniel Watkins <[email protected]>
2+
Origin: upstream
3+
Bug: https://launchpad.net/bugs/1506187
4+
Description: Handle new Azure instance IDs
5+
--- a/cloudinit/DataSourceAzure.py
6+
+++ b/cloudinit/DataSourceAzure.py
7+
@@ -41,7 +41,6 @@
8+
AGENT_START = ['service', 'walinuxagent', 'start']
9+
BOUNCE_COMMAND = ['sh', '-xc',
10+
"i=$interface; x=0; ifdown $i || x=$?; ifup $i || x=$?; exit $x"]
11+
-DATA_DIR_CLEAN_LIST = ['SharedConfig.xml']
12+
13+
BUILTIN_DS_CONFIG = {
14+
'agent_command': AGENT_START,
15+
@@ -139,21 +138,6 @@
16+
mycfg = self.ds_cfg
17+
ddir = mycfg['data_dir']
18+
19+
- if found != ddir:
20+
- cached_ovfenv = util.load_file(
21+
- os.path.join(ddir, 'ovf-env.xml'), quiet=True)
22+
- if cached_ovfenv != files['ovf-env.xml']:
23+
- # source was not walinux-agent's datadir, so we have to clean
24+
- # up so 'wait_for_files' doesn't return early due to stale data
25+
- cleaned = []
26+
- for f in [os.path.join(ddir, f) for f in DATA_DIR_CLEAN_LIST]:
27+
- if os.path.exists(f):
28+
- futil.del_file(f)
29+
- cleaned.append(f)
30+
- if cleaned:
31+
- LOG.info("removed stale file(s) in '%s': %s",
32+
- ddir, str(cleaned))
33+
-
34+
# walinux agent writes files world readable, but expects
35+
# the directory to be protected.
36+
write_files(ddir, files, dirmode=0700)
37+
@@ -185,9 +169,6 @@
38+
LOG.warn("agent command '%s' failed.", mycfg['agent_command'])
39+
util.logexc(LOG)
40+
41+
- shcfgxml = os.path.join(mycfg['data_dir'], "SharedConfig.xml")
42+
- wait_for = [shcfgxml]
43+
-
44+
fp_files = []
45+
key_value = None
46+
for pk in self.cfg.get('_pubkeys', []):
47+
@@ -200,24 +181,17 @@
48+
LOG.debug("ssh authentication: using fingerprint from fabric")
49+
50+
start = time.time()
51+
- missing = wait_for_files(wait_for + fp_files)
52+
+ missing = wait_for_files(fp_files)
53+
if len(missing):
54+
LOG.warn("Did not find files, but going on: %s", missing)
55+
else:
56+
- LOG.debug("waited %.3f seconds for %d files to appear",
57+
- time.time() - start, len(wait_for))
58+
-
59+
- if shcfgxml in missing:
60+
- LOG.warn("SharedConfig.xml missing, using static instance-id")
61+
- else:
62+
- try:
63+
- self.metadata['instance-id'] = iid_from_shared_config(shcfgxml)
64+
- except ValueError as e:
65+
- LOG.warn("failed to get instance id in %s: %s" % (shcfgxml, e))
66+
+ LOG.debug("waited %.3f seconds for files to appear",
67+
+ time.time() - start)
68+
69+
pubkeys = key_value or pubkeys_from_crt_files(fp_files)
70+
71+
self.metadata['public-keys'] = pubkeys
72+
+ self.metadata['instance-id'] = get_instance_id()
73+
74+
found_ephemeral = find_fabric_formatted_ephemeral_disk()
75+
if found_ephemeral:
76+
@@ -239,6 +213,14 @@
77+
def count_files(mp):
78+
return len(fnmatch.filter(os.listdir(mp), '*[!cdrom]*'))
79+
80+
+
81+
+def get_instance_id():
82+
+ """
83+
+ Read the instance ID from dmi data
84+
+ """
85+
+ return util.read_dmi_data('system-uuid')
86+
+
87+
+
88+
def find_fabric_formatted_ephemeral_part():
89+
"""
90+
Locate the first fabric formatted ephemeral device.
91+
@@ -683,25 +665,6 @@
92+
return (md, ud, cfg, {'ovf-env.xml': contents})
93+
94+
95+
-def iid_from_shared_config(path):
96+
- with open(path, "rb") as fp:
97+
- content = fp.read()
98+
- return iid_from_shared_config_content(content)
99+
-
100+
-
101+
-def iid_from_shared_config_content(content):
102+
- """
103+
- find INSTANCE_ID in:
104+
- <?xml version="1.0" encoding="utf-8"?>
105+
- <SharedConfig version="1.0.0.0" goalStateIncarnation="1">
106+
- <Deployment name="INSTANCE_ID" guid="{...}" incarnation="0">
107+
- <Service name="..." guid="{00000000-0000-0000-0000-000000000000}" />
108+
- """
109+
- dom = minidom.parseString(content)
110+
- depnode = single_node_at_path(dom, ["SharedConfig", "Deployment"])
111+
- return depnode.attributes.get('name').value
112+
-
113+
-
114+
class BrokenAzureDataSource(Exception):
115+
pass
116+
117+
--- a/cloudinit/util.py
118+
+++ b/cloudinit/util.py
119+
@@ -46,6 +46,31 @@
120+
except ImportError:
121+
HAVE_LIBSELINUX = False
122+
123+
+# Path for DMI Data
124+
+DMI_SYS_PATH = "/sys/class/dmi/id"
125+
+
126+
+# dmidecode and /sys/class/dmi/id/* use different names for the same value,
127+
+# this allows us to refer to them by one canonical name
128+
+DMIDECODE_TO_DMI_SYS_MAPPING = {
129+
+ 'baseboard-asset-tag': 'board_asset_tag',
130+
+ 'baseboard-manufacturer': 'board_vendor',
131+
+ 'baseboard-product-name': 'board_name',
132+
+ 'baseboard-serial-number': 'board_serial',
133+
+ 'baseboard-version': 'board_version',
134+
+ 'bios-release-date': 'bios_date',
135+
+ 'bios-vendor': 'bios_vendor',
136+
+ 'bios-version': 'bios_version',
137+
+ 'chassis-asset-tag': 'chassis_asset_tag',
138+
+ 'chassis-manufacturer': 'chassis_vendor',
139+
+ 'chassis-serial-number': 'chassis_serial',
140+
+ 'chassis-version': 'chassis_version',
141+
+ 'system-manufacturer': 'sys_vendor',
142+
+ 'system-product-name': 'product_name',
143+
+ 'system-serial-number': 'product_serial',
144+
+ 'system-uuid': 'product_uuid',
145+
+ 'system-version': 'product_version',
146+
+}
147+
+
148+
_DNS_REDIRECT_IP = None
149+
LOG = logging.getLogger("cloudinit")
150+
151+
@@ -982,3 +1007,90 @@
152+
153+
return os.path.isfile("/sys/class/block/%s/partition" % device)
154+
155+
+
156+
+def _read_dmi_syspath(key):
157+
+ """
158+
+ Reads dmi data with from /sys/class/dmi/id
159+
+ """
160+
+ if key not in DMIDECODE_TO_DMI_SYS_MAPPING:
161+
+ return None
162+
+ mapped_key = DMIDECODE_TO_DMI_SYS_MAPPING[key]
163+
+ dmi_key_path = "{0}/{1}".format(DMI_SYS_PATH, mapped_key)
164+
+ LOG.debug("querying dmi data %s", dmi_key_path)
165+
+ try:
166+
+ if not os.path.exists(dmi_key_path):
167+
+ LOG.debug("did not find %s", dmi_key_path)
168+
+ return None
169+
+
170+
+ key_data = load_file(dmi_key_path)
171+
+ if not key_data:
172+
+ LOG.debug("%s did not return any data", dmi_key_path)
173+
+ return None
174+
+
175+
+ LOG.debug("dmi data %s returned %s", dmi_key_path, key_data)
176+
+ return key_data.strip()
177+
+
178+
+ except Exception:
179+
+ LOG.warn("failed read of %s", dmi_key_path)
180+
+ logexc(LOG)
181+
+ return None
182+
+
183+
+
184+
+def _call_dmidecode(key, dmidecode_path):
185+
+ """
186+
+ Calls out to dmidecode to get the data out. This is mostly for supporting
187+
+ OS's without /sys/class/dmi/id support.
188+
+ """
189+
+ try:
190+
+ cmd = [dmidecode_path, "--string", key]
191+
+ (result, _err) = subp(cmd)
192+
+ LOG.debug("dmidecode returned '%s' for '%s'", result, key)
193+
+ return result
194+
+ except (IOError, OSError) as _err:
195+
+ LOG.debug('failed dmidecode cmd: %s\n%s', cmd, _err.message)
196+
+ return None
197+
+
198+
+
199+
+def which(program):
200+
+ # Return path of program for execution if found in path
201+
+ def is_exe(fpath):
202+
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
203+
+
204+
+ _fpath, _ = os.path.split(program)
205+
+ if _fpath:
206+
+ if is_exe(program):
207+
+ return program
208+
+ else:
209+
+ for path in os.environ.get("PATH", "").split(os.pathsep):
210+
+ path = path.strip('"')
211+
+ exe_file = os.path.join(path, program)
212+
+ if is_exe(exe_file):
213+
+ return exe_file
214+
+
215+
+ return None
216+
+
217+
+
218+
+def read_dmi_data(key):
219+
+ """
220+
+ Wrapper for reading DMI data.
221+
+
222+
+ This will do the following (returning the first that produces a
223+
+ result):
224+
+ 1) Use a mapping to translate `key` from dmidecode naming to
225+
+ sysfs naming and look in /sys/class/dmi/... for a value.
226+
+ 2) Use `key` as a sysfs key directly and look in /sys/class/dmi/...
227+
+ 3) Fall-back to passing `key` to `dmidecode --string`.
228+
+
229+
+ If all of the above fail to find a value, None will be returned.
230+
+ """
231+
+ syspath_value = _read_dmi_syspath(key)
232+
+ if syspath_value is not None:
233+
+ return syspath_value
234+
+
235+
+ dmidecode_path = which('dmidecode')
236+
+ if dmidecode_path:
237+
+ return _call_dmidecode(key, dmidecode_path)
238+
+
239+
+ LOG.warn("did not find either path %s or dmidecode command",
240+
+ DMI_SYS_PATH)
241+
+ return None

debian/patches/series

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ lp-1458052-redact-azure-password.patch
4040
lp-1382481-cloudstack-vr.patch
4141
lp-1177432-same-archives-as-ubuntu-server.patch
4242
lp-1506244-azure-ssh-key-values.patch
43+
lp-1506187-azure_use_unique_vm_id.patch

0 commit comments

Comments
 (0)