summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Moser <smoser@brickies.net>2016-08-23 16:48:35 -0400
committerScott Moser <smoser@brickies.net>2016-08-23 16:48:35 -0400
commita4fc0accc44a4e974a48c142d36adfe5547ff9cd (patch)
tree99dd6f590ffe6d44162a8462ad32b4d18965f109
parent4e486355e946c650bba4e848be1d8941c88c88e2 (diff)
downloadcloud-init-git-ubuntu/0.6.3-0ubuntu1.19.tar.gz
Import version 0.6.3-0ubuntu1.19ubuntu/0.6.3-0ubuntu1.19
Imported using git-dsc-commit.
-rw-r--r--debian/changelog13
-rw-r--r--debian/patches/lp-1411582-azure-udev-ephemeral-disks.patch406
-rw-r--r--debian/patches/lp-1470880-fix-gce-az-determination.patch17
-rw-r--r--debian/patches/lp-1470890-include-regions-in-dynamic-mirror-discovery.patch119
-rw-r--r--debian/patches/series3
5 files changed, 558 insertions, 0 deletions
diff --git a/debian/changelog b/debian/changelog
index 65158959..985a1bb0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,16 @@
+cloud-init (0.6.3-0ubuntu1.19) precise; urgency=medium
+
+ * debian/patches/lp-1411582-azure-udev-ephemeral-disks.patch:
+ - Use udev rules to discover ephemeral disk locations rather than
+ hard-coded device names (LP: #1411582).
+ * debian/patches/lp-1470880-fix-gce-az-determination.patch:
+ - Correctly parse GCE's availability zones (LP: #1470880).
+ * d/patches/lp-1470890-include-regions-in-dynamic-mirror-discovery.patch:
+ - Make %(region)s a valid substitution in mirror discovery
+ (LP: #1470890).
+
+ -- Daniel Watkins <daniel.watkins@canonical.com> Fri, 14 Aug 2015 14:38:48 +0100
+
cloud-init (0.6.3-0ubuntu1.18) precise; urgency=medium
* d/patches/lp-1456684-eu-central-1.patch:
diff --git a/debian/patches/lp-1411582-azure-udev-ephemeral-disks.patch b/debian/patches/lp-1411582-azure-udev-ephemeral-disks.patch
new file mode 100644
index 00000000..609a5832
--- /dev/null
+++ b/debian/patches/lp-1411582-azure-udev-ephemeral-disks.patch
@@ -0,0 +1,406 @@
+Description: Use udev rules to find Azure ephemeral disks
+Author: Daniel Watkins <daniel.watkins@canonical.com>
+Origin: upstream, http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/revision/1127
+Bug: https://bugs.launchpad.net/cloud-init/+bug/1411582
+--- a/cloudinit/CloudConfig/cc_disk_setup.py
++++ b/cloudinit/CloudConfig/cc_disk_setup.py
+@@ -579,6 +579,8 @@
+ table_type: Which partition table to use, defaults to MBR
+ device: the device to work on.
+ """
++ # ensure that we get a real device rather than a symbolic link
++ device = os.path.realpath(device)
+
+ LOG.debug("Checking values for %s definition" % device)
+ overwrite = definition.get('overwrite', False)
+@@ -676,6 +678,9 @@
+ fs_replace = fs_cfg.get('replace_fs', False)
+ overwrite = fs_cfg.get('overwrite', False)
+
++ # ensure that we get a real device rather than a symbolic link
++ device = os.path.realpath(device)
++
+ # This allows you to define the default ephemeral or swap
+ LOG.debug("Checking %s against default devices", device)
+
+--- a/cloudinit/CloudConfig/cc_mounts.py
++++ b/cloudinit/CloudConfig/cc_mounts.py
+@@ -29,15 +29,15 @@
+ from cloudinit import util
+
+ # Shortname matches 'sda', 'sda1', 'xvda', 'hda', 'sdb', xvdb, vda, vdd1, sr0
+-SHORTNAME_FILTER = r"^([x]{0,1}[shv]d[a-z][0-9]*|sr[0-9]+)$"
+-SHORTNAME = re.compile(SHORTNAME_FILTER)
++DEVICE_NAME_FILTER = r"^([x]{0,1}[shv]d[a-z][0-9]*|sr[0-9]+)$"
++DEVICE_NAME_RE = re.compile(DEVICE_NAME_FILTER)
+ WS = re.compile("[%s]+" % (whitespace))
+ FSTAB_PATH = "/etc/fstab"
+
+ LOG = logging.getLogger(__name__)
+
+
+-def is_mdname(name):
++def is_meta_device_name(name):
+ # return true if this is a metadata service name
+ if name in ["ami", "root", "swap"]:
+ return True
+@@ -49,6 +49,25 @@
+ return False
+
+
++def _get_nth_partition_for_device(device_path, partition_number):
++ potential_suffixes = [str(partition_number), 'p%s' % (partition_number,),
++ '-part%s' % (partition_number,)]
++ for suffix in potential_suffixes:
++ potential_partition_device = '%s%s' % (device_path, suffix)
++ if os.path.exists(potential_partition_device):
++ return potential_partition_device
++ return None
++
++
++def _is_block_device(device_path, partition_path=None):
++ device_name = os.path.realpath(device_path).split('/')[-1]
++ sys_path = os.path.join('/sys/block/', device_name)
++ if partition_path is not None:
++ sys_path = os.path.join(
++ sys_path, os.path.realpath(partition_path).split('/')[-1])
++ return os.path.exists(sys_path)
++
++
+ def sanitize_devname(startname, transformer, log):
+ log.debug("Attempting to determine the real name of %s", startname)
+
+@@ -59,21 +78,34 @@
+ devname = "ephemeral0"
+ log.debug("Adjusted mount option from ephemeral to ephemeral0")
+
+- (blockdev, part) = futil.expand_dotted_devname(devname)
++ device_path, partition_number = futil.expand_dotted_devname(devname)
+
+- if is_mdname(blockdev):
+- orig = blockdev
+- blockdev = transformer(blockdev)
+- if not blockdev:
++ if is_meta_device_name(device_path):
++ orig = device_path
++ device_path = transformer(device_path)
++ if not device_path:
+ return None
+- if not blockdev.startswith("/"):
+- blockdev = "/dev/%s" % blockdev
+- log.debug("Mapped metadata name %s to %s", orig, blockdev)
++ if not device_path.startswith("/"):
++ device_path = "/dev/%s" % (device_path,)
++ log.debug("Mapped metadata name %s to %s", orig, device_path)
+ else:
+- if SHORTNAME.match(startname):
+- blockdev = "/dev/%s" % blockdev
++ if DEVICE_NAME_RE.match(startname):
++ device_path = "/dev/%s" % (device_path,)
+
+- return devnode_for_dev_part(blockdev, part)
++ partition_path = None
++ if partition_number is None:
++ partition_path = _get_nth_partition_for_device(device_path, 1)
++ else:
++ partition_path = _get_nth_partition_for_device(device_path,
++ partition_number)
++ if partition_path is None:
++ return None
++
++ if _is_block_device(device_path, partition_path):
++ if partition_path is not None:
++ return partition_path
++ return device_path
++ return None
+
+
+ def handle(_name, cfg, cloud, log, _args):
+@@ -211,50 +243,3 @@
+ futil.subp(("mount", "-a"))
+ except:
+ log.warn("Activating mounts via 'mount -a' failed")
+-
+-
+-def devnode_for_dev_part(device, partition):
+- """
+- Find the name of the partition. While this might seem rather
+- straight forward, its not since some devices are '<device><partition>'
+- while others are '<device>p<partition>'. For example, /dev/xvda3 on EC2
+- will present as /dev/xvda3p1 for the first partition since /dev/xvda3 is
+- a block device.
+- """
+- if not os.path.exists(device):
+- return None
+-
+- short_name = os.path.basename(device)
+- sys_path = "/sys/block/%s" % short_name
+-
+- if not os.path.exists(sys_path):
+- LOG.debug("did not find entry for %s in /sys/block", short_name)
+- return None
+-
+- sys_long_path = sys_path + "/" + short_name
+-
+- if partition is not None:
+- partition = str(partition)
+-
+- if partition is None:
+- valid_mappings = [sys_long_path + "1",
+- sys_long_path + "p1"]
+- elif partition != "0":
+- valid_mappings = [sys_long_path + "%s" % partition,
+- sys_long_path + "p%s" % partition]
+- else:
+- valid_mappings = []
+-
+- for cdisk in valid_mappings:
+- if not os.path.exists(cdisk):
+- continue
+-
+- dev_path = "/dev/%s" % os.path.basename(cdisk)
+- if os.path.exists(dev_path):
+- return dev_path
+-
+- if partition is None or partition == "0":
+- return device
+-
+- LOG.debug("Did not fine partition %s for device %s", partition, device)
+- return None
+--- a/cloudinit/DataSourceAzure.py
++++ b/cloudinit/DataSourceAzure.py
+@@ -207,7 +207,7 @@
+
+ self.metadata['public-keys'] = pubkeys
+
+- found_ephemeral = find_ephemeral_disk()
++ found_ephemeral = find_fabric_formatted_ephemeral_disk()
+ if found_ephemeral:
+ self.ds_cfg['disk_aliases']['ephemeral0'] = found_ephemeral
+ LOG.debug("using detected ephemeral0 of %s", found_ephemeral)
+@@ -227,30 +227,33 @@
+ def count_files(mp):
+ return len(fnmatch.filter(os.listdir(mp), '*[!cdrom]*'))
+
+-def find_ephemeral_part():
++def find_fabric_formatted_ephemeral_part():
+ """
+- Locate the default ephmeral0.1 device. This will be the first device
+- that has a LABEL of DEF_EPHEMERAL_LABEL and is a NTFS device. If Azure
+- gets more ephemeral devices, this logic will only identify the first
+- such device.
+- """
+- c_label_devs = util.find_devs_with("LABEL=%s" % DEF_EPHEMERAL_LABEL)
+- c_fstype_devs = util.find_devs_with("TYPE=ntfs")
+- for dev in c_label_devs:
+- if dev in c_fstype_devs:
+- return dev
++ Locate the first fabric formatted ephemeral device.
++ """
++ potential_locations = ['/dev/disk/cloud/azure_resource-part1',
++ '/dev/disk/azure/resource-part1']
++ device_location = None
++ for potential_location in potential_locations:
++ if os.path.exists(potential_location):
++ device_location = potential_location
++ break
++ if device_location is None:
++ return None
++ ntfs_devices = util.find_devs_with("TYPE=ntfs")
++ real_device = os.path.realpath(device_location)
++ if real_device in ntfs_devices:
++ return device_location
+ return None
+
+
+-def find_ephemeral_disk():
++def find_fabric_formatted_ephemeral_disk():
+ """
+ Get the ephemeral disk.
+ """
+- part_dev = find_ephemeral_part()
+- if part_dev and str(part_dev[-1]).isdigit():
+- return part_dev[:-1]
+- elif part_dev:
+- return part_dev
++ part_dev = find_fabric_formatted_ephemeral_part()
++ if part_dev:
++ return part_dev.split('-')[0]
+ return None
+
+ def support_new_ephemeral(cfg):
+@@ -263,7 +266,7 @@
+ new ephemeral device is detected, cloud-init overrides the default
+ frequency for both disk-setup and mounts for the current boot only.
+ """
+- device = find_ephemeral_part()
++ device = find_fabric_formatted_ephemeral_part()
+ if not device:
+ LOG.debug("no default fabric formated ephemeral0.1 found")
+ return None
+--- /dev/null
++++ b/tests/unittests/test_handler/test_handler_mounts.py
+@@ -0,0 +1,133 @@
++import os.path
++import shutil
++import tempfile
++
++from cloudinit.config import cc_mounts
++
++from .. import helpers as test_helpers
++
++try:
++ from unittest import mock
++except ImportError:
++ import mock
++
++
++class TestSanitizeDevname(test_helpers.FilesystemMockingTestCase):
++
++ def setUp(self):
++ super(TestSanitizeDevname, self).setUp()
++ self.new_root = tempfile.mkdtemp()
++ self.addCleanup(shutil.rmtree, self.new_root)
++ self.patchOS(self.new_root)
++
++ def _touch(self, path):
++ path = os.path.join(self.new_root, path.lstrip('/'))
++ basedir = os.path.dirname(path)
++ if not os.path.exists(basedir):
++ os.makedirs(basedir)
++ open(path, 'a').close()
++
++ def _makedirs(self, directory):
++ directory = os.path.join(self.new_root, directory.lstrip('/'))
++ if not os.path.exists(directory):
++ os.makedirs(directory)
++
++ def mock_existence_of_disk(self, disk_path):
++ self._touch(disk_path)
++ self._makedirs(os.path.join('/sys/block', disk_path.split('/')[-1]))
++
++ def mock_existence_of_partition(self, disk_path, partition_number):
++ self.mock_existence_of_disk(disk_path)
++ self._touch(disk_path + str(partition_number))
++ disk_name = disk_path.split('/')[-1]
++ self._makedirs(os.path.join('/sys/block',
++ disk_name,
++ disk_name + str(partition_number)))
++
++ def test_existent_full_disk_path_is_returned(self):
++ disk_path = '/dev/sda'
++ self.mock_existence_of_disk(disk_path)
++ self.assertEqual(disk_path,
++ cc_mounts.sanitize_devname(disk_path,
++ lambda x: None,
++ mock.Mock()))
++
++ def test_existent_disk_name_returns_full_path(self):
++ disk_name = 'sda'
++ disk_path = '/dev/' + disk_name
++ self.mock_existence_of_disk(disk_path)
++ self.assertEqual(disk_path,
++ cc_mounts.sanitize_devname(disk_name,
++ lambda x: None,
++ mock.Mock()))
++
++ def test_existent_meta_disk_is_returned(self):
++ actual_disk_path = '/dev/sda'
++ self.mock_existence_of_disk(actual_disk_path)
++ self.assertEqual(
++ actual_disk_path,
++ cc_mounts.sanitize_devname('ephemeral0',
++ lambda x: actual_disk_path,
++ mock.Mock()))
++
++ def test_existent_meta_partition_is_returned(self):
++ disk_name, partition_part = '/dev/sda', '1'
++ actual_partition_path = disk_name + partition_part
++ self.mock_existence_of_partition(disk_name, partition_part)
++ self.assertEqual(
++ actual_partition_path,
++ cc_mounts.sanitize_devname('ephemeral0.1',
++ lambda x: disk_name,
++ mock.Mock()))
++
++ def test_existent_meta_partition_with_p_is_returned(self):
++ disk_name, partition_part = '/dev/sda', 'p1'
++ actual_partition_path = disk_name + partition_part
++ self.mock_existence_of_partition(disk_name, partition_part)
++ self.assertEqual(
++ actual_partition_path,
++ cc_mounts.sanitize_devname('ephemeral0.1',
++ lambda x: disk_name,
++ mock.Mock()))
++
++ def test_first_partition_returned_if_existent_disk_is_partitioned(self):
++ disk_name, partition_part = '/dev/sda', '1'
++ actual_partition_path = disk_name + partition_part
++ self.mock_existence_of_partition(disk_name, partition_part)
++ self.assertEqual(
++ actual_partition_path,
++ cc_mounts.sanitize_devname('ephemeral0',
++ lambda x: disk_name,
++ mock.Mock()))
++
++ def test_nth_partition_returned_if_requested(self):
++ disk_name, partition_part = '/dev/sda', '3'
++ actual_partition_path = disk_name + partition_part
++ self.mock_existence_of_partition(disk_name, partition_part)
++ self.assertEqual(
++ actual_partition_path,
++ cc_mounts.sanitize_devname('ephemeral0.3',
++ lambda x: disk_name,
++ mock.Mock()))
++
++ def test_transformer_returning_none_returns_none(self):
++ self.assertIsNone(
++ cc_mounts.sanitize_devname(
++ 'ephemeral0', lambda x: None, mock.Mock()))
++
++ def test_missing_device_returns_none(self):
++ self.assertIsNone(
++ cc_mounts.sanitize_devname('/dev/sda', None, mock.Mock()))
++
++ def test_missing_sys_returns_none(self):
++ disk_path = '/dev/sda'
++ self._makedirs(disk_path)
++ self.assertIsNone(
++ cc_mounts.sanitize_devname(disk_path, None, mock.Mock()))
++
++ def test_existent_disk_but_missing_partition_returns_none(self):
++ disk_path = '/dev/sda'
++ self.mock_existence_of_disk(disk_path)
++ self.assertIsNone(
++ cc_mounts.sanitize_devname(
++ 'ephemeral0.1', lambda x: disk_path, mock.Mock()))
+--- /dev/null
++++ b/udev/66-azure-ephemeral.rules
+@@ -0,0 +1,18 @@
++# Azure specific rules
++ACTION!="add|change", GOTO="cloud_init_end"
++SUBSYSTEM!="block", GOTO="cloud_init_end"
++ATTRS{ID_VENDOR}!="Msft", GOTO="cloud_init_end"
++ATTRS{ID_MODEL}!="Virtual_Disk", GOTO="cloud_init_end"
++
++# Root has a GUID of 0000 as the second value
++# The resource/resource has GUID of 0001 as the second value
++ATTRS{device_id}=="?00000000-0000-*", ENV{fabric_name}="azure_root", GOTO="ci_azure_names"
++ATTRS{device_id}=="?00000000-0001-*", ENV{fabric_name}="azure_resource", GOTO="ci_azure_names"
++GOTO="cloud_init_end"
++
++# Create the symlinks
++LABEL="ci_azure_names"
++ENV{DEVTYPE}=="disk", SYMLINK+="disk/cloud/$env{fabric_name}"
++ENV{DEVTYPE}=="partition", SYMLINK+="disk/cloud/$env{fabric_name}-part%n"
++
++LABEL="cloud_init_end"
+--- a/setup.py
++++ b/setup.py
+@@ -48,5 +48,6 @@
+ ('/usr/share/doc/cloud-init/examples', filter(is_f,glob('doc/examples/*'))),
+ ('/usr/share/doc/cloud-init/examples/seed', filter(is_f,glob('doc/examples/seed/*'))),
+ ('/etc/profile.d', ['tools/Z99-cloud-locale-test.sh']),
++ ('/lib/udev/rules.d', ['udev/66-azure-ephemeral.rules']),
+ ],
+ )
diff --git a/debian/patches/lp-1470880-fix-gce-az-determination.patch b/debian/patches/lp-1470880-fix-gce-az-determination.patch
new file mode 100644
index 00000000..867f2b28
--- /dev/null
+++ b/debian/patches/lp-1470880-fix-gce-az-determination.patch
@@ -0,0 +1,17 @@
+Description: Correctly parse GCE's availability zones
+Author: Daniel Watkins <daniel.watkins@canonical.com>
+Origin: upstream, http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/revision/1121
+Bug: https://bugs.launchpad.net/cloud-init/+bug/1470880
+--- a/cloudinit/DataSourceGCE.py
++++ b/cloudinit/DataSourceGCE.py
+@@ -124,6 +124,10 @@
+ lines = self.metadata['public-keys'].splitlines()
+ self.metadata['public-keys'] = [self._trim_key(k) for k in lines]
+
++ if self.metadata['availability-zone']:
++ self.metadata['availability-zone'] = self.metadata[
++ 'availability-zone'].split('/')[-1]
++
+ encoding = self.metadata.get('user-data-encoding')
+ if encoding:
+ if encoding == 'base64':
diff --git a/debian/patches/lp-1470890-include-regions-in-dynamic-mirror-discovery.patch b/debian/patches/lp-1470890-include-regions-in-dynamic-mirror-discovery.patch
new file mode 100644
index 00000000..d7e659bb
--- /dev/null
+++ b/debian/patches/lp-1470890-include-regions-in-dynamic-mirror-discovery.patch
@@ -0,0 +1,119 @@
+Description: Enable %(region)s as a dynamic mirror substitution
+Author: Daniel Watkins <daniel.watkins@canonical.com>
+Origin: upstream, http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/revision/1126
+Bug: https://bugs.launchpad.net/cloud-init/+bug/1470890
+--- a/cloudinit/CloudConfig/cc_apt_update_upgrade.py
++++ b/cloudinit/CloudConfig/cc_apt_update_upgrade.py
+@@ -271,9 +271,8 @@
+
+ try:
+ pmirrors = cfg['system_info']['package_mirrors']
+- az = cloud.datasource.get_availability_zone()
+ mirror_info = get_package_mirror_info(package_mirrors=pmirrors,
+- availability_zone=az)
++ data_source=cloud.datasource)
+ except Exception as e:
+ util.logexc(log)
+ log.warn("Failed to get mirror info, falling back to default" %
+@@ -292,13 +291,13 @@
+ ## put together from trunk's cloudinit/distros/__init__.py and
+ ## cloudinit/sources/__init__.py
+ def get_package_mirror_info(package_mirrors,
+- availability_zone=None, arch=None):
++ data_source=None, arch=None):
+ if arch == None:
+ arch = get_primary_arch()
+ arch_info = _get_arch_package_mirror_info(package_mirrors, arch)
+
+ info = _get_package_mirror_info(mirror_info=arch_info,
+- availability_zone=availability_zone)
++ data_source=data_source)
+ return info
+
+ ## taken from trunk's cloudinit/distros/debian.py (Distro)
+@@ -307,7 +306,7 @@
+ return str(arch).strip()
+
+ ## taken from trunk's cloudinit/distros/__init__.py ##
+-def _get_package_mirror_info(mirror_info, availability_zone=None,
++def _get_package_mirror_info(mirror_info, data_source=None,
+ mirror_filter=util.search_for_mirror):
+ # given a arch specific 'mirror_info' entry (from package_mirrors)
+ # search through the 'search' entries, and fallback appropriately
+@@ -321,11 +320,15 @@
+ ec2_az_re = ("^[a-z][a-z]-(%s)-[1-9][0-9]*[a-z]$" % directions_re)
+
+ subst = {}
+- if availability_zone:
+- subst['availability_zone'] = availability_zone
++ if data_source and data_source.get_availability_zone():
++ subst['availability_zone'] = data_source.get_availability_zone()
+
+- if availability_zone and re.match(ec2_az_re, availability_zone):
+- subst['ec2_region'] = "%s" % availability_zone[0:-1]
++ if re.match(ec2_az_re, data_source.get_availability_zone()):
++ subst['ec2_region'] = "%s" % (
++ data_source.get_availability_zone()[0:-1],)
++
++ if data_source and data_source.region:
++ subst['region'] = data_source.region
+
+ results = {}
+ for (name, mirror) in mirror_info.get('failsafe', {}).iteritems():
+--- a/cloudinit/DataSourceEc2.py
++++ b/cloudinit/DataSourceEc2.py
+@@ -186,6 +186,13 @@
+ return True
+ return False
+
++ @property
++ def region(self):
++ az = self.get_availability_zone()
++ if az is not None:
++ return az[:-1]
++ return None
++
+
+ datasources = [
+ (DataSourceEc2, (DataSource.DEP_FILESYSTEM, DataSource.DEP_NETWORK)),
+--- a/cloudinit/DataSourceGCE.py
++++ b/cloudinit/DataSourceGCE.py
+@@ -156,10 +156,13 @@
+ def userdata_raw(self):
+ return self.metadata['user-data'] or ''
+
+- @property
+- def availability_zone(self):
++ def get_availability_zone(self):
+ return self.metadata['availability-zone']
+
++ @property
++ def region(self):
++ return self.get_availability_zone().rsplit('-', 1)[0]
++
+ # Used to match classes to dependencies
+ datasources = [
+ (DataSourceGCE, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
+--- a/cloudinit/DataSource.py
++++ b/cloudinit/DataSource.py
+@@ -102,6 +102,10 @@
+ def get_local_mirror(self):
+ return None
+
++ @property
++ def region(self):
++ return self.metadata.get('region')
++
+ def get_instance_id(self):
+ if 'instance-id' not in self.metadata:
+ return "iid-datasource"
+--- a/config/cloud.cfg
++++ b/config/cloud.cfg
+@@ -52,6 +52,7 @@
+ primary:
+ - http://%(ec2_region)s.ec2.archive.ubuntu.com/ubuntu/
+ - http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/
++ - http://%(region)s.clouds.archive.ubuntu.com/ubuntu/
+ security: []
+ - arches: [armhf, armel, default]
+ failsafe:
diff --git a/debian/patches/series b/debian/patches/series
index d7ff135c..630c04ed 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -30,3 +30,6 @@ lp-1404311-gce-data_encoding.patch
lp-1422388-cloudstack-passwords.patch
lp-1456684-eu-central-1.patch
lp-1464253-handle-new-cloudstack-passwords.patch
+lp-1411582-azure-udev-ephemeral-disks.patch
+lp-1470880-fix-gce-az-determination.patch
+lp-1470890-include-regions-in-dynamic-mirror-discovery.patch