Merge lp:~oddbloke/ubuntu/precise/cloud-init/lp1374600 into lp:ubuntu/precise-proposed/cloud-init

Proposed by Dan Watkins
Status: Merged
Merged at revision: 212
Proposed branch: lp:~oddbloke/ubuntu/precise/cloud-init/lp1374600
Merge into: lp:ubuntu/precise-proposed/cloud-init
Diff against target: 388 lines (+338/-3)
6 files modified
.pc/applied-patches (+1/-0)
cloudinit/DataSourceGCE.py (+156/-0)
debian/changelog (+7/-0)
debian/cloud-init.templates (+3/-3)
debian/patches/lp-1378441-backport-gce-data-source.patch (+170/-0)
debian/patches/series (+1/-0)
To merge this branch: bzr merge lp:~oddbloke/ubuntu/precise/cloud-init/lp1374600
Reviewer Review Type Date Requested Status
Scott Moser Needs Fixing
Review via email: mp+237813@code.launchpad.net

Description of the change

This backports the GCE data source from trusty; the intent is to SRU it in the near future.

To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

2 nit picks, other than that, assuming this is tested it looks fine.
The headers you're putting on the patch are described at http://dep.debian.net/deps/dep3/
so:
a.) add 'Origin: upstream'
    you can probably remove 'Author:' here (i realize we're probably not consistent in other patches on this).

b.) the bug number you referenced is a private bug (1374600), while there is a public bug (bug 1378441). Seems to make sense to reference the public bug.

c.) reference the ubuntu bug in the changelog message.

so make those changes, and i'll upload for you.

review: Needs Fixing
212. By Dan Watkins

debian/patches/lp-1378441-backport-gce-data-source.patch: backported
Google Compute Engine data source. (LP: #1378441)

Revision history for this message
Dan Watkins (oddbloke) wrote :

I've just pushed up those changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2014-09-17 19:44:07 +0000
+++ .pc/applied-patches 2014-10-10 08:21:23 +0000
@@ -24,3 +24,4 @@
24lp-1302229-fix_futils_azure.patch24lp-1302229-fix_futils_azure.patch
25lp-1363260-add-cloudsigma_ds.patch25lp-1363260-add-cloudsigma_ds.patch
26lp-1336855-grub_xvda.patch26lp-1336855-grub_xvda.patch
27lp-1378441-backport-gce-data-source.patch
2728
=== added directory '.pc/lp-1378441-backport-gce-data-source.patch'
=== added directory '.pc/lp-1378441-backport-gce-data-source.patch/cloudinit'
=== added file '.pc/lp-1378441-backport-gce-data-source.patch/cloudinit/DataSourceGCE.py'
=== added file '.pc/lp-1378441-backport-gce-data-source.patch/cloudinit/url_helper.py'
=== added file 'cloudinit/DataSourceGCE.py'
--- cloudinit/DataSourceGCE.py 1970-01-01 00:00:00 +0000
+++ cloudinit/DataSourceGCE.py 2014-10-10 08:21:23 +0000
@@ -0,0 +1,156 @@
1# vi: ts=4 expandtab
2#
3# Author: Vaidas Jablonskis <jablonskis@gmail.com>
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3, as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import logging
18import urllib2
19
20from cloudinit import util
21from cloudinit import DataSource as sources
22
23LOG = logging.getLogger(__name__)
24
25BUILTIN_DS_CONFIG = {
26 'metadata_url': 'http://metadata.google.internal./computeMetadata/v1/'
27}
28REQUIRED_FIELDS = ('instance-id', 'availability-zone', 'local-hostname')
29
30
31class _FakeResponse(object):
32
33 def __init__(self, code, contents):
34 self.code = code
35 self.contents = contents
36
37
38class url_helper(object):
39 # This is a shim designed to look like url_helper.py from future versions
40 # of cloud-init.
41
42 @staticmethod
43 def readurl(url, headers):
44 request = urllib2.Request(url, headers=headers)
45 response = urllib2.urlopen(request)
46 return _FakeResponse(code=response.getcode(), contents=response.read())
47
48 UrlError = urllib2.URLError
49
50
51class DataSourceGCE(sources.DataSource):
52 def __init__(self, sys_cfg):
53 sources.DataSource.__init__(self, sys_cfg)
54 self.metadata = dict()
55 self.ds_cfg = util.mergedict(
56 util.get_cfg_by_path(sys_cfg, ["datasource", "GCE"], {}),
57 BUILTIN_DS_CONFIG)
58 self.metadata_address = self.ds_cfg['metadata_url']
59
60 # GCE takes sshKeys attribute in the format of '<user>:<public_key>'
61 # so we have to trim each key to remove the username part
62 def _trim_key(self, public_key):
63 try:
64 index = public_key.index(':')
65 if index > 0:
66 return public_key[(index + 1):]
67 except:
68 return public_key
69
70 def get_data(self):
71 # GCE metadata server requires a custom header since v1
72 headers = {'X-Google-Metadata-Request': 'True'}
73
74 # url_map: (our-key, path, required)
75 url_map = [
76 ('instance-id', 'instance/id', True),
77 ('availability-zone', 'instance/zone', True),
78 ('local-hostname', 'instance/hostname', True),
79 ('public-keys', 'project/attributes/sshKeys', False),
80 ('user-data', 'instance/attributes/user-data', False),
81 ]
82
83 # if we cannot resolve the metadata server, then no point in trying
84 if not util.is_resolvable_url(self.metadata_address):
85 LOG.debug("%s is not resolvable", self.metadata_address)
86 return False
87
88 # iterate over url_map keys to get metadata items
89 found = False
90 for (mkey, path, required) in url_map:
91 try:
92 resp = url_helper.readurl(url=self.metadata_address + path,
93 headers=headers)
94 if resp.code == 200:
95 found = True
96 self.metadata[mkey] = resp.contents
97 else:
98 if required:
99 msg = "required url %s returned code %s. not GCE"
100 if not found:
101 LOG.debug(msg, path, resp.code)
102 else:
103 LOG.warn(msg, path, resp.code)
104 return False
105 else:
106 self.metadata[mkey] = None
107 except url_helper.UrlError as e:
108 if required:
109 msg = "required url %s raised exception %s. not GCE"
110 if not found:
111 LOG.debug(msg, path, e)
112 else:
113 LOG.warn(msg, path, e)
114 return False
115 msg = "Failed to get %s metadata item: %s."
116 LOG.debug(msg, path, e)
117
118 self.metadata[mkey] = None
119
120 if self.metadata['public-keys']:
121 lines = self.metadata['public-keys'].splitlines()
122 self.metadata['public-keys'] = [self._trim_key(k) for k in lines]
123
124 return found
125
126 @property
127 def launch_index(self):
128 # GCE does not provide lauch_index property
129 return None
130
131 def get_instance_id(self):
132 return self.metadata['instance-id']
133
134 def get_public_ssh_keys(self):
135 return self.metadata['public-keys']
136
137 def get_hostname(self, fqdn=False, _resolve_ip=False):
138 return self.metadata['local-hostname']
139
140 @property
141 def userdata_raw(self):
142 return self.metadata['user-data'] or ''
143
144 @property
145 def availability_zone(self):
146 return self.metadata['availability-zone']
147
148# Used to match classes to dependencies
149datasources = [
150 (DataSourceGCE, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
151]
152
153
154# Return a list of data sources that match this set of dependencies
155def get_datasource_list(depends):
156 return sources.list_from_depends(depends, datasources)
0157
=== modified file 'debian/changelog'
--- debian/changelog 2014-09-18 22:26:16 +0000
+++ debian/changelog 2014-10-10 08:21:23 +0000
@@ -1,3 +1,10 @@
1cloud-init (0.6.3-0ubuntu1.15) precise; urgency=medium
2
3 * debian/patches/lp-1378441-backport-gce-data-source.patch: backported
4 Google Compute Engine data source. (LP: #1378441)
5
6 -- Daniel Watkins <daniel.watkins@canonical.com> Thu, 10 Oct 2014 09:24:57 +0100
7
1cloud-init (0.6.3-0ubuntu1.14) precise-proposed; urgency=medium8cloud-init (0.6.3-0ubuntu1.14) precise-proposed; urgency=medium
29
3 * debian/patches/lp-1363260-add-cloudsigma_ds.patch: backport from10 * debian/patches/lp-1363260-add-cloudsigma_ds.patch: backport from
411
=== modified file 'debian/cloud-init.templates'
--- debian/cloud-init.templates 2014-09-17 19:44:07 +0000
+++ debian/cloud-init.templates 2014-10-10 08:21:23 +0000
@@ -1,8 +1,8 @@
1Template: cloud-init/datasources1Template: cloud-init/datasources
2Type: multiselect2Type: multiselect
3Default: NoCloud, ConfigDrive, Azure, OVF, MAAS, CloudSigma3Default: NoCloud, ConfigDrive, Azure, OVF, MAAS, CloudSigma, GCE
4Choices-C: NoCloud, ConfigDrive, Azure, OVF, MAAS, Ec2, SmartOS, CloudSigma4Choices-C: NoCloud, ConfigDrive, Azure, OVF, MAAS, Ec2, SmartOS, CloudSigma, GCE
5Choices: NoCloud: Reads info from /var/lib/cloud/seed only, ConfigDrive: Reads data from Openstack Config Drive, Azure: read from MS Azure cdrom. Requires walinux-agent, OVF: Reads data from OVF Transports, MAAS: Reads data from Ubuntu MAAS, Ec2: reads data from EC2 Metadata service, SmartOS: reads data from serial console, CloudSigma: reads data from serial console5Choices: NoCloud: Reads info from /var/lib/cloud/seed only, ConfigDrive: Reads data from Openstack Config Drive, Azure: read from MS Azure cdrom. Requires walinux-agent, OVF: Reads data from OVF Transports, MAAS: Reads data from Ubuntu MAAS, Ec2: reads data from EC2 Metadata service, SmartOS: reads data from serial console, CloudSigma: reads data from serial console, GCE: reads data from Google Compute Engine metadata service
6Description: Which data sources should be searched?6Description: Which data sources should be searched?
7 Cloud-init supports searching different "Data Sources" for information7 Cloud-init supports searching different "Data Sources" for information
8 that it uses to configure a cloud instance.8 that it uses to configure a cloud instance.
99
=== added file 'debian/patches/lp-1378441-backport-gce-data-source.patch'
--- debian/patches/lp-1378441-backport-gce-data-source.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/lp-1378441-backport-gce-data-source.patch 2014-10-10 08:21:23 +0000
@@ -0,0 +1,170 @@
1Origin: upstream
2Bug: https://launchpad.net/bugs/1378441
3Forwarded: not-needed
4Description: Add support for Google Compute Engine
5 In order to use cloud-init on GCE, we need a GCE data source. This backports
6 the GCE datasource from trusty, DataSourceGCE.py.
7 .
8 This is accompanied by a debian/cloud-init.templates change to enable debconf
9 to select the 'GCE' datasource.
10Index: precise-proposed/cloudinit/DataSourceGCE.py
11===================================================================
12--- /dev/null 1970-01-01 00:00:00.000000000 +0000
13+++ precise-proposed/cloudinit/DataSourceGCE.py 2014-10-07 15:43:05.054129022 +0100
14@@ -0,0 +1,156 @@
15+# vi: ts=4 expandtab
16+#
17+# Author: Vaidas Jablonskis <jablonskis@gmail.com>
18+#
19+# This program is free software: you can redistribute it and/or modify
20+# it under the terms of the GNU General Public License version 3, as
21+# published by the Free Software Foundation.
22+#
23+# This program is distributed in the hope that it will be useful,
24+# but WITHOUT ANY WARRANTY; without even the implied warranty of
25+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26+# GNU General Public License for more details.
27+#
28+# You should have received a copy of the GNU General Public License
29+# along with this program. If not, see <http://www.gnu.org/licenses/>.
30+
31+import logging
32+import urllib2
33+
34+from cloudinit import util
35+from cloudinit import DataSource as sources
36+
37+LOG = logging.getLogger(__name__)
38+
39+BUILTIN_DS_CONFIG = {
40+ 'metadata_url': 'http://metadata.google.internal./computeMetadata/v1/'
41+}
42+REQUIRED_FIELDS = ('instance-id', 'availability-zone', 'local-hostname')
43+
44+
45+class _FakeResponse(object):
46+
47+ def __init__(self, code, contents):
48+ self.code = code
49+ self.contents = contents
50+
51+
52+class url_helper(object):
53+ # This is a shim designed to look like url_helper.py from future versions
54+ # of cloud-init.
55+
56+ @staticmethod
57+ def readurl(url, headers):
58+ request = urllib2.Request(url, headers=headers)
59+ response = urllib2.urlopen(request)
60+ return _FakeResponse(code=response.getcode(), contents=response.read())
61+
62+ UrlError = urllib2.URLError
63+
64+
65+class DataSourceGCE(sources.DataSource):
66+ def __init__(self, sys_cfg):
67+ sources.DataSource.__init__(self, sys_cfg)
68+ self.metadata = dict()
69+ self.ds_cfg = util.mergedict(
70+ util.get_cfg_by_path(sys_cfg, ["datasource", "GCE"], {}),
71+ BUILTIN_DS_CONFIG)
72+ self.metadata_address = self.ds_cfg['metadata_url']
73+
74+ # GCE takes sshKeys attribute in the format of '<user>:<public_key>'
75+ # so we have to trim each key to remove the username part
76+ def _trim_key(self, public_key):
77+ try:
78+ index = public_key.index(':')
79+ if index > 0:
80+ return public_key[(index + 1):]
81+ except:
82+ return public_key
83+
84+ def get_data(self):
85+ # GCE metadata server requires a custom header since v1
86+ headers = {'X-Google-Metadata-Request': 'True'}
87+
88+ # url_map: (our-key, path, required)
89+ url_map = [
90+ ('instance-id', 'instance/id', True),
91+ ('availability-zone', 'instance/zone', True),
92+ ('local-hostname', 'instance/hostname', True),
93+ ('public-keys', 'project/attributes/sshKeys', False),
94+ ('user-data', 'instance/attributes/user-data', False),
95+ ]
96+
97+ # if we cannot resolve the metadata server, then no point in trying
98+ if not util.is_resolvable_url(self.metadata_address):
99+ LOG.debug("%s is not resolvable", self.metadata_address)
100+ return False
101+
102+ # iterate over url_map keys to get metadata items
103+ found = False
104+ for (mkey, path, required) in url_map:
105+ try:
106+ resp = url_helper.readurl(url=self.metadata_address + path,
107+ headers=headers)
108+ if resp.code == 200:
109+ found = True
110+ self.metadata[mkey] = resp.contents
111+ else:
112+ if required:
113+ msg = "required url %s returned code %s. not GCE"
114+ if not found:
115+ LOG.debug(msg, path, resp.code)
116+ else:
117+ LOG.warn(msg, path, resp.code)
118+ return False
119+ else:
120+ self.metadata[mkey] = None
121+ except url_helper.UrlError as e:
122+ if required:
123+ msg = "required url %s raised exception %s. not GCE"
124+ if not found:
125+ LOG.debug(msg, path, e)
126+ else:
127+ LOG.warn(msg, path, e)
128+ return False
129+ msg = "Failed to get %s metadata item: %s."
130+ LOG.debug(msg, path, e)
131+
132+ self.metadata[mkey] = None
133+
134+ if self.metadata['public-keys']:
135+ lines = self.metadata['public-keys'].splitlines()
136+ self.metadata['public-keys'] = [self._trim_key(k) for k in lines]
137+
138+ return found
139+
140+ @property
141+ def launch_index(self):
142+ # GCE does not provide lauch_index property
143+ return None
144+
145+ def get_instance_id(self):
146+ return self.metadata['instance-id']
147+
148+ def get_public_ssh_keys(self):
149+ return self.metadata['public-keys']
150+
151+ def get_hostname(self, fqdn=False, _resolve_ip=False):
152+ return self.metadata['local-hostname']
153+
154+ @property
155+ def userdata_raw(self):
156+ return self.metadata['user-data'] or ''
157+
158+ @property
159+ def availability_zone(self):
160+ return self.metadata['availability-zone']
161+
162+# Used to match classes to dependencies
163+datasources = [
164+ (DataSourceGCE, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
165+]
166+
167+
168+# Return a list of data sources that match this set of dependencies
169+def get_datasource_list(depends):
170+ return sources.list_from_depends(depends, datasources)
0171
=== modified file 'debian/patches/series'
--- debian/patches/series 2014-09-17 19:44:07 +0000
+++ debian/patches/series 2014-10-10 08:21:23 +0000
@@ -24,3 +24,4 @@
24lp-1302229-fix_futils_azure.patch24lp-1302229-fix_futils_azure.patch
25lp-1363260-add-cloudsigma_ds.patch25lp-1363260-add-cloudsigma_ds.patch
26lp-1336855-grub_xvda.patch26lp-1336855-grub_xvda.patch
27lp-1378441-backport-gce-data-source.patch

Subscribers

People subscribed via source and target branches

to all changes: