blob: d4f225d4970ca8eaf7c75c76d6444353a463a717 [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.
Tri Vo29ac1822016-10-01 17:06:29 -070016"""Tests for acloud.internal.lib.gcompute_client."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -070017# pylint: disable=too-many-lines
Tri Vo29ac1822016-10-01 17:06:29 -070018
Kevin Cheng5c124ec2018-05-16 13:28:51 -070019import copy
Tri Vo29ac1822016-10-01 17:06:29 -070020import os
21
Kevin Cheng5c124ec2018-05-16 13:28:51 -070022import unittest
Tri Vo29ac1822016-10-01 17:06:29 -070023import mock
Kevin Cheng5c124ec2018-05-16 13:28:51 -070024
25# pylint: disable=import-error
Kevin Chengda4f07a2018-06-26 10:25:05 -070026import apiclient.http
Tri Vo29ac1822016-10-01 17:06:29 -070027
Sam Chiu7de3b232018-12-06 19:45:52 +080028from acloud import errors
cylanc2f98802019-08-15 17:47:30 +080029from acloud.internal import constants
Tri Vo29ac1822016-10-01 17:06:29 -070030from acloud.internal.lib import driver_test_lib
31from acloud.internal.lib import gcompute_client
32from acloud.internal.lib import utils
Tri Vo29ac1822016-10-01 17:06:29 -070033
herbertxue1512f8a2019-06-27 13:56:23 +080034
Kevin Chengb5963882018-05-09 00:06:27 -070035GS_IMAGE_SOURCE_URI = "https://storage.googleapis.com/fake-bucket/fake.tar.gz"
36GS_IMAGE_SOURCE_DISK = (
37 "https://www.googleapis.com/compute/v1/projects/fake-project/zones/"
38 "us-east1-d/disks/fake-disk")
39PROJECT = "fake-project"
Tri Vo29ac1822016-10-01 17:06:29 -070040
herbertxue1512f8a2019-06-27 13:56:23 +080041
Kevin Cheng5c124ec2018-05-16 13:28:51 -070042# pylint: disable=protected-access, too-many-public-methods
Kevin Cheng070ae5c2018-08-02 16:03:00 -070043class ComputeClientTest(driver_test_lib.BaseDriverTest):
Tri Vo29ac1822016-10-01 17:06:29 -070044 """Test ComputeClient."""
45
Kevin Chengb5963882018-05-09 00:06:27 -070046 PROJECT_OTHER = "fake-project-other"
Tri Vo29ac1822016-10-01 17:06:29 -070047 INSTANCE = "fake-instance"
48 IMAGE = "fake-image"
49 IMAGE_URL = "http://fake-image-url"
Kevin Chengb5963882018-05-09 00:06:27 -070050 IMAGE_OTHER = "fake-image-other"
Tri Vo29ac1822016-10-01 17:06:29 -070051 MACHINE_TYPE = "fake-machine-type"
52 MACHINE_TYPE_URL = "http://fake-machine-type-url"
53 METADATA = ("metadata_key", "metadata_value")
Kevin Chengb5963882018-05-09 00:06:27 -070054 ACCELERATOR_URL = "http://speedy-gpu"
Tri Vo29ac1822016-10-01 17:06:29 -070055 NETWORK = "fake-network"
56 NETWORK_URL = "http://fake-network-url"
Kevin Cheng480e1212018-10-24 00:23:30 -070057 SUBNETWORK_URL = "http://fake-subnetwork-url"
Tri Vo29ac1822016-10-01 17:06:29 -070058 ZONE = "fake-zone"
59 REGION = "fake-region"
60 OPERATION_NAME = "fake-op"
Kevin Chengb5963882018-05-09 00:06:27 -070061 IMAGE_FINGERPRINT = "L_NWHuz7wTY="
62 GPU = "fancy-graphics"
cylan64af2db2019-01-17 15:13:59 +080063 SSHKEY = (
64 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
65 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
66 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
67 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
68 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
69 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
70 "ApiihqNL1111 test@test1.org")
Kevin Chengc330f6f2019-05-13 09:32:42 -070071 EXTRA_SCOPES = ["scope1"]
Tri Vo29ac1822016-10-01 17:06:29 -070072
73 def setUp(self):
74 """Set up test."""
75 super(ComputeClientTest, self).setUp()
76 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
77 fake_cfg = mock.MagicMock()
Kevin Chengb5963882018-05-09 00:06:27 -070078 fake_cfg.project = PROJECT
Kevin Chengc330f6f2019-05-13 09:32:42 -070079 fake_cfg.extra_scopes = self.EXTRA_SCOPES
Kevin Chengb5963882018-05-09 00:06:27 -070080 self.compute_client = gcompute_client.ComputeClient(
81 fake_cfg, mock.MagicMock())
Tri Vo29ac1822016-10-01 17:06:29 -070082 self.compute_client._service = mock.MagicMock()
83
Kevin Cheng5c124ec2018-05-16 13:28:51 -070084 self._disk_args = copy.deepcopy(gcompute_client.BASE_DISK_ARGS)
85 self._disk_args["initializeParams"] = {"diskName": self.INSTANCE,
86 "sourceImage": self.IMAGE_URL}
87
88 # pylint: disable=invalid-name
Tri Vo29ac1822016-10-01 17:06:29 -070089 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
90 """A helper class for setting up mocks for testGetOperationStatus*.
91
Kevin Chengb5963882018-05-09 00:06:27 -070092 Args:
93 mock_result: The result to return by _GetOperationStatus.
94 operation_scope: A value of OperationScope.
Tri Vo29ac1822016-10-01 17:06:29 -070095
Kevin Chengb5963882018-05-09 00:06:27 -070096 Returns:
97 A mock for Resource object.
98 """
Tri Vo29ac1822016-10-01 17:06:29 -070099 resource_mock = mock.MagicMock()
100 mock_api = mock.MagicMock()
101 if operation_scope == gcompute_client.OperationScope.GLOBAL:
102 self.compute_client._service.globalOperations = mock.MagicMock(
103 return_value=resource_mock)
104 elif operation_scope == gcompute_client.OperationScope.ZONE:
105 self.compute_client._service.zoneOperations = mock.MagicMock(
106 return_value=resource_mock)
107 elif operation_scope == gcompute_client.OperationScope.REGION:
108 self.compute_client._service.regionOperations = mock.MagicMock(
109 return_value=resource_mock)
110 resource_mock.get = mock.MagicMock(return_value=mock_api)
111 mock_api.execute = mock.MagicMock(return_value=mock_result)
112 return resource_mock
113
114 def testGetOperationStatusGlobal(self):
115 """Test _GetOperationStatus for global."""
116 resource_mock = self._SetupMocksForGetOperationStatus(
117 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
118 status = self.compute_client._GetOperationStatus(
119 {"name": self.OPERATION_NAME},
120 gcompute_client.OperationScope.GLOBAL)
121 self.assertEqual(status, "GOOD")
122 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700123 project=PROJECT, operation=self.OPERATION_NAME)
Tri Vo29ac1822016-10-01 17:06:29 -0700124
125 def testGetOperationStatusZone(self):
126 """Test _GetOperationStatus for zone."""
127 resource_mock = self._SetupMocksForGetOperationStatus(
128 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
129 status = self.compute_client._GetOperationStatus(
130 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
131 self.ZONE)
132 self.assertEqual(status, "GOOD")
133 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700134 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700135 operation=self.OPERATION_NAME,
136 zone=self.ZONE)
137
138 def testGetOperationStatusRegion(self):
139 """Test _GetOperationStatus for region."""
140 resource_mock = self._SetupMocksForGetOperationStatus(
141 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
142 self.compute_client._GetOperationStatus(
143 {"name": self.OPERATION_NAME},
144 gcompute_client.OperationScope.REGION, self.REGION)
145 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700146 project=PROJECT, operation=self.OPERATION_NAME, region=self.REGION)
Tri Vo29ac1822016-10-01 17:06:29 -0700147
148 def testGetOperationStatusError(self):
149 """Test _GetOperationStatus failed."""
150 self._SetupMocksForGetOperationStatus(
151 {"error": {"errors": ["error1", "error2"]}},
152 gcompute_client.OperationScope.GLOBAL)
153 self.assertRaisesRegexp(errors.DriverError,
154 "Get operation state failed.*error1.*error2",
155 self.compute_client._GetOperationStatus,
156 {"name": self.OPERATION_NAME},
157 gcompute_client.OperationScope.GLOBAL)
158
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700159 @mock.patch.object(errors, "GceOperationTimeoutError")
160 @mock.patch.object(utils, "PollAndWait")
161 def testWaitOnOperation(self, mock_poll, mock_gce_operation_timeout_error):
Tri Vo29ac1822016-10-01 17:06:29 -0700162 """Test WaitOnOperation."""
163 mock_error = mock.MagicMock()
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700164 mock_gce_operation_timeout_error.return_value = mock_error
Tri Vo29ac1822016-10-01 17:06:29 -0700165 self.compute_client.WaitOnOperation(
166 operation={"name": self.OPERATION_NAME},
167 operation_scope=gcompute_client.OperationScope.REGION,
168 scope_name=self.REGION)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700169 mock_poll.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700170 func=self.compute_client._GetOperationStatus,
171 expected_return="DONE",
172 timeout_exception=mock_error,
173 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
Kevin Chengb5963882018-05-09 00:06:27 -0700174 sleep_interval_secs=self.compute_client.OPERATION_POLL_INTERVAL_SECS,
Tri Vo29ac1822016-10-01 17:06:29 -0700175 operation={"name": self.OPERATION_NAME},
176 operation_scope=gcompute_client.OperationScope.REGION,
177 scope_name=self.REGION)
178
Kevin Chengb5963882018-05-09 00:06:27 -0700179 def testGetImage(self):
180 """Test GetImage."""
181 resource_mock = mock.MagicMock()
182 mock_api = mock.MagicMock()
183 self.compute_client._service.images = mock.MagicMock(
184 return_value=resource_mock)
185 resource_mock.get = mock.MagicMock(return_value=mock_api)
186 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
187 result = self.compute_client.GetImage(self.IMAGE)
188 self.assertEqual(result, {"name": self.IMAGE})
189 resource_mock.get.assert_called_with(project=PROJECT, image=self.IMAGE)
190
191 def testGetImageOther(self):
192 """Test GetImage with other project."""
193 resource_mock = mock.MagicMock()
194 mock_api = mock.MagicMock()
195 self.compute_client._service.images = mock.MagicMock(
196 return_value=resource_mock)
197 resource_mock.get = mock.MagicMock(return_value=mock_api)
198 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE_OTHER})
199 result = self.compute_client.GetImage(
200 image_name=self.IMAGE_OTHER,
201 image_project=self.PROJECT_OTHER)
202 self.assertEqual(result, {"name": self.IMAGE_OTHER})
203 resource_mock.get.assert_called_with(
204 project=self.PROJECT_OTHER, image=self.IMAGE_OTHER)
205
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700206 def testCreateImageWithSourceURI(self):
207 """Test CreateImage with src uri."""
208 source_uri = GS_IMAGE_SOURCE_URI
209 source_disk = None
210 labels = None
211 expected_body = {"name": self.IMAGE,
212 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}
213 mock_check = self.Patch(gcompute_client.ComputeClient,
214 "CheckImageExists",
215 return_value=False)
216 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
217 resource_mock = mock.MagicMock()
218 self.compute_client._service.images = mock.MagicMock(
219 return_value=resource_mock)
220 resource_mock.insert = mock.MagicMock()
221 self.compute_client.CreateImage(
222 image_name=self.IMAGE, source_uri=source_uri,
223 source_disk=source_disk, labels=labels)
224 resource_mock.insert.assert_called_with(
225 project=PROJECT, body=expected_body)
226 mock_wait.assert_called_with(
227 operation=mock.ANY,
228 operation_scope=gcompute_client.OperationScope.GLOBAL)
229 mock_check.assert_called_with(self.IMAGE)
230
231 def testCreateImageWithSourceDisk(self):
232 """Test CreateImage with src disk."""
233 source_uri = None
234 source_disk = GS_IMAGE_SOURCE_DISK
235 labels = None
236 expected_body = {"name": self.IMAGE,
237 "sourceDisk": GS_IMAGE_SOURCE_DISK}
238 mock_check = self.Patch(gcompute_client.ComputeClient,
239 "CheckImageExists",
240 return_value=False)
241 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
242 resource_mock = mock.MagicMock()
243 self.compute_client._service.images = mock.MagicMock(
244 return_value=resource_mock)
245 resource_mock.insert = mock.MagicMock()
246 self.compute_client.CreateImage(
247 image_name=self.IMAGE, source_uri=source_uri,
248 source_disk=source_disk, labels=labels)
249 resource_mock.insert.assert_called_with(
250 project=PROJECT, body=expected_body)
251 mock_wait.assert_called_with(
252 operation=mock.ANY,
253 operation_scope=gcompute_client.OperationScope.GLOBAL)
254 mock_check.assert_called_with(self.IMAGE)
255
256 def testCreateImageWithSourceDiskAndLabel(self):
257 """Test CreateImage with src disk and label."""
258 source_uri = None
259 source_disk = GS_IMAGE_SOURCE_DISK
260 labels = {"label1": "xxx"}
261 expected_body = {"name": self.IMAGE,
262 "sourceDisk": GS_IMAGE_SOURCE_DISK,
263 "labels": {"label1": "xxx"}}
herbertxue308f7662018-05-18 03:25:58 +0000264 mock_check = self.Patch(gcompute_client.ComputeClient,
265 "CheckImageExists",
266 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700267 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700268 resource_mock = mock.MagicMock()
269 self.compute_client._service.images = mock.MagicMock(
270 return_value=resource_mock)
271 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700272 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700273 image_name=self.IMAGE, source_uri=source_uri,
274 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700275 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700276 project=PROJECT, body=expected_body)
277 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700278 operation=mock.ANY,
279 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000280 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700281
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700282 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
283 def testSetImageLabel(self, mock_get_image):
284 """Test SetImageLabel."""
285 with mock.patch.object(self.compute_client._service, "images",
286 return_value=mock.MagicMock(
287 setLabels=mock.MagicMock())) as _:
288 image = {"name": self.IMAGE,
289 "sourceDisk": GS_IMAGE_SOURCE_DISK,
290 "labelFingerprint": self.IMAGE_FINGERPRINT,
291 "labels": {"a": "aaa", "b": "bbb"}}
292 mock_get_image.return_value = image
293 new_labels = {"a": "xxx", "c": "ccc"}
294 # Test
295 self.compute_client.SetImageLabels(
296 self.IMAGE, new_labels)
297 # Check result
298 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
299 self.compute_client._service.images().setLabels.assert_called_with(
300 project=PROJECT,
301 resource=self.IMAGE,
302 body={
303 "labels": expected_labels,
304 "labelFingerprint": self.IMAGE_FINGERPRINT
305 })
Kevin Chengb5963882018-05-09 00:06:27 -0700306
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700307 def testCreateImageRaiseDriverErrorWithValidInput(self):
308 """Test CreateImage with valid input."""
309 source_uri = GS_IMAGE_SOURCE_URI
310 source_disk = GS_IMAGE_SOURCE_DISK
herbertxue308f7662018-05-18 03:25:58 +0000311 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700312 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
313 image_name=self.IMAGE, source_uri=source_uri,
314 source_disk=source_disk)
315
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700316 def testCreateImageRaiseDriverErrorWithInvalidInput(self):
317 """Test CreateImage with valid input."""
318 source_uri = None
319 source_disk = None
320 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
321 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
322 image_name=self.IMAGE, source_uri=source_uri,
323 source_disk=source_disk)
Tri Vo29ac1822016-10-01 17:06:29 -0700324
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700325 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
326 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000327 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700328 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
329 side_effect=errors.DriverError("Expected fake error"))
330 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
331 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700332 resource_mock = mock.MagicMock()
333 self.compute_client._service.images = mock.MagicMock(
334 return_value=resource_mock)
335 resource_mock.insert = mock.MagicMock()
336
337 expected_body = {
338 "name": self.IMAGE,
339 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700340 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700341 },
342 }
343 self.assertRaisesRegexp(
344 errors.DriverError,
345 "Expected fake error",
346 self.compute_client.CreateImage,
347 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700348 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700349 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700350 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700351 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700352 operation=mock.ANY,
353 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700354 mock_check.assert_called_with(self.IMAGE)
355 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700356
357 def testCheckImageExistsTrue(self):
358 """Test CheckImageExists return True."""
359 resource_mock = mock.MagicMock()
360 mock_api = mock.MagicMock()
361 self.compute_client._service.images = mock.MagicMock(
362 return_value=resource_mock)
363 resource_mock.get = mock.MagicMock(return_value=mock_api)
364 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
365 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
366
367 def testCheckImageExistsFalse(self):
368 """Test CheckImageExists return False."""
369 resource_mock = mock.MagicMock()
370 mock_api = mock.MagicMock()
371 self.compute_client._service.images = mock.MagicMock(
372 return_value=resource_mock)
373 resource_mock.get = mock.MagicMock(return_value=mock_api)
374 mock_api.execute = mock.MagicMock(
375 side_effect=errors.ResourceNotFoundError(404, "no image"))
376 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
377
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700378 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
379 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700380 """Test DeleteImage."""
Tri Vo29ac1822016-10-01 17:06:29 -0700381 resource_mock = mock.MagicMock()
382 self.compute_client._service.images = mock.MagicMock(
383 return_value=resource_mock)
384 resource_mock.delete = mock.MagicMock()
385 self.compute_client.DeleteImage(self.IMAGE)
386 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700387 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700388 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700389
390 def _SetupBatchHttpRequestMock(self):
391 """Setup BatchHttpRequest mock."""
392 requests = {}
393
394 def _Add(request, callback, request_id):
395 requests[request_id] = (request, callback)
396
397 def _Execute():
398 for rid in requests:
399 _, callback = requests[rid]
400 callback(
401 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700402 mock_batch = mock.MagicMock()
403 mock_batch.add = _Add
404 mock_batch.execute = _Execute
405 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
406
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700407 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
408 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700409 """Test DeleteImages."""
410 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700411 fake_images = ["fake_image_1", "fake_image_2"]
412 mock_api = mock.MagicMock()
413 resource_mock = mock.MagicMock()
414 self.compute_client._service.images = mock.MagicMock(
415 return_value=resource_mock)
416 resource_mock.delete = mock.MagicMock(return_value=mock_api)
417 # Call the API.
418 deleted, failed, error_msgs = self.compute_client.DeleteImages(
419 fake_images)
420 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700421 calls = [
422 mock.call(project=PROJECT, image="fake_image_1"),
423 mock.call(project=PROJECT, image="fake_image_2")
424 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700425 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700426 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700427 self.assertEqual(error_msgs, [])
428 self.assertEqual(failed, [])
429 self.assertEqual(set(deleted), set(fake_images))
430
431 def testListImages(self):
432 """Test ListImages."""
433 fake_token = "fake_next_page_token"
434 image_1 = "image_1"
435 image_2 = "image_2"
436 response_1 = {"items": [image_1], "nextPageToken": fake_token}
437 response_2 = {"items": [image_2]}
438 self.Patch(
439 gcompute_client.ComputeClient,
440 "Execute",
441 side_effect=[response_1, response_2])
442 resource_mock = mock.MagicMock()
443 self.compute_client._service.images = mock.MagicMock(
444 return_value=resource_mock)
445 resource_mock.list = mock.MagicMock()
446 images = self.compute_client.ListImages()
447 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700448 mock.call(project=PROJECT, filter=None, pageToken=None),
449 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700450 ]
451 resource_mock.list.assert_has_calls(calls)
452 self.assertEqual(images, [image_1, image_2])
453
Kevin Chengb5963882018-05-09 00:06:27 -0700454 def testListImagesFromExternalProject(self):
455 """Test ListImages which accepts different project."""
456 image = "image_1"
457 response = {"items": [image]}
458 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
459 resource_mock = mock.MagicMock()
460 self.compute_client._service.images = mock.MagicMock(
461 return_value=resource_mock)
462 resource_mock.list = mock.MagicMock()
463 images = self.compute_client.ListImages(
464 image_project="fake-project-2")
465 calls = [
466 mock.call(project="fake-project-2", filter=None, pageToken=None)]
467 resource_mock.list.assert_has_calls(calls)
468 self.assertEqual(images, [image])
469
Tri Vo29ac1822016-10-01 17:06:29 -0700470 def testGetInstance(self):
471 """Test GetInstance."""
472 resource_mock = mock.MagicMock()
473 mock_api = mock.MagicMock()
474 self.compute_client._service.instances = mock.MagicMock(
475 return_value=resource_mock)
476 resource_mock.get = mock.MagicMock(return_value=mock_api)
477 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
478 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
479 self.assertEqual(result, {"name": self.INSTANCE})
480 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700481 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700482
483 def testListInstances(self):
484 """Test ListInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700485 instance_1 = "instance_1"
486 instance_2 = "instance_2"
herbertxue7a501212019-08-29 15:37:13 +0800487 response = {"items": {'zones/fake_zone': {"instances": [instance_1, instance_2]}}}
Tri Vo29ac1822016-10-01 17:06:29 -0700488 self.Patch(
489 gcompute_client.ComputeClient,
490 "Execute",
herbertxue7a501212019-08-29 15:37:13 +0800491 side_effect=[response])
Tri Vo29ac1822016-10-01 17:06:29 -0700492 resource_mock = mock.MagicMock()
493 self.compute_client._service.instances = mock.MagicMock(
494 return_value=resource_mock)
herbertxue7a501212019-08-29 15:37:13 +0800495 resource_mock.aggregatedList = mock.MagicMock()
496 instances = self.compute_client.ListInstances()
Tri Vo29ac1822016-10-01 17:06:29 -0700497 calls = [
498 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700499 project=PROJECT,
herbertxue7a501212019-08-29 15:37:13 +0800500 filter=None),
Tri Vo29ac1822016-10-01 17:06:29 -0700501 ]
herbertxue7a501212019-08-29 15:37:13 +0800502 resource_mock.aggregatedList.assert_has_calls(calls)
Tri Vo29ac1822016-10-01 17:06:29 -0700503 self.assertEqual(instances, [instance_1, instance_2])
504
herbertxue7a501212019-08-29 15:37:13 +0800505 def testGetZoneByInstance(self):
506 """Test GetZoneByInstance."""
507 instance_1 = "instance_1"
508 response = {"items": {'zones/fake_zone': {"instances": [instance_1]}}}
509 self.Patch(
510 gcompute_client.ComputeClient,
511 "Execute",
512 side_effect=[response])
513 expected_zone = "fake_zone"
514 self.assertEqual(self.compute_client.GetZoneByInstance(instance_1),
515 expected_zone)
516
517 # Test unable to find 'zone' from instance name.
518 response = {"items": {'zones/fake_zone': {"warning": "No instances."}}}
519 self.Patch(
520 gcompute_client.ComputeClient,
521 "Execute",
522 side_effect=[response])
523 with self.assertRaises(errors.GetGceZoneError):
524 self.compute_client.GetZoneByInstance(instance_1)
525
526 def testGetZonesByInstances(self):
527 """Test GetZonesByInstances."""
528 instances = ["instance_1", "instance_2"]
529 # Test instances in the same zone.
530 self.Patch(
531 gcompute_client.ComputeClient,
532 "GetZoneByInstance",
533 side_effect=["zone_1", "zone_1"])
534 expected_result = {"zone_1": ["instance_1", "instance_2"]}
535 self.assertEqual(self.compute_client.GetZonesByInstances(instances),
536 expected_result)
537
538 # Test instances in different zones.
539 self.Patch(
540 gcompute_client.ComputeClient,
541 "GetZoneByInstance",
542 side_effect=["zone_1", "zone_2"])
543 expected_result = {"zone_1": ["instance_1"],
544 "zone_2": ["instance_2"]}
545 self.assertEqual(self.compute_client.GetZonesByInstances(instances),
546 expected_result)
547
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700548 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
549 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700550 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700551 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
552 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800553 @mock.patch("getpass.getuser", return_value="fake_user")
554 def testCreateInstance(self, _get_user, mock_wait, mock_get_mach_type,
Kevin Cheng480e1212018-10-24 00:23:30 -0700555 mock_get_subnetwork_url, mock_get_network_url,
556 mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700557 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700558 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
559 mock_get_network_url.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700560 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700561 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700562 resource_mock = mock.MagicMock()
563 self.compute_client._service.instances = mock.MagicMock(
564 return_value=resource_mock)
565 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000566 self.Patch(
567 self.compute_client,
568 "_GetExtraDiskArgs",
569 return_value=[{"fake_extra_arg": "fake_extra_value"}])
570 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
571 expected_disk_args = [self._disk_args]
572 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Kevin Chengc330f6f2019-05-13 09:32:42 -0700573 expected_scope = []
574 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
575 expected_scope.extend(self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700576
577 expected_body = {
578 "machineType": self.MACHINE_TYPE_URL,
579 "name": self.INSTANCE,
580 "networkInterfaces": [
581 {
582 "network": self.NETWORK_URL,
Kevin Cheng480e1212018-10-24 00:23:30 -0700583 "subnetwork": self.SUBNETWORK_URL,
Tri Vo29ac1822016-10-01 17:06:29 -0700584 "accessConfigs": [
585 {"name": "External NAT",
586 "type": "ONE_TO_ONE_NAT"}
587 ],
588 }
589 ],
herbertxue308f7662018-05-18 03:25:58 +0000590 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700591 "serviceAccounts": [
592 {"email": "default",
Kevin Chengc330f6f2019-05-13 09:32:42 -0700593 "scopes": expected_scope}
Tri Vo29ac1822016-10-01 17:06:29 -0700594 ],
595 "metadata": {
596 "items": [{"key": self.METADATA[0],
597 "value": self.METADATA[1]}],
598 },
cylanc2f98802019-08-15 17:47:30 +0800599 "labels":{constants.LABEL_CREATE_BY: "fake_user"},
Tri Vo29ac1822016-10-01 17:06:29 -0700600 }
601
602 self.compute_client.CreateInstance(
603 instance=self.INSTANCE,
604 image_name=self.IMAGE,
605 machine_type=self.MACHINE_TYPE,
606 metadata={self.METADATA[0]: self.METADATA[1]},
607 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000608 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700609 extra_disk_name=extra_disk_name,
610 extra_scopes=self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700611
612 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700613 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700614 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700615 mock.ANY,
616 operation_scope=gcompute_client.OperationScope.ZONE,
617 scope_name=self.ZONE)
618
Erwin Jansenf39798d2019-05-14 21:06:44 -0700619
620 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
621 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
622 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
623 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
624 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800625 @mock.patch("getpass.getuser", return_value="fake_user")
herbertxue1512f8a2019-06-27 13:56:23 +0800626 def testCreateInstanceWithTags(self,
cylanc2f98802019-08-15 17:47:30 +0800627 _get_user,
herbertxue1512f8a2019-06-27 13:56:23 +0800628 mock_wait,
629 mock_get_mach_type,
630 mock_get_subnetwork_url,
631 mock_get_network_url,
632 mock_get_image):
Erwin Jansenf39798d2019-05-14 21:06:44 -0700633 """Test CreateInstance."""
634 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
635 mock_get_network_url.return_value = self.NETWORK_URL
636 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
637 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
638 resource_mock = mock.MagicMock()
639 self.compute_client._service.instances = mock.MagicMock(
640 return_value=resource_mock)
641 resource_mock.insert = mock.MagicMock()
642 self.Patch(
643 self.compute_client,
644 "_GetExtraDiskArgs",
645 return_value=[{"fake_extra_arg": "fake_extra_value"}])
646 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
647 expected_disk_args = [self._disk_args]
648 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
649 expected_scope = []
650 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
651 expected_scope.extend(self.EXTRA_SCOPES)
652
653 expected_body = {
654 "machineType": self.MACHINE_TYPE_URL,
655 "name": self.INSTANCE,
656 "networkInterfaces": [
657 {
658 "network": self.NETWORK_URL,
659 "subnetwork": self.SUBNETWORK_URL,
660 "accessConfigs": [
661 {"name": "External NAT",
662 "type": "ONE_TO_ONE_NAT"}
663 ],
664 }
665 ],
666 'tags': {'items': ['https-server']},
667 "disks": expected_disk_args,
668 "serviceAccounts": [
669 {"email": "default",
670 "scopes": expected_scope}
671 ],
672 "metadata": {
673 "items": [{"key": self.METADATA[0],
674 "value": self.METADATA[1]}],
675 },
cylanc2f98802019-08-15 17:47:30 +0800676 "labels":{'created_by': "fake_user"},
Erwin Jansenf39798d2019-05-14 21:06:44 -0700677 }
678
679 self.compute_client.CreateInstance(
680 instance=self.INSTANCE,
681 image_name=self.IMAGE,
682 machine_type=self.MACHINE_TYPE,
683 metadata={self.METADATA[0]: self.METADATA[1]},
684 network=self.NETWORK,
685 zone=self.ZONE,
686 extra_disk_name=extra_disk_name,
687 tags=["https-server"],
688 extra_scopes=self.EXTRA_SCOPES)
689
690 resource_mock.insert.assert_called_with(
691 project=PROJECT, zone=self.ZONE, body=expected_body)
692 mock_wait.assert_called_with(
693 mock.ANY,
694 operation_scope=gcompute_client.OperationScope.ZONE,
695 scope_name=self.ZONE)
696
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700697 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
698 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
699 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700700 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700701 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
702 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800703 @mock.patch("getpass.getuser", return_value="fake_user")
704 def testCreateInstanceWithGpu(self, _get_user, mock_wait, mock_get_mach,
Kevin Cheng480e1212018-10-24 00:23:30 -0700705 mock_get_subnetwork, mock_get_network,
706 mock_get_image, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700707 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700708 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
709 mock_get_network.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700710 mock_get_subnetwork.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700711 mock_get_accel.return_value = self.ACCELERATOR_URL
712 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700713
714 resource_mock = mock.MagicMock()
715 self.compute_client._service.instances = mock.MagicMock(
716 return_value=resource_mock)
717 resource_mock.insert = mock.MagicMock()
718
719 expected_body = {
720 "machineType":
721 self.MACHINE_TYPE_URL,
722 "name":
723 self.INSTANCE,
724 "networkInterfaces": [{
Kevin Cheng480e1212018-10-24 00:23:30 -0700725 "network": self.NETWORK_URL,
726 "subnetwork": self.SUBNETWORK_URL,
Kevin Chengb5963882018-05-09 00:06:27 -0700727 "accessConfigs": [{
728 "name": "External NAT",
729 "type": "ONE_TO_ONE_NAT"
730 }],
731 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700732 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700733 "serviceAccounts": [{
734 "email": "default",
735 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
736 }],
737 "scheduling": {
738 "onHostMaintenance": "terminate"
739 },
740 "guestAccelerators": [{
741 "acceleratorCount": 1,
742 "acceleratorType": "http://speedy-gpu"
743 }],
744 "metadata": {
745 "items": [{
746 "key": self.METADATA[0],
747 "value": self.METADATA[1]
748 }],
749 },
cylanc2f98802019-08-15 17:47:30 +0800750 "labels":{'created_by': "fake_user"},
Kevin Chengb5963882018-05-09 00:06:27 -0700751 }
752
753 self.compute_client.CreateInstance(
754 instance=self.INSTANCE,
755 image_name=self.IMAGE,
756 machine_type=self.MACHINE_TYPE,
757 metadata={self.METADATA[0]: self.METADATA[1]},
758 network=self.NETWORK,
759 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700760 gpu=self.GPU,
761 extra_scopes=None)
Kevin Chengb5963882018-05-09 00:06:27 -0700762
763 resource_mock.insert.assert_called_with(
764 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700765 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700766 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
767 scope_name=self.ZONE)
768
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700769 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
770 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700771 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700772 resource_mock = mock.MagicMock()
773 self.compute_client._service.instances = mock.MagicMock(
774 return_value=resource_mock)
775 resource_mock.delete = mock.MagicMock()
776 self.compute_client.DeleteInstance(
777 instance=self.INSTANCE, zone=self.ZONE)
778 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700779 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700780 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700781 mock.ANY,
782 operation_scope=gcompute_client.OperationScope.ZONE,
783 scope_name=self.ZONE)
784
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700785 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
786 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700787 """Test DeleteInstances."""
788 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700789 fake_instances = ["fake_instance_1", "fake_instance_2"]
790 mock_api = mock.MagicMock()
791 resource_mock = mock.MagicMock()
792 self.compute_client._service.instances = mock.MagicMock(
793 return_value=resource_mock)
794 resource_mock.delete = mock.MagicMock(return_value=mock_api)
795 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
796 fake_instances, self.ZONE)
797 calls = [
798 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700799 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700800 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700801 zone=self.ZONE),
802 mock.call(
803 project=PROJECT,
804 instance="fake_instance_2",
805 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700806 ]
807 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700808 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700809 self.assertEqual(error_msgs, [])
810 self.assertEqual(failed, [])
811 self.assertEqual(set(deleted), set(fake_instances))
812
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700813 def testCreateDiskWithProject(self):
814 """Test CreateDisk with images using a set project."""
815 source_project = "fake-image-project"
816 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700817 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700818 resource_mock = mock.MagicMock()
819 self.compute_client._service.disks = mock.MagicMock(
820 return_value=resource_mock)
821 resource_mock.insert = mock.MagicMock()
822 self.compute_client.CreateDisk(
823 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
824 resource_mock.insert.assert_called_with(
825 project=PROJECT,
826 zone=self.ZONE,
827 sourceImage="projects/%s/global/images/fake_image" %
828 expected_project_to_use,
829 body={
830 "name":
831 "fake_disk",
832 "sizeGb":
833 10,
834 "type":
835 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
836 self.ZONE)
837 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700838 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700839
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700840 def testCreateDiskWithNoSourceProject(self):
841 """Test CreateDisk with images with no set project."""
842 source_project = None
843 expected_project_to_use = PROJECT
844 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
845 resource_mock = mock.MagicMock()
846 self.compute_client._service.disks = mock.MagicMock(
847 return_value=resource_mock)
848 resource_mock.insert = mock.MagicMock()
849 self.compute_client.CreateDisk(
850 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
851 resource_mock.insert.assert_called_with(
852 project=PROJECT,
853 zone=self.ZONE,
854 sourceImage="projects/%s/global/images/fake_image" %
855 expected_project_to_use,
856 body={
857 "name":
858 "fake_disk",
859 "sizeGb":
860 10,
861 "type":
862 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
863 self.ZONE)
864 })
865 self.assertTrue(mock_wait.called)
866
867 def testCreateDiskWithTypeStandard(self):
868 """Test CreateDisk with images using standard."""
869 disk_type = gcompute_client.PersistentDiskType.STANDARD
870 expected_disk_type_string = "pd-standard"
871 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
872 resource_mock = mock.MagicMock()
873 self.compute_client._service.disks = mock.MagicMock(
874 return_value=resource_mock)
875 resource_mock.insert = mock.MagicMock()
876 self.compute_client.CreateDisk(
877 "fake_disk",
878 "fake_image",
879 10,
880 self.ZONE,
881 source_project="fake-project",
882 disk_type=disk_type)
883 resource_mock.insert.assert_called_with(
884 project=PROJECT,
885 zone=self.ZONE,
886 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
887 body={
888 "name":
889 "fake_disk",
890 "sizeGb":
891 10,
892 "type":
893 "projects/%s/zones/%s/diskTypes/%s" %
894 (PROJECT, self.ZONE, expected_disk_type_string)
895 })
896 self.assertTrue(mock_wait.called)
897
898 def testCreateDiskWithTypeSSD(self):
899 """Test CreateDisk with images using standard."""
900 disk_type = gcompute_client.PersistentDiskType.SSD
901 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700902 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700903 resource_mock = mock.MagicMock()
904 self.compute_client._service.disks = mock.MagicMock(
905 return_value=resource_mock)
906 resource_mock.insert = mock.MagicMock()
907 self.compute_client.CreateDisk(
908 "fake_disk",
909 "fake_image",
910 10,
911 self.ZONE,
912 source_project="fake-project",
913 disk_type=disk_type)
914 resource_mock.insert.assert_called_with(
915 project=PROJECT,
916 zone=self.ZONE,
917 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
918 body={
919 "name":
920 "fake_disk",
921 "sizeGb":
922 10,
923 "type":
924 "projects/%s/zones/%s/diskTypes/%s" %
925 (PROJECT, self.ZONE, expected_disk_type_string)
926 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700927 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700928
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700929 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
930 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700931 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700932 resource_mock = mock.MagicMock()
933 self.compute_client._service.instances = mock.MagicMock(
934 return_value=resource_mock)
935 resource_mock.attachDisk = mock.MagicMock()
936 self.compute_client.AttachDisk(
937 "fake_instance_1", self.ZONE, deviceName="fake_disk",
938 source="fake-selfLink")
939 resource_mock.attachDisk.assert_called_with(
940 project=PROJECT,
941 zone=self.ZONE,
942 instance="fake_instance_1",
943 body={
944 "deviceName": "fake_disk",
945 "source": "fake-selfLink"
946 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700947 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700948
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700949 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
950 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700951 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700952 resource_mock = mock.MagicMock()
953 self.compute_client._service.instances = mock.MagicMock(
954 return_value=resource_mock)
955 resource_mock.detachDisk = mock.MagicMock()
956 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
957 resource_mock.detachDisk.assert_called_with(
958 project=PROJECT,
959 zone=self.ZONE,
960 instance="fake_instance_1",
961 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700962 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700963
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700964 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
965 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
966 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700967 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700968 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700969 resource_mock = mock.MagicMock()
970 self.compute_client._service.instances = mock.MagicMock(
971 return_value=resource_mock)
972 resource_mock.attachAccelerator = mock.MagicMock()
973 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
974 "nvidia-tesla-k80")
975 resource_mock.setMachineResources.assert_called_with(
976 project=PROJECT,
977 zone=self.ZONE,
978 instance="fake_instance_1",
979 body={
980 "guestAccelerators": [{
981 "acceleratorType": self.ACCELERATOR_URL,
982 "acceleratorCount": 1
983 }]
984 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700985 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700986
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700987 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
988 def testBatchExecuteOnInstances(self, mock_wait):
989 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700990 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700991 action = mock.MagicMock(return_value=mock.MagicMock())
992 fake_instances = ["fake_instance_1", "fake_instance_2"]
993 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
994 fake_instances, self.ZONE, action)
995 calls = [mock.call(instance="fake_instance_1"),
996 mock.call(instance="fake_instance_2")]
997 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700998 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700999 self.assertEqual(set(done), set(fake_instances))
1000 self.assertEqual(error_msgs, [])
1001 self.assertEqual(failed, [])
1002
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001003 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1004 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001005 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -07001006 resource_mock = mock.MagicMock()
1007 self.compute_client._service.instances = mock.MagicMock(
1008 return_value=resource_mock)
1009 resource_mock.reset = mock.MagicMock()
1010 self.compute_client.ResetInstance(
1011 instance=self.INSTANCE, zone=self.ZONE)
1012 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001013 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001014 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -07001015 mock.ANY,
1016 operation_scope=gcompute_client.OperationScope.ZONE,
1017 scope_name=self.ZONE)
1018
1019 def _CompareMachineSizeTestHelper(self,
1020 machine_info_1,
1021 machine_info_2,
1022 expected_result=None,
1023 expected_error_type=None):
1024 """Helper class for testing CompareMachineSize.
1025
Kevin Chengb5963882018-05-09 00:06:27 -07001026 Args:
1027 machine_info_1: A dictionary representing the first machine size.
1028 machine_info_2: A dictionary representing the second machine size.
1029 expected_result: An integer, 0, 1 or -1, or None if not set.
1030 expected_error_type: An exception type, if set will check for exception.
1031 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001032 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -07001033 gcompute_client.ComputeClient,
1034 "GetMachineType",
1035 side_effect=[machine_info_1, machine_info_2])
1036 if expected_error_type:
1037 self.assertRaises(expected_error_type,
1038 self.compute_client.CompareMachineSize, "name1",
1039 "name2", self.ZONE)
1040 else:
1041 result = self.compute_client.CompareMachineSize("name1", "name2",
1042 self.ZONE)
1043 self.assertEqual(result, expected_result)
1044
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001045 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -07001046 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
1047
1048 def testCompareMachineSizeSmall(self):
1049 """Test CompareMachineSize where the first one is smaller."""
1050 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
1051 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1052 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1053
Kevin Cheng4ae42772018-10-02 11:39:48 -07001054 def testCompareMachineSizeSmallSmallerOnSecond(self):
1055 """Test CompareMachineSize where the first one is smaller."""
1056 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
1057 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1058 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1059
Tri Vo29ac1822016-10-01 17:06:29 -07001060 def testCompareMachineSizeLarge(self):
1061 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -07001062 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
1063 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1064 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1065
1066 def testCompareMachineSizeLargeWithEqualElement(self):
1067 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -07001068 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
1069 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1070 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1071
1072 def testCompareMachineSizeEqual(self):
1073 """Test CompareMachineSize where two machine sizes are equal."""
1074 machine_info = {"guestCpus": 10, "memoryMb": 100}
1075 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
1076
1077 def testCompareMachineSizeBadMetric(self):
1078 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -07001079 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -07001080 self._CompareMachineSizeTestHelper(
1081 machine_info, machine_info, expected_error_type=errors.DriverError)
1082
1083 def testGetMachineType(self):
1084 """Test GetMachineType."""
1085 resource_mock = mock.MagicMock()
1086 mock_api = mock.MagicMock()
1087 self.compute_client._service.machineTypes = mock.MagicMock(
1088 return_value=resource_mock)
1089 resource_mock.get = mock.MagicMock(return_value=mock_api)
1090 mock_api.execute = mock.MagicMock(
1091 return_value={"name": self.MACHINE_TYPE})
1092 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
1093 self.ZONE)
1094 self.assertEqual(result, {"name": self.MACHINE_TYPE})
1095 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001096 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001097 zone=self.ZONE,
1098 machineType=self.MACHINE_TYPE)
1099
1100 def _GetSerialPortOutputTestHelper(self, response):
1101 """Helper function for testing GetSerialPortOutput.
1102
Kevin Chengb5963882018-05-09 00:06:27 -07001103 Args:
1104 response: A dictionary representing a fake response.
1105 """
Tri Vo29ac1822016-10-01 17:06:29 -07001106 resource_mock = mock.MagicMock()
1107 mock_api = mock.MagicMock()
1108 self.compute_client._service.instances = mock.MagicMock(
1109 return_value=resource_mock)
1110 resource_mock.getSerialPortOutput = mock.MagicMock(
1111 return_value=mock_api)
1112 mock_api.execute = mock.MagicMock(return_value=response)
1113
1114 if "contents" in response:
1115 result = self.compute_client.GetSerialPortOutput(
1116 instance=self.INSTANCE, zone=self.ZONE)
1117 self.assertEqual(result, "fake contents")
1118 else:
1119 self.assertRaisesRegexp(
1120 errors.DriverError,
1121 "Malformed response.*",
1122 self.compute_client.GetSerialPortOutput,
1123 instance=self.INSTANCE,
1124 zone=self.ZONE)
1125 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001126 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001127 zone=self.ZONE,
1128 instance=self.INSTANCE,
1129 port=1)
1130
1131 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001132 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -07001133 response = {"contents": "fake contents"}
1134 self._GetSerialPortOutputTestHelper(response)
1135
1136 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001137 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -07001138 response = {"malformed": "fake contents"}
1139 self._GetSerialPortOutputTestHelper(response)
1140
1141 def testGetInstanceNamesByIPs(self):
1142 """Test GetInstanceNamesByIPs."""
1143 good_instance = {
1144 "name": "instance_1",
1145 "networkInterfaces": [
1146 {
1147 "accessConfigs": [
1148 {"natIP": "172.22.22.22"},
1149 ],
1150 },
1151 ],
1152 }
1153 bad_instance = {"name": "instance_2"}
1154 self.Patch(
1155 gcompute_client.ComputeClient,
1156 "ListInstances",
1157 return_value=[good_instance, bad_instance])
1158 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
herbertxue7a501212019-08-29 15:37:13 +08001159 ips=["172.22.22.22", "172.22.22.23"])
Tri Vo29ac1822016-10-01 17:06:29 -07001160 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1161 "172.22.22.23": None})
1162
cylan64af2db2019-01-17 15:13:59 +08001163 def testRsaNotInMetadata(self):
1164 """Test rsa not in metadata."""
Tri Vo29ac1822016-10-01 17:06:29 -07001165 fake_user = "fake_user"
cylan64af2db2019-01-17 15:13:59 +08001166 fake_ssh_key = "fake_ssh"
1167 metadata = {
1168 "kind": "compute#metadata",
1169 "fingerprint": "a-23icsyx4E=",
1170 "items": [
1171 {
1172 "key": "sshKeys",
1173 "value": "%s:%s" % (fake_user, self.SSHKEY)
1174 }
1175 ]
1176 }
1177 # Test rsa doesn't exist in metadata.
1178 new_entry = "%s:%s" % (fake_user, fake_ssh_key)
1179 self.assertEqual(True, gcompute_client.RsaNotInMetadata(metadata, new_entry))
1180
1181 # Test rsa exists in metadata.
1182 exist_entry = "%s:%s" %(fake_user, self.SSHKEY)
1183 self.assertEqual(False, gcompute_client.RsaNotInMetadata(metadata, exist_entry))
1184
1185 def testGetSshKeyFromMetadata(self):
1186 """Test get ssh key from metadata."""
1187 fake_user = "fake_user"
1188 metadata_key_exist_value_is_empty = {
1189 "kind": "compute#metadata",
1190 "fingerprint": "a-23icsyx4E=",
1191 "items": [
1192 {
1193 "key": "sshKeys",
1194 "value": ""
1195 }
1196 ]
1197 }
1198 metadata_key_exist = {
1199 "kind": "compute#metadata",
1200 "fingerprint": "a-23icsyx4E=",
1201 "items": [
1202 {
1203 "key": "sshKeys",
1204 "value": "%s:%s" % (fake_user, self.SSHKEY)
1205 }
1206 ]
1207 }
1208 metadata_key_not_exist = {
1209 "kind": "compute#metadata",
1210 "fingerprint": "a-23icsyx4E=",
1211 "items": [
1212 {
1213 }
1214 ]
1215 }
1216 expected_key_exist_value_is_empty = {
1217 "key": "sshKeys",
1218 "value": ""
1219 }
1220 expected_key_exist = {
1221 "key": "sshKeys",
1222 "value": "%s:%s" % (fake_user, self.SSHKEY)
1223 }
1224 self.assertEqual(expected_key_exist_value_is_empty,
1225 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist_value_is_empty))
1226 self.assertEqual(expected_key_exist,
1227 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist))
1228 self.assertEqual(None,
1229 gcompute_client.GetSshKeyFromMetadata(metadata_key_not_exist))
1230
1231
1232 def testGetRsaKeyPathExistsFalse(self):
1233 """Test the rsa key path not exists."""
1234 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1235 self.Patch(os.path, "exists", return_value=False)
1236 self.assertRaisesRegexp(errors.DriverError,
1237 "RSA file %s does not exist." % fake_ssh_rsa_path,
1238 gcompute_client.GetRsaKey,
1239 ssh_rsa_path=fake_ssh_rsa_path)
1240
1241 def testGetRsaKey(self):
1242 """Test get the rsa key."""
1243 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1244 self.Patch(os.path, "exists", return_value=True)
1245 m = mock.mock_open(read_data=self.SSHKEY)
1246 with mock.patch("__builtin__.open", m):
1247 result = gcompute_client.GetRsaKey(fake_ssh_rsa_path)
1248 self.assertEqual(self.SSHKEY, result)
1249
1250 def testUpdateRsaInMetadata(self):
1251 """Test update rsa in metadata."""
1252 fake_ssh_key = "fake_ssh"
1253 fake_metadata_sshkeys_not_exist = {
1254 "kind": "compute#metadata",
1255 "fingerprint": "a-23icsyx4E=",
1256 "items": [
1257 {
1258 "key": "not_sshKeys",
1259 "value": ""
1260 }
1261 ]
1262 }
1263 new_entry = "new_user:%s" % fake_ssh_key
1264 expected = {
1265 "kind": "compute#metadata",
1266 "fingerprint": "a-23icsyx4E=",
1267 "items": [
1268 {
1269 "key": "not_sshKeys",
1270 "value": ""
1271 },
1272 {
1273 "key": "sshKeys",
1274 "value": new_entry
1275 }
1276 ]
1277 }
1278 self.Patch(os.path, "exists", return_value=True)
1279 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1280 resource_mock = mock.MagicMock()
1281 self.compute_client.SetInstanceMetadata = mock.MagicMock(
1282 return_value=resource_mock)
1283 # Test the key item not exists in the metadata.
1284 self.compute_client.UpdateRsaInMetadata(
1285 "fake_zone",
1286 "fake_instance",
1287 fake_metadata_sshkeys_not_exist,
1288 new_entry)
1289 self.compute_client.SetInstanceMetadata.assert_called_with(
1290 "fake_zone",
1291 "fake_instance",
1292 expected)
1293
1294 # Test the key item exists in the metadata.
1295 fake_metadata_ssh_keys_exists = {
1296 "kind": "compute#metadata",
1297 "fingerprint": "a-23icsyx4E=",
1298 "items": [
1299 {
1300 "key": "sshKeys",
1301 "value": "old_user:%s" % self.SSHKEY
1302 }
1303 ]
1304 }
1305 expected_ssh_keys_exists = {
1306 "kind": "compute#metadata",
1307 "fingerprint": "a-23icsyx4E=",
1308 "items": [
1309 {
1310 "key": "sshKeys",
1311 "value": "old_user:%s\n%s" % (self.SSHKEY, new_entry)
1312 }
1313 ]
1314 }
1315
1316 self.compute_client.UpdateRsaInMetadata(
1317 "fake_zone",
1318 "fake_instance",
1319 fake_metadata_ssh_keys_exists,
1320 new_entry)
1321 self.compute_client.SetInstanceMetadata.assert_called_with(
1322 "fake_zone",
1323 "fake_instance",
1324 expected_ssh_keys_exists)
1325
1326 def testAddSshRsaToInstance(self):
1327 """Test add ssh rsa key to instance."""
1328 fake_user = "fake_user"
1329 instance_metadata_key_not_exist = {
1330 "metadata": {
Tri Vo29ac1822016-10-01 17:06:29 -07001331 "kind": "compute#metadata",
1332 "fingerprint": "a-23icsyx4E=",
1333 "items": [
1334 {
1335 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001336 "value": ""
1337 }
1338 ]
1339 }
1340 }
1341 instance_metadata_key_exist = {
1342 "metadata": {
1343 "kind": "compute#metadata",
1344 "fingerprint": "a-23icsyx4E=",
1345 "items": [
1346 {
1347 "key": "sshKeys",
1348 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001349 }
1350 ]
1351 }
1352 }
1353 expected = {
1354 "kind": "compute#metadata",
1355 "fingerprint": "a-23icsyx4E=",
1356 "items": [
1357 {
1358 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001359 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001360 }
1361 ]
1362 }
1363
1364 self.Patch(os.path, "exists", return_value=True)
cylan64af2db2019-01-17 15:13:59 +08001365 m = mock.mock_open(read_data=self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001366 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
herbertxue7a501212019-08-29 15:37:13 +08001367 self.Patch(gcompute_client.ComputeClient, "GetZoneByInstance",
1368 return_value="fake_zone")
Tri Vo29ac1822016-10-01 17:06:29 -07001369 resource_mock = mock.MagicMock()
cylan64af2db2019-01-17 15:13:59 +08001370 self.compute_client._service.instances = mock.MagicMock(
Tri Vo29ac1822016-10-01 17:06:29 -07001371 return_value=resource_mock)
cylan64af2db2019-01-17 15:13:59 +08001372 resource_mock.setMetadata = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001373
cylan64af2db2019-01-17 15:13:59 +08001374 # Test the key not exists in the metadata.
Tri Vo29ac1822016-10-01 17:06:29 -07001375 self.Patch(
cylan64af2db2019-01-17 15:13:59 +08001376 gcompute_client.ComputeClient, "GetInstance",
1377 return_value=instance_metadata_key_not_exist)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001378 with mock.patch("__builtin__.open", m):
cylan64af2db2019-01-17 15:13:59 +08001379 self.compute_client.AddSshRsaInstanceMetadata(
cylan64af2db2019-01-17 15:13:59 +08001380 fake_user,
1381 "/path/to/test_rsa.pub",
1382 "fake_instance")
1383 resource_mock.setMetadata.assert_called_with(
1384 project=PROJECT,
1385 zone="fake_zone",
1386 instance="fake_instance",
1387 body=expected)
1388
1389 # Test the key already exists in the metadata.
1390 resource_mock.setMetadata.call_count = 0
1391 self.Patch(
1392 gcompute_client.ComputeClient, "GetInstance",
1393 return_value=instance_metadata_key_exist)
1394 with mock.patch("__builtin__.open", m):
1395 self.compute_client.AddSshRsaInstanceMetadata(
cylan64af2db2019-01-17 15:13:59 +08001396 fake_user,
1397 "/path/to/test_rsa.pub",
1398 "fake_instance")
1399 resource_mock.setMetadata.assert_not_called()
Tri Vo29ac1822016-10-01 17:06:29 -07001400
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001401 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1402 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001403 """Test DeleteDisks."""
1404 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001405 fake_disks = ["fake_disk_1", "fake_disk_2"]
1406 mock_api = mock.MagicMock()
1407 resource_mock = mock.MagicMock()
1408 self.compute_client._service.disks = mock.MagicMock(
1409 return_value=resource_mock)
1410 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1411 # Call the API.
1412 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1413 fake_disks, zone=self.ZONE)
1414 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001415 calls = [
1416 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1417 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1418 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001419 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001420 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001421 self.assertEqual(error_msgs, [])
1422 self.assertEqual(failed, [])
1423 self.assertEqual(set(deleted), set(fake_disks))
1424
Kevin Chengb5963882018-05-09 00:06:27 -07001425 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001426 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001427 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1428 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001429 """Raise 412 HTTP exception."""
1430 if not sentinel.hitFingerPrintConflict.called:
1431 sentinel.hitFingerPrintConflict()
1432 raise errors.HttpError(412, "resource labels have changed")
1433 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001434
1435 sentinel = mock.MagicMock()
1436 result = Raise412(sentinel)
1437 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1438 self.assertEqual("Passed", result)
1439
Tri Vo29ac1822016-10-01 17:06:29 -07001440
1441if __name__ == "__main__":
1442 unittest.main()