Merge lp:~oddbloke/cloud-init/fix-gce-az into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Dan Watkins
Status: Merged
Merged at revision: 1126
Proposed branch: lp:~oddbloke/cloud-init/fix-gce-az
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 195 lines (+43/-18)
6 files modified
cloudinit/distros/__init__.py (+11/-9)
cloudinit/sources/DataSourceEc2.py (+7/-0)
cloudinit/sources/DataSourceGCE.py (+4/-0)
cloudinit/sources/__init__.py (+5/-2)
config/cloud.cfg (+1/-0)
tests/unittests/test_distros/test_generic.py (+15/-7)
To merge this branch: bzr merge lp:~oddbloke/cloud-init/fix-gce-az
Reviewer Review Type Date Requested Status
cloud-init Commiters Pending
Review via email: mp+265509@code.launchpad.net

Description of the change

This makes the full data source available to the mirror selection code, which means we can implement region logic on the data source for everything to use rather than it being mirror-selection-specific.

It also implements that region logic for EC2 and GCE.

To post a comment you must log in.
lp:~oddbloke/cloud-init/fix-gce-az updated
1124. By Dan Watkins

Make full data source available to code that handles mirror selection.

1125. By Dan Watkins

Add DataSource.region and use it in mirror selection.

Also implement DataSource.region for EC2 and GCE data sources.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cloudinit/distros/__init__.py'
2--- cloudinit/distros/__init__.py 2015-06-02 20:27:57 +0000
3+++ cloudinit/distros/__init__.py 2015-07-22 12:06:45 +0000
4@@ -117,12 +117,11 @@
5 arch = self.get_primary_arch()
6 return _get_arch_package_mirror_info(mirror_info, arch)
7
8- def get_package_mirror_info(self, arch=None,
9- availability_zone=None):
10+ def get_package_mirror_info(self, arch=None, data_source=None):
11 # This resolves the package_mirrors config option
12 # down to a single dict of {mirror_name: mirror_url}
13 arch_info = self._get_arch_package_mirror_info(arch)
14- return _get_package_mirror_info(availability_zone=availability_zone,
15+ return _get_package_mirror_info(data_source=data_source,
16 mirror_info=arch_info)
17
18 def apply_network(self, settings, bring_up=True):
19@@ -556,7 +555,7 @@
20 LOG.info("Added user '%s' to group '%s'" % (member, name))
21
22
23-def _get_package_mirror_info(mirror_info, availability_zone=None,
24+def _get_package_mirror_info(mirror_info, data_source=None,
25 mirror_filter=util.search_for_mirror):
26 # given a arch specific 'mirror_info' entry (from package_mirrors)
27 # search through the 'search' entries, and fallback appropriately
28@@ -572,11 +571,14 @@
29 ec2_az_re = ("^[a-z][a-z]-(%s)-[1-9][0-9]*[a-z]$" % directions_re)
30
31 subst = {}
32- if availability_zone:
33- subst['availability_zone'] = availability_zone
34-
35- if availability_zone and re.match(ec2_az_re, availability_zone):
36- subst['ec2_region'] = "%s" % availability_zone[0:-1]
37+ if data_source and data_source.availability_zone:
38+ subst['availability_zone'] = data_source.availability_zone
39+
40+ if re.match(ec2_az_re, data_source.availability_zone):
41+ subst['ec2_region'] = "%s" % data_source.availability_zone[0:-1]
42+
43+ if data_source and data_source.region:
44+ subst['region'] = data_source.region
45
46 results = {}
47 for (name, mirror) in mirror_info.get('failsafe', {}).items():
48
49=== modified file 'cloudinit/sources/DataSourceEc2.py'
50--- cloudinit/sources/DataSourceEc2.py 2015-01-21 22:56:53 +0000
51+++ cloudinit/sources/DataSourceEc2.py 2015-07-22 12:06:45 +0000
52@@ -197,6 +197,13 @@
53 except KeyError:
54 return None
55
56+ @property
57+ def region(self):
58+ az = self.availability_zone
59+ if az is not None:
60+ return az[:-1]
61+ return None
62+
63 # Used to match classes to dependencies
64 datasources = [
65 (DataSourceEc2, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
66
67=== modified file 'cloudinit/sources/DataSourceGCE.py'
68--- cloudinit/sources/DataSourceGCE.py 2015-07-06 14:33:33 +0000
69+++ cloudinit/sources/DataSourceGCE.py 2015-07-22 12:06:45 +0000
70@@ -152,6 +152,10 @@
71 def availability_zone(self):
72 return self.metadata['availability-zone']
73
74+ @property
75+ def region(self):
76+ return self.availability_zone.rsplit('-', 1)[0]
77+
78 # Used to match classes to dependencies
79 datasources = [
80 (DataSourceGCE, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
81
82=== modified file 'cloudinit/sources/__init__.py'
83--- cloudinit/sources/__init__.py 2015-01-21 22:56:53 +0000
84+++ cloudinit/sources/__init__.py 2015-07-22 12:06:45 +0000
85@@ -157,6 +157,10 @@
86 return self.metadata.get('availability-zone',
87 self.metadata.get('availability_zone'))
88
89+ @property
90+ def region(self):
91+ return self.metadata.get('region')
92+
93 def get_instance_id(self):
94 if not self.metadata or 'instance-id' not in self.metadata:
95 # Return a magic not really instance id string
96@@ -210,8 +214,7 @@
97 return hostname
98
99 def get_package_mirror_info(self):
100- return self.distro.get_package_mirror_info(
101- availability_zone=self.availability_zone)
102+ return self.distro.get_package_mirror_info(data_source=self)
103
104
105 def normalize_pubkey_data(pubkey_data):
106
107=== modified file 'config/cloud.cfg'
108--- config/cloud.cfg 2015-03-04 15:10:11 +0000
109+++ config/cloud.cfg 2015-07-22 12:06:45 +0000
110@@ -104,6 +104,7 @@
111 primary:
112 - http://%(ec2_region)s.ec2.archive.ubuntu.com/ubuntu/
113 - http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/
114+ - http://%(region)s.clouds.archive.ubuntu.com/ubuntu/
115 security: []
116 - arches: [armhf, armel, default]
117 failsafe:
118
119=== modified file 'tests/unittests/test_distros/test_generic.py'
120--- tests/unittests/test_distros/test_generic.py 2015-06-03 17:18:38 +0000
121+++ tests/unittests/test_distros/test_generic.py 2015-07-22 12:06:45 +0000
122@@ -7,6 +7,11 @@
123 import shutil
124 import tempfile
125
126+try:
127+ from unittest import mock
128+except ImportError:
129+ import mock
130+
131 unknown_arch_info = {
132 'arches': ['default'],
133 'failsafe': {'primary': 'http://fs-primary-default',
134@@ -144,33 +149,35 @@
135
136 def test_get_package_mirror_info_az_ec2(self):
137 arch_mirrors = gapmi(package_mirrors, arch="amd64")
138+ data_source_mock = mock.Mock(availability_zone="us-east-1a")
139
140- results = gpmi(arch_mirrors, availability_zone="us-east-1a",
141+ results = gpmi(arch_mirrors, data_source=data_source_mock,
142 mirror_filter=self.return_first)
143 self.assertEqual(results,
144 {'primary': 'http://us-east-1.ec2/',
145 'security': 'http://security-mirror1-intel'})
146
147- results = gpmi(arch_mirrors, availability_zone="us-east-1a",
148+ results = gpmi(arch_mirrors, data_source=data_source_mock,
149 mirror_filter=self.return_second)
150 self.assertEqual(results,
151 {'primary': 'http://us-east-1a.clouds/',
152 'security': 'http://security-mirror2-intel'})
153
154- results = gpmi(arch_mirrors, availability_zone="us-east-1a",
155+ results = gpmi(arch_mirrors, data_source=data_source_mock,
156 mirror_filter=self.return_none)
157 self.assertEqual(results, package_mirrors[0]['failsafe'])
158
159 def test_get_package_mirror_info_az_non_ec2(self):
160 arch_mirrors = gapmi(package_mirrors, arch="amd64")
161+ data_source_mock = mock.Mock(availability_zone="nova.cloudvendor")
162
163- results = gpmi(arch_mirrors, availability_zone="nova.cloudvendor",
164+ results = gpmi(arch_mirrors, data_source=data_source_mock,
165 mirror_filter=self.return_first)
166 self.assertEqual(results,
167 {'primary': 'http://nova.cloudvendor.clouds/',
168 'security': 'http://security-mirror1-intel'})
169
170- results = gpmi(arch_mirrors, availability_zone="nova.cloudvendor",
171+ results = gpmi(arch_mirrors, data_source=data_source_mock,
172 mirror_filter=self.return_last)
173 self.assertEqual(results,
174 {'primary': 'http://nova.cloudvendor.clouds/',
175@@ -178,17 +185,18 @@
176
177 def test_get_package_mirror_info_none(self):
178 arch_mirrors = gapmi(package_mirrors, arch="amd64")
179+ data_source_mock = mock.Mock(availability_zone=None)
180
181 # because both search entries here replacement based on
182 # availability-zone, the filter will be called with an empty list and
183 # failsafe should be taken.
184- results = gpmi(arch_mirrors, availability_zone=None,
185+ results = gpmi(arch_mirrors, data_source=data_source_mock,
186 mirror_filter=self.return_first)
187 self.assertEqual(results,
188 {'primary': 'http://fs-primary-intel',
189 'security': 'http://security-mirror1-intel'})
190
191- results = gpmi(arch_mirrors, availability_zone=None,
192+ results = gpmi(arch_mirrors, data_source=data_source_mock,
193 mirror_filter=self.return_last)
194 self.assertEqual(results,
195 {'primary': 'http://fs-primary-intel',