2
# Copyright (C) 2014 Vaidas Jablonskis
4
# Author: Vaidas Jablonskis <jablonskis@gmail.com>
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License version 3, as
8
# published by the Free Software Foundation.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
from base64 import b64encode, b64decode
21
from six.moves.urllib_parse import urlparse
23
from cloudinit import helpers
24
from cloudinit import settings
25
from cloudinit.sources import DataSourceGCE
27
from .. import helpers as test_helpers
29
httpretty = test_helpers.import_httpretty()
33
'instance/zone': 'foo/bar',
34
'project/attributes/sshKeys': 'user:ssh-rsa AA2..+aRD0fyVw== root@server',
35
'instance/hostname': 'server.project-foo.local',
36
'instance/attributes/user-data': b'/bin/echo foo\n',
40
'instance/id': '1234',
41
'instance/hostname': 'server.project-bar.local',
42
'instance/zone': 'bar/baz',
46
'instance/id': '12345',
47
'instance/hostname': 'server.project-baz.local',
48
'instance/zone': 'baz/bang',
49
'instance/attributes/user-data': b64encode(b'/bin/echo baz\n'),
50
'instance/attributes/user-data-encoding': 'base64',
53
HEADERS = {'X-Google-Metadata-Request': 'True'}
54
MD_URL_RE = re.compile(
55
r'http://metadata.google.internal/computeMetadata/v1/.*')
58
def _set_mock_metadata(gce_meta=None):
62
def _request_callback(method, uri, headers):
63
url_path = urlparse(uri).path
64
if url_path.startswith('/computeMetadata/v1/'):
65
path = url_path.split('/computeMetadata/v1/')[1:][0]
69
return (200, headers, gce_meta.get(path))
71
return (404, headers, '')
73
httpretty.register_uri(httpretty.GET, MD_URL_RE, body=_request_callback)
77
class TestDataSourceGCE(test_helpers.HttprettyTestCase):
80
self.ds = DataSourceGCE.DataSourceGCE(
81
settings.CFG_BUILTIN, None,
83
super(TestDataSourceGCE, self).setUp()
85
def test_connection(self):
87
success = self.ds.get_data()
88
self.assertTrue(success)
90
req_header = httpretty.last_request().headers
91
self.assertDictContainsSubset(HEADERS, req_header)
93
def test_metadata(self):
97
shostname = GCE_META.get('instance/hostname').split('.')[0]
98
self.assertEqual(shostname,
99
self.ds.get_hostname())
101
self.assertEqual(GCE_META.get('instance/id'),
102
self.ds.get_instance_id())
104
self.assertEqual(GCE_META.get('instance/attributes/user-data'),
105
self.ds.get_userdata_raw())
107
# test partial metadata (missing user-data in particular)
108
def test_metadata_partial(self):
109
_set_mock_metadata(GCE_META_PARTIAL)
112
self.assertEqual(GCE_META_PARTIAL.get('instance/id'),
113
self.ds.get_instance_id())
115
shostname = GCE_META_PARTIAL.get('instance/hostname').split('.')[0]
116
self.assertEqual(shostname, self.ds.get_hostname())
118
def test_metadata_encoding(self):
119
_set_mock_metadata(GCE_META_ENCODING)
123
GCE_META_ENCODING.get('instance/attributes/user-data'))
124
self.assertEqual(decoded, self.ds.get_userdata_raw())
126
def test_missing_required_keys_return_false(self):
127
for required_key in ['instance/id', 'instance/zone',
128
'instance/hostname']:
129
meta = GCE_META_PARTIAL.copy()
130
del meta[required_key]
131
_set_mock_metadata(meta)
132
self.assertEqual(False, self.ds.get_data())
135
def test_project_level_ssh_keys_are_used(self):
139
# we expect a list of public ssh keys with user names stripped
140
self.assertEqual(['ssh-rsa AA2..+aRD0fyVw== root@server'],
141
self.ds.get_public_ssh_keys())
143
def test_instance_level_ssh_keys_are_used(self):
144
key_content = 'ssh-rsa JustAUser root@server'
145
meta = GCE_META.copy()
146
meta['instance/attributes/sshKeys'] = 'user:{0}'.format(key_content)
148
_set_mock_metadata(meta)
151
self.assertIn(key_content, self.ds.get_public_ssh_keys())
153
def test_instance_level_keys_replace_project_level_keys(self):
154
key_content = 'ssh-rsa JustAUser root@server'
155
meta = GCE_META.copy()
156
meta['instance/attributes/sshKeys'] = 'user:{0}'.format(key_content)
158
_set_mock_metadata(meta)
161
self.assertEqual([key_content], self.ds.get_public_ssh_keys())
163
def test_only_last_part_of_zone_used_for_availability_zone(self):
166
self.assertEqual('bar', self.ds.availability_zone)