Merge lp:~harlowja/cloud-init/shared-wait-metadata into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Joshua Harlow
Status: Rejected
Rejected by: Scott Moser
Proposed branch: lp:~harlowja/cloud-init/shared-wait-metadata
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 231 lines (+64/-85)
3 files modified
cloudinit/sources/DataSourceEc2.py (+14/-46)
cloudinit/sources/DataSourceOpenStack.py (+13/-39)
cloudinit/util.py (+37/-0)
To merge this branch: bzr merge lp:~harlowja/cloud-init/shared-wait-metadata
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Needs Fixing
cloud-init Commiters Pending
Review via email: mp+206567@code.launchpad.net

Description of the change

Move shared waiting function to util

The ec2 and openstack datasources use a similar
piece of code for waiting for there metadata services
to become accessible (which varies depending on cloud,
service provider...) so its much nicer if we move that
duplicated/similar code to a standard utility method and
use that instead.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Scott Moser (smoser) wrote :

Hello,
Thank you for taking the time to contribute to cloud-init. Cloud-init has moved its revision control system to git. As a result, we are marking all bzr merge proposals as 'rejected'. If you would like to re-submit this proposal for review, please do so by following the current HACKING documentation at http://cloudinit.readthedocs.io/en/latest/topics/hacking.html .

I do think this is likely already solved at this point.

Unmerged revisions

951. By Joshua Harlow

Move shared waiting function to util

The ec2 and openstack datasources use a similar
piece of code for waiting for there metadata services
to become accessible (which varies depending on cloud,
service provider...) so its much nicer if we move that
duplicated/similar code to a standard utility method and
use that instead.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cloudinit/sources/DataSourceEc2.py'
2--- cloudinit/sources/DataSourceEc2.py 2014-02-01 20:03:32 +0000
3+++ cloudinit/sources/DataSourceEc2.py 2014-02-15 00:55:16 +0000
4@@ -26,7 +26,7 @@
5 from cloudinit import ec2_utils as ec2
6 from cloudinit import log as logging
7 from cloudinit import sources
8-from cloudinit import url_helper as uhelp
9+from cloudinit import url_helper
10 from cloudinit import util
11
12 LOG = logging.getLogger(__name__)
13@@ -83,65 +83,33 @@
14 return self.metadata['instance-id']
15
16 def _get_url_settings(self):
17- mcfg = self.ds_cfg
18- if not mcfg:
19- mcfg = {}
20+ # max_wait < 0 indicates do not wait
21 max_wait = 120
22 try:
23- max_wait = int(mcfg.get("max_wait", max_wait))
24+ max_wait = int(self.ds_cfg.get("max_wait", max_wait))
25 except Exception:
26 util.logexc(LOG, "Failed to get max wait. using %s", max_wait)
27
28 timeout = 50
29 try:
30- timeout = max(0, int(mcfg.get("timeout", timeout)))
31+ timeout = max(0, int(self.ds_cfg.get("timeout", timeout)))
32 except Exception:
33 util.logexc(LOG, "Failed to get timeout, using %s", timeout)
34
35 return (max_wait, timeout)
36
37 def wait_for_metadata_service(self):
38- mcfg = self.ds_cfg
39- if not mcfg:
40- mcfg = {}
41-
42 (max_wait, timeout) = self._get_url_settings()
43- if max_wait <= 0:
44- return False
45-
46- # Remove addresses from the list that wont resolve.
47- mdurls = mcfg.get("metadata_urls", DEF_MD_URLS)
48- filtered = [x for x in mdurls if util.is_resolvable_url(x)]
49-
50- if set(filtered) != set(mdurls):
51- LOG.debug("Removed the following from metadata urls: %s",
52- list((set(mdurls) - set(filtered))))
53-
54- if len(filtered):
55- mdurls = filtered
56- else:
57- LOG.warn("Empty metadata url list! using default list")
58- mdurls = DEF_MD_URLS
59-
60- urls = []
61- url2base = {}
62- for url in mdurls:
63- cur = "%s/%s/meta-data/instance-id" % (url, self.api_ver)
64- urls.append(cur)
65- url2base[cur] = url
66-
67- start_time = time.time()
68- url = uhelp.wait_for_url(urls=urls, max_wait=max_wait,
69- timeout=timeout, status_cb=LOG.warn)
70-
71- if url:
72- LOG.debug("Using metadata source: '%s'", url2base[url])
73- else:
74- LOG.critical("Giving up on md from %s after %s seconds",
75- urls, int(time.time() - start_time))
76-
77- self.metadata_address = url2base.get(url)
78- return bool(url)
79+ md_urls = self.ds_cfg.get("metadata_urls", [])
80+ md_check_path = url_helper.combine_url(self.api_ver,
81+ 'meta-data', 'instance-id')
82+ md_url = util.wait_for_metadata_service(md_urls,
83+ path=md_check_path,
84+ max_wait=max_wait,
85+ timeout=timeout,
86+ fallback_urls=DEF_MD_URLS)
87+ self.metadata_address = md_url
88+ return bool(md_url)
89
90 def device_name_to_device(self, name):
91 # Consult metadata service, that has
92
93=== modified file 'cloudinit/sources/DataSourceOpenStack.py'
94--- cloudinit/sources/DataSourceOpenStack.py 2014-02-14 19:24:06 +0000
95+++ cloudinit/sources/DataSourceOpenStack.py 2014-02-15 00:55:16 +0000
96@@ -16,8 +16,6 @@
97 # You should have received a copy of the GNU General Public License
98 # along with this program. If not, see <http://www.gnu.org/licenses/>.
99
100-import time
101-
102 from cloudinit import log as logging
103 from cloudinit import sources
104 from cloudinit import url_helper
105@@ -29,6 +27,7 @@
106
107 # Various defaults/constants...
108 DEF_MD_URL = "http://169.254.169.254"
109+DEF_MD_URLS = [DEF_MD_URL]
110 DEFAULT_IID = "iid-dsopenstack"
111 DEFAULT_METADATA = {
112 "instance-id": DEFAULT_IID,
113@@ -54,19 +53,14 @@
114 return mstr
115
116 def _get_url_settings(self):
117- # TODO(harlowja): this is shared with ec2 datasource, we should just
118- # move it to a shared location instead...
119- # Note: the defaults here are different though.
120-
121 # max_wait < 0 indicates do not wait
122 max_wait = -1
123- timeout = 10
124-
125 try:
126 max_wait = int(self.ds_cfg.get("max_wait", max_wait))
127 except Exception:
128 util.logexc(LOG, "Failed to get max wait. using %s", max_wait)
129
130+ timeout = 10
131 try:
132 timeout = max(0, int(self.ds_cfg.get("timeout", timeout)))
133 except Exception:
134@@ -74,38 +68,18 @@
135 return (max_wait, timeout)
136
137 def wait_for_metadata_service(self):
138- urls = self.ds_cfg.get("metadata_urls", [DEF_MD_URL])
139- filtered = [x for x in urls if util.is_resolvable_url(x)]
140- if set(filtered) != set(urls):
141- LOG.debug("Removed the following from metadata urls: %s",
142- list((set(urls) - set(filtered))))
143- if len(filtered):
144- urls = filtered
145- else:
146- LOG.warn("Empty metadata url list! using default list")
147- urls = [DEF_MD_URL]
148-
149- md_urls = []
150- url2base = {}
151- for url in urls:
152- md_url = url_helper.combine_url(url, 'openstack',
153- openstack.OS_LATEST,
154- 'meta_data.json')
155- md_urls.append(md_url)
156- url2base[md_url] = url
157-
158 (max_wait, timeout) = self._get_url_settings()
159- start_time = time.time()
160- avail_url = url_helper.wait_for_url(urls=md_urls, max_wait=max_wait,
161- timeout=timeout)
162- if avail_url:
163- LOG.debug("Using metadata source: '%s'", url2base[avail_url])
164- else:
165- LOG.debug("Giving up on OpenStack md from %s after %s seconds",
166- md_urls, int(time.time() - start_time))
167-
168- self.metadata_address = url2base.get(avail_url)
169- return bool(avail_url)
170+ md_urls = self.ds_cfg.get("metadata_urls", [])
171+ md_check_path = url_helper.combine_url("openstack",
172+ openstack.OS_LATEST,
173+ 'meta_data.json')
174+ md_url = util.wait_for_metadata_service(md_urls,
175+ path=md_check_path,
176+ max_wait=max_wait,
177+ timeout=timeout,
178+ fallback_urls=DEF_MD_URLS)
179+ self.metadata_address = md_url
180+ return bool(md_url)
181
182 def get_data(self):
183 try:
184
185=== modified file 'cloudinit/util.py'
186--- cloudinit/util.py 2014-02-13 11:27:22 +0000
187+++ cloudinit/util.py 2014-02-15 00:55:16 +0000
188@@ -1796,6 +1796,43 @@
189 return None
190
191
192+def wait_for_metadata_service(urls, path=None, fallback_urls=None,
193+ max_wait=120, timeout=50):
194+ resolvable_urls = [x for x in urls if is_resolvable_url(x)]
195+ if set(resolvable_urls) != set(urls):
196+ LOG.debug("Removed the following non-resolveable metadata urls: %s",
197+ list((set(urls) - set(resolvable_urls))))
198+ if not resolvable_urls:
199+ resolvable_urls = fallback_urls
200+ if not resolvable_urls:
201+ return None
202+
203+ urls = resolvable_urls
204+ md_urls = []
205+ url2base = {}
206+ for url in urls:
207+ if path:
208+ md_url = url_helper.combine_url(url, path)
209+ else:
210+ md_url = url
211+ md_urls.append(md_url)
212+ url2base[md_url] = url
213+
214+ start_time = time.time()
215+ url = url_helper.wait_for_url(urls=md_urls, max_wait=max_wait,
216+ timeout=timeout, status_cb=LOG.warn)
217+ total_time = int(time.time() - start_time)
218+ if url:
219+ md_url = url2base[url]
220+ LOG.debug("Using metadata url: '%s' (found after %s seconds)",
221+ md_url, total_time)
222+ return md_url
223+ else:
224+ LOG.critical("Giving up on metadata from %s after %s seconds",
225+ md_urls, total_time)
226+ return None
227+
228+
229 def get_mount_info(path, log=LOG):
230 # Use /proc/$$/mountinfo to find the device where path is mounted.
231 # This is done because with a btrfs filesystem using os.stat(path)