blob: 2382eb1e225df51315d040740121dfa6eea09064 [file] [log] [blame]
Tri Vo29ac1822016-10-01 17:06:29 -07001#!/usr/bin/env python
2#
3# Copyright 2016 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Tests for acloud.internal.lib.gcompute_client."""
18
19import os
20
21import apiclient.http
22import mock
23
24import unittest
25from acloud.internal.lib import driver_test_lib
26from acloud.internal.lib import gcompute_client
27from acloud.internal.lib import utils
28from acloud.public import errors
29
30
31class ComputeClientTest(driver_test_lib.BaseDriverTest):
32 """Test ComputeClient."""
33
34 PROJECT = "fake-project"
35 INSTANCE = "fake-instance"
36 IMAGE = "fake-image"
37 IMAGE_URL = "http://fake-image-url"
38 GS_IMAGE_SOURCE_URI = "https://storage.googleapis.com/fake-bucket/fake.tar.gz"
39 MACHINE_TYPE = "fake-machine-type"
40 MACHINE_TYPE_URL = "http://fake-machine-type-url"
41 METADATA = ("metadata_key", "metadata_value")
42 NETWORK = "fake-network"
43 NETWORK_URL = "http://fake-network-url"
44 ZONE = "fake-zone"
45 REGION = "fake-region"
46 OPERATION_NAME = "fake-op"
47
48 def setUp(self):
49 """Set up test."""
50 super(ComputeClientTest, self).setUp()
51 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
52 fake_cfg = mock.MagicMock()
53 fake_cfg.project = self.PROJECT
54 self.compute_client = gcompute_client.ComputeClient(fake_cfg,
55 mock.MagicMock())
56 self.compute_client._service = mock.MagicMock()
57
58 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
59 """A helper class for setting up mocks for testGetOperationStatus*.
60
61 Args:
62 mock_result: The result to return by _GetOperationStatus.
63 operation_scope: A value of OperationScope.
64
65 Returns:
66 A mock for Resource object.
67 """
68 resource_mock = mock.MagicMock()
69 mock_api = mock.MagicMock()
70 if operation_scope == gcompute_client.OperationScope.GLOBAL:
71 self.compute_client._service.globalOperations = mock.MagicMock(
72 return_value=resource_mock)
73 elif operation_scope == gcompute_client.OperationScope.ZONE:
74 self.compute_client._service.zoneOperations = mock.MagicMock(
75 return_value=resource_mock)
76 elif operation_scope == gcompute_client.OperationScope.REGION:
77 self.compute_client._service.regionOperations = mock.MagicMock(
78 return_value=resource_mock)
79 resource_mock.get = mock.MagicMock(return_value=mock_api)
80 mock_api.execute = mock.MagicMock(return_value=mock_result)
81 return resource_mock
82
83 def testGetOperationStatusGlobal(self):
84 """Test _GetOperationStatus for global."""
85 resource_mock = self._SetupMocksForGetOperationStatus(
86 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
87 status = self.compute_client._GetOperationStatus(
88 {"name": self.OPERATION_NAME},
89 gcompute_client.OperationScope.GLOBAL)
90 self.assertEqual(status, "GOOD")
91 resource_mock.get.assert_called_with(
92 project=self.PROJECT, operation=self.OPERATION_NAME)
93
94 def testGetOperationStatusZone(self):
95 """Test _GetOperationStatus for zone."""
96 resource_mock = self._SetupMocksForGetOperationStatus(
97 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
98 status = self.compute_client._GetOperationStatus(
99 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
100 self.ZONE)
101 self.assertEqual(status, "GOOD")
102 resource_mock.get.assert_called_with(
103 project=self.PROJECT,
104 operation=self.OPERATION_NAME,
105 zone=self.ZONE)
106
107 def testGetOperationStatusRegion(self):
108 """Test _GetOperationStatus for region."""
109 resource_mock = self._SetupMocksForGetOperationStatus(
110 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
111 self.compute_client._GetOperationStatus(
112 {"name": self.OPERATION_NAME},
113 gcompute_client.OperationScope.REGION, self.REGION)
114 resource_mock.get.assert_called_with(
115 project=self.PROJECT,
116 operation=self.OPERATION_NAME,
117 region=self.REGION)
118
119 def testGetOperationStatusError(self):
120 """Test _GetOperationStatus failed."""
121 self._SetupMocksForGetOperationStatus(
122 {"error": {"errors": ["error1", "error2"]}},
123 gcompute_client.OperationScope.GLOBAL)
124 self.assertRaisesRegexp(errors.DriverError,
125 "Get operation state failed.*error1.*error2",
126 self.compute_client._GetOperationStatus,
127 {"name": self.OPERATION_NAME},
128 gcompute_client.OperationScope.GLOBAL)
129
130 def testWaitOnOperation(self):
131 """Test WaitOnOperation."""
132 mock_error = mock.MagicMock()
133 self.Patch(utils, "PollAndWait")
134 self.Patch(errors, "GceOperationTimeoutError", return_value=mock_error)
135 self.compute_client.WaitOnOperation(
136 operation={"name": self.OPERATION_NAME},
137 operation_scope=gcompute_client.OperationScope.REGION,
138 scope_name=self.REGION)
139 utils.PollAndWait.assert_called_with(
140 func=self.compute_client._GetOperationStatus,
141 expected_return="DONE",
142 timeout_exception=mock_error,
143 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
144 sleep_interval_secs=self.compute_client.
145 OPERATION_POLL_INTERVAL_SECS,
146 operation={"name": self.OPERATION_NAME},
147 operation_scope=gcompute_client.OperationScope.REGION,
148 scope_name=self.REGION)
149
150 def testCreateImage(self):
151 """Test CreateImage."""
152 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
153 resource_mock = mock.MagicMock()
154 self.compute_client._service.images = mock.MagicMock(
155 return_value=resource_mock)
156 resource_mock.insert = mock.MagicMock()
157
158 expected_body = {
159 "name": self.IMAGE,
160 "rawDisk": {
161 "source": self.GS_IMAGE_SOURCE_URI,
162 },
163 }
164 self.compute_client.CreateImage(
165 image_name=self.IMAGE, source_uri=self.GS_IMAGE_SOURCE_URI)
166 resource_mock.insert.assert_called_with(
167 project=self.PROJECT, body=expected_body)
168 self.compute_client.WaitOnOperation.assert_called_with(
169 operation=mock.ANY,
170 operation_scope=gcompute_client.OperationScope.GLOBAL)
171
172 def testCreateImageFail(self):
173 """Test CreateImage fails."""
174 self.Patch(
175 gcompute_client.ComputeClient,
176 "WaitOnOperation",
177 side_effect=errors.DriverError("Expected fake error"))
178 self.Patch(
179 gcompute_client.ComputeClient,
180 "CheckImageExists",
181 return_value=True)
182 self.Patch(gcompute_client.ComputeClient, "DeleteImage")
183
184 resource_mock = mock.MagicMock()
185 self.compute_client._service.images = mock.MagicMock(
186 return_value=resource_mock)
187 resource_mock.insert = mock.MagicMock()
188
189 expected_body = {
190 "name": self.IMAGE,
191 "rawDisk": {
192 "source": self.GS_IMAGE_SOURCE_URI,
193 },
194 }
195 self.assertRaisesRegexp(
196 errors.DriverError,
197 "Expected fake error",
198 self.compute_client.CreateImage,
199 image_name=self.IMAGE,
200 source_uri=self.GS_IMAGE_SOURCE_URI)
201 resource_mock.insert.assert_called_with(
202 project=self.PROJECT, body=expected_body)
203 self.compute_client.WaitOnOperation.assert_called_with(
204 operation=mock.ANY,
205 operation_scope=gcompute_client.OperationScope.GLOBAL)
206 self.compute_client.CheckImageExists.assert_called_with(self.IMAGE)
207 self.compute_client.DeleteImage.assert_called_with(self.IMAGE)
208
209 def testCheckImageExistsTrue(self):
210 """Test CheckImageExists return True."""
211 resource_mock = mock.MagicMock()
212 mock_api = mock.MagicMock()
213 self.compute_client._service.images = mock.MagicMock(
214 return_value=resource_mock)
215 resource_mock.get = mock.MagicMock(return_value=mock_api)
216 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
217 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
218
219 def testCheckImageExistsFalse(self):
220 """Test CheckImageExists return False."""
221 resource_mock = mock.MagicMock()
222 mock_api = mock.MagicMock()
223 self.compute_client._service.images = mock.MagicMock(
224 return_value=resource_mock)
225 resource_mock.get = mock.MagicMock(return_value=mock_api)
226 mock_api.execute = mock.MagicMock(
227 side_effect=errors.ResourceNotFoundError(404, "no image"))
228 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
229
230 def testDeleteImage(self):
231 """Test DeleteImage."""
232 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
233 resource_mock = mock.MagicMock()
234 self.compute_client._service.images = mock.MagicMock(
235 return_value=resource_mock)
236 resource_mock.delete = mock.MagicMock()
237 self.compute_client.DeleteImage(self.IMAGE)
238 resource_mock.delete.assert_called_with(
239 project=self.PROJECT, image=self.IMAGE)
240 self.assertTrue(self.compute_client.WaitOnOperation.called)
241
242 def _SetupBatchHttpRequestMock(self):
243 """Setup BatchHttpRequest mock."""
244 requests = {}
245
246 def _Add(request, callback, request_id):
247 requests[request_id] = (request, callback)
248
249 def _Execute():
250 for rid in requests:
251 _, callback = requests[rid]
252 callback(
253 request_id=rid, response=mock.MagicMock(), exception=None)
254
255 mock_batch = mock.MagicMock()
256 mock_batch.add = _Add
257 mock_batch.execute = _Execute
258 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
259
260 def testDeleteImages(self):
261 """Test DeleteImages."""
262 self._SetupBatchHttpRequestMock()
263 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
264 fake_images = ["fake_image_1", "fake_image_2"]
265 mock_api = mock.MagicMock()
266 resource_mock = mock.MagicMock()
267 self.compute_client._service.images = mock.MagicMock(
268 return_value=resource_mock)
269 resource_mock.delete = mock.MagicMock(return_value=mock_api)
270 # Call the API.
271 deleted, failed, error_msgs = self.compute_client.DeleteImages(
272 fake_images)
273 # Verify
274 calls = [mock.call(
275 project=self.PROJECT, image="fake_image_1"), mock.call(
276 project=self.PROJECT, image="fake_image_2")]
277 resource_mock.delete.assert_has_calls(calls, any_order=True)
278 self.assertEqual(
279 gcompute_client.ComputeClient.WaitOnOperation.call_count, 2)
280 self.assertEqual(error_msgs, [])
281 self.assertEqual(failed, [])
282 self.assertEqual(set(deleted), set(fake_images))
283
284 def testListImages(self):
285 """Test ListImages."""
286 fake_token = "fake_next_page_token"
287 image_1 = "image_1"
288 image_2 = "image_2"
289 response_1 = {"items": [image_1], "nextPageToken": fake_token}
290 response_2 = {"items": [image_2]}
291 self.Patch(
292 gcompute_client.ComputeClient,
293 "Execute",
294 side_effect=[response_1, response_2])
295 resource_mock = mock.MagicMock()
296 self.compute_client._service.images = mock.MagicMock(
297 return_value=resource_mock)
298 resource_mock.list = mock.MagicMock()
299 images = self.compute_client.ListImages()
300 calls = [
301 mock.call(
302 project=self.PROJECT, filter=None, pageToken=None), mock.call(
303 project=self.PROJECT, filter=None, pageToken=fake_token)
304 ]
305 resource_mock.list.assert_has_calls(calls)
306 self.assertEqual(images, [image_1, image_2])
307
308 def testGetInstance(self):
309 """Test GetInstance."""
310 resource_mock = mock.MagicMock()
311 mock_api = mock.MagicMock()
312 self.compute_client._service.instances = mock.MagicMock(
313 return_value=resource_mock)
314 resource_mock.get = mock.MagicMock(return_value=mock_api)
315 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
316 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
317 self.assertEqual(result, {"name": self.INSTANCE})
318 resource_mock.get.assert_called_with(
319 project=self.PROJECT, zone=self.ZONE, instance=self.INSTANCE)
320
321 def testListInstances(self):
322 """Test ListInstances."""
323 fake_token = "fake_next_page_token"
324 instance_1 = "instance_1"
325 instance_2 = "instance_2"
326 response_1 = {"items": [instance_1], "nextPageToken": fake_token}
327 response_2 = {"items": [instance_2]}
328 self.Patch(
329 gcompute_client.ComputeClient,
330 "Execute",
331 side_effect=[response_1, response_2])
332 resource_mock = mock.MagicMock()
333 self.compute_client._service.instances = mock.MagicMock(
334 return_value=resource_mock)
335 resource_mock.list = mock.MagicMock()
336 instances = self.compute_client.ListInstances(self.ZONE)
337 calls = [
338 mock.call(
339 project=self.PROJECT,
340 zone=self.ZONE,
341 filter=None,
342 pageToken=None),
343 mock.call(
344 project=self.PROJECT,
345 zone=self.ZONE,
346 filter=None,
347 pageToken=fake_token),
348 ]
349 resource_mock.list.assert_has_calls(calls)
350 self.assertEqual(instances, [instance_1, instance_2])
351
352 def testCreateInstance(self):
353 """Test CreateInstance."""
354 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
355 self.Patch(
356 gcompute_client.ComputeClient,
357 "GetMachineType",
358 return_value={"selfLink": self.MACHINE_TYPE_URL})
359 self.Patch(
360 gcompute_client.ComputeClient,
361 "GetNetworkUrl",
362 return_value=self.NETWORK_URL)
363 self.Patch(
364 gcompute_client.ComputeClient,
365 "GetImage",
366 return_value={"selfLink": self.IMAGE_URL})
367
368 resource_mock = mock.MagicMock()
369 self.compute_client._service.instances = mock.MagicMock(
370 return_value=resource_mock)
371 resource_mock.insert = mock.MagicMock()
372
373 expected_body = {
374 "machineType": self.MACHINE_TYPE_URL,
375 "name": self.INSTANCE,
376 "networkInterfaces": [
377 {
378 "network": self.NETWORK_URL,
379 "accessConfigs": [
380 {"name": "External NAT",
381 "type": "ONE_TO_ONE_NAT"}
382 ],
383 }
384 ],
385 "disks": [
386 {
387 "type": "PERSISTENT",
388 "boot": True,
389 "mode": "READ_WRITE",
390 "autoDelete": True,
391 "initializeParams": {
392 "diskName": self.INSTANCE,
393 "sourceImage": self.IMAGE_URL,
394 },
395 }
396 ],
397 "serviceAccounts": [
398 {"email": "default",
399 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE}
400 ],
401 "metadata": {
402 "items": [{"key": self.METADATA[0],
403 "value": self.METADATA[1]}],
404 },
405 }
406
407 self.compute_client.CreateInstance(
408 instance=self.INSTANCE,
409 image_name=self.IMAGE,
410 machine_type=self.MACHINE_TYPE,
411 metadata={self.METADATA[0]: self.METADATA[1]},
412 network=self.NETWORK,
413 zone=self.ZONE)
414
415 resource_mock.insert.assert_called_with(
416 project=self.PROJECT, zone=self.ZONE, body=expected_body)
417 self.compute_client.WaitOnOperation.assert_called_with(
418 mock.ANY,
419 operation_scope=gcompute_client.OperationScope.ZONE,
420 scope_name=self.ZONE)
421
422 def testDeleteInstance(self):
423 """Test DeleteInstance."""
424 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
425 resource_mock = mock.MagicMock()
426 self.compute_client._service.instances = mock.MagicMock(
427 return_value=resource_mock)
428 resource_mock.delete = mock.MagicMock()
429 self.compute_client.DeleteInstance(
430 instance=self.INSTANCE, zone=self.ZONE)
431 resource_mock.delete.assert_called_with(
432 project=self.PROJECT, zone=self.ZONE, instance=self.INSTANCE)
433 self.compute_client.WaitOnOperation.assert_called_with(
434 mock.ANY,
435 operation_scope=gcompute_client.OperationScope.ZONE,
436 scope_name=self.ZONE)
437
438 def testDeleteInstances(self):
439 """Test DeleteInstances."""
440 self._SetupBatchHttpRequestMock()
441 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
442 fake_instances = ["fake_instance_1", "fake_instance_2"]
443 mock_api = mock.MagicMock()
444 resource_mock = mock.MagicMock()
445 self.compute_client._service.instances = mock.MagicMock(
446 return_value=resource_mock)
447 resource_mock.delete = mock.MagicMock(return_value=mock_api)
448 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
449 fake_instances, self.ZONE)
450 calls = [
451 mock.call(
452 project=self.PROJECT,
453 instance="fake_instance_1",
454 zone=self.ZONE), mock.call(
455 project=self.PROJECT,
456 instance="fake_instance_2",
457 zone=self.ZONE)
458 ]
459 resource_mock.delete.assert_has_calls(calls, any_order=True)
460 self.assertEqual(
461 gcompute_client.ComputeClient.WaitOnOperation.call_count, 2)
462 self.assertEqual(error_msgs, [])
463 self.assertEqual(failed, [])
464 self.assertEqual(set(deleted), set(fake_instances))
465
466 def testBatchExecuteOnInstances(self):
467 self._SetupBatchHttpRequestMock()
468 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
469 action = mock.MagicMock(return_value=mock.MagicMock())
470 fake_instances = ["fake_instance_1", "fake_instance_2"]
471 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
472 fake_instances, self.ZONE, action)
473 calls = [mock.call(instance="fake_instance_1"),
474 mock.call(instance="fake_instance_2")]
475 action.assert_has_calls(calls, any_order=True)
476 self.assertEqual(
477 gcompute_client.ComputeClient.WaitOnOperation.call_count, 2)
478 self.assertEqual(set(done), set(fake_instances))
479 self.assertEqual(error_msgs, [])
480 self.assertEqual(failed, [])
481
482 def testResetInstance(self):
483 """Test ResetInstance."""
484 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
485 resource_mock = mock.MagicMock()
486 self.compute_client._service.instances = mock.MagicMock(
487 return_value=resource_mock)
488 resource_mock.reset = mock.MagicMock()
489 self.compute_client.ResetInstance(
490 instance=self.INSTANCE, zone=self.ZONE)
491 resource_mock.reset.assert_called_with(
492 project=self.PROJECT, zone=self.ZONE, instance=self.INSTANCE)
493 self.compute_client.WaitOnOperation.assert_called_with(
494 mock.ANY,
495 operation_scope=gcompute_client.OperationScope.ZONE,
496 scope_name=self.ZONE)
497
498 def _CompareMachineSizeTestHelper(self,
499 machine_info_1,
500 machine_info_2,
501 expected_result=None,
502 expected_error_type=None):
503 """Helper class for testing CompareMachineSize.
504
505 Args:
506 machine_info_1: A dictionary representing the first machine size.
507 machine_info_2: A dictionary representing the second machine size.
508 expected_result: An integer, 0, 1 or -1, or None if not set.
509 expected_error_type: An exception type, if set will check for exception.
510 """
511 self.Patch(
512 gcompute_client.ComputeClient,
513 "GetMachineType",
514 side_effect=[machine_info_1, machine_info_2])
515 if expected_error_type:
516 self.assertRaises(expected_error_type,
517 self.compute_client.CompareMachineSize, "name1",
518 "name2", self.ZONE)
519 else:
520 result = self.compute_client.CompareMachineSize("name1", "name2",
521 self.ZONE)
522 self.assertEqual(result, expected_result)
523
524 self.compute_client.GetMachineType.assert_has_calls(
525 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
526
527 def testCompareMachineSizeSmall(self):
528 """Test CompareMachineSize where the first one is smaller."""
529 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
530 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
531 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
532
533 def testCompareMachineSizeLarge(self):
534 """Test CompareMachineSize where the first one is larger."""
535 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
536 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
537 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
538
539 def testCompareMachineSizeEqual(self):
540 """Test CompareMachineSize where two machine sizes are equal."""
541 machine_info = {"guestCpus": 10, "memoryMb": 100}
542 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
543
544 def testCompareMachineSizeBadMetric(self):
545 """Test CompareMachineSize with bad metric."""
546 machine_info = {"unkown_metric": 10, "memoryMb": 100}
547 self._CompareMachineSizeTestHelper(
548 machine_info, machine_info, expected_error_type=errors.DriverError)
549
550 def testGetMachineType(self):
551 """Test GetMachineType."""
552 resource_mock = mock.MagicMock()
553 mock_api = mock.MagicMock()
554 self.compute_client._service.machineTypes = mock.MagicMock(
555 return_value=resource_mock)
556 resource_mock.get = mock.MagicMock(return_value=mock_api)
557 mock_api.execute = mock.MagicMock(
558 return_value={"name": self.MACHINE_TYPE})
559 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
560 self.ZONE)
561 self.assertEqual(result, {"name": self.MACHINE_TYPE})
562 resource_mock.get.assert_called_with(
563 project=self.PROJECT,
564 zone=self.ZONE,
565 machineType=self.MACHINE_TYPE)
566
567 def _GetSerialPortOutputTestHelper(self, response):
568 """Helper function for testing GetSerialPortOutput.
569
570 Args:
571 response: A dictionary representing a fake response.
572 """
573 resource_mock = mock.MagicMock()
574 mock_api = mock.MagicMock()
575 self.compute_client._service.instances = mock.MagicMock(
576 return_value=resource_mock)
577 resource_mock.getSerialPortOutput = mock.MagicMock(
578 return_value=mock_api)
579 mock_api.execute = mock.MagicMock(return_value=response)
580
581 if "contents" in response:
582 result = self.compute_client.GetSerialPortOutput(
583 instance=self.INSTANCE, zone=self.ZONE)
584 self.assertEqual(result, "fake contents")
585 else:
586 self.assertRaisesRegexp(
587 errors.DriverError,
588 "Malformed response.*",
589 self.compute_client.GetSerialPortOutput,
590 instance=self.INSTANCE,
591 zone=self.ZONE)
592 resource_mock.getSerialPortOutput.assert_called_with(
593 project=self.PROJECT,
594 zone=self.ZONE,
595 instance=self.INSTANCE,
596 port=1)
597
598 def testGetSerialPortOutput(self):
599 response = {"contents": "fake contents"}
600 self._GetSerialPortOutputTestHelper(response)
601
602 def testGetSerialPortOutputFail(self):
603 response = {"malformed": "fake contents"}
604 self._GetSerialPortOutputTestHelper(response)
605
606 def testGetInstanceNamesByIPs(self):
607 """Test GetInstanceNamesByIPs."""
608 good_instance = {
609 "name": "instance_1",
610 "networkInterfaces": [
611 {
612 "accessConfigs": [
613 {"natIP": "172.22.22.22"},
614 ],
615 },
616 ],
617 }
618 bad_instance = {"name": "instance_2"}
619 self.Patch(
620 gcompute_client.ComputeClient,
621 "ListInstances",
622 return_value=[good_instance, bad_instance])
623 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
624 ips=["172.22.22.22", "172.22.22.23"], zone=self.ZONE)
625 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
626 "172.22.22.23": None})
627
628 def testAddSshRsa(self):
629 """Test AddSshRsa.."""
630 fake_user = "fake_user"
631 sshkey = (
632 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
633 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
634 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
635 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
636 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
637 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
638 "ApiihqNL1111 test@test1.org")
639 project = {
640 "commonInstanceMetadata": {
641 "kind": "compute#metadata",
642 "fingerprint": "a-23icsyx4E=",
643 "items": [
644 {
645 "key": "sshKeys",
646 "value": "user:key"
647 }
648 ]
649 }
650 }
651 expected = {
652 "kind": "compute#metadata",
653 "fingerprint": "a-23icsyx4E=",
654 "items": [
655 {
656 "key": "sshKeys",
657 "value": "user:key\n%s:%s" % (fake_user, sshkey)
658 }
659 ]
660 }
661
662 self.Patch(os.path, "exists", return_value=True)
663 m = mock.mock_open(read_data=sshkey)
664 self.Patch(__builtins__, "open", m, create=True)
665 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
666 self.Patch(
667 gcompute_client.ComputeClient, "GetProject", return_value=project)
668 resource_mock = mock.MagicMock()
669 self.compute_client._service.projects = mock.MagicMock(
670 return_value=resource_mock)
671 resource_mock.setCommonInstanceMetadata = mock.MagicMock()
672
673 self.compute_client.AddSshRsa(fake_user, "/path/to/test_rsa.pub")
674 resource_mock.setCommonInstanceMetadata.assert_called_with(
675 project=self.PROJECT, body=expected)
676
677 def testAddSshRsaInvalidKey(self):
678 """Test AddSshRsa.."""
679 fake_user = "fake_user"
680 sshkey = "ssh-rsa v2VOqkkf7RGL1111 test@test1.org"
681 project = {
682 "commonInstanceMetadata": {
683 "kind": "compute#metadata",
684 "fingerprint": "a-23icsyx4E=",
685 "items": [
686 {
687 "key": "sshKeys",
688 "value": "user:key"
689 }
690 ]
691 }
692 }
693 self.Patch(os.path, "exists", return_value=True)
694 m = mock.mock_open(read_data=sshkey)
695 self.Patch(__builtins__, "open", m, create=True)
696 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
697 self.Patch(
698 gcompute_client.ComputeClient, "GetProject", return_value=project)
699 self.assertRaisesRegexp(errors.DriverError, "rsa key is invalid:*",
700 self.compute_client.AddSshRsa, fake_user,
701 "/path/to/test_rsa.pub")
702
703 def testDeleteDisks(self):
704 """Test DeleteDisks."""
705 self._SetupBatchHttpRequestMock()
706 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
707 fake_disks = ["fake_disk_1", "fake_disk_2"]
708 mock_api = mock.MagicMock()
709 resource_mock = mock.MagicMock()
710 self.compute_client._service.disks = mock.MagicMock(
711 return_value=resource_mock)
712 resource_mock.delete = mock.MagicMock(return_value=mock_api)
713 # Call the API.
714 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
715 fake_disks, zone=self.ZONE)
716 # Verify
717 calls = [mock.call(
718 project=self.PROJECT, disk="fake_disk_1", zone=self.ZONE),
719 mock.call(
720 project=self.PROJECT, disk="fake_disk_2", zone=self.ZONE)]
721 resource_mock.delete.assert_has_calls(calls, any_order=True)
722 self.assertEqual(
723 gcompute_client.ComputeClient.WaitOnOperation.call_count, 2)
724 self.assertEqual(error_msgs, [])
725 self.assertEqual(failed, [])
726 self.assertEqual(set(deleted), set(fake_disks))
727
728
729if __name__ == "__main__":
730 unittest.main()