blob: 690588a3fdb626031ea40f7de43ffbe7bc59d8da [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,
Kevin Cheng05945e42019-11-15 16:15:13 -0800500 filter=None,
501 pageToken=None),
Tri Vo29ac1822016-10-01 17:06:29 -0700502 ]
herbertxue7a501212019-08-29 15:37:13 +0800503 resource_mock.aggregatedList.assert_has_calls(calls)
Tri Vo29ac1822016-10-01 17:06:29 -0700504 self.assertEqual(instances, [instance_1, instance_2])
505
herbertxue7a501212019-08-29 15:37:13 +0800506 def testGetZoneByInstance(self):
507 """Test GetZoneByInstance."""
508 instance_1 = "instance_1"
509 response = {"items": {'zones/fake_zone': {"instances": [instance_1]}}}
510 self.Patch(
511 gcompute_client.ComputeClient,
512 "Execute",
513 side_effect=[response])
514 expected_zone = "fake_zone"
515 self.assertEqual(self.compute_client.GetZoneByInstance(instance_1),
516 expected_zone)
517
518 # Test unable to find 'zone' from instance name.
519 response = {"items": {'zones/fake_zone': {"warning": "No instances."}}}
520 self.Patch(
521 gcompute_client.ComputeClient,
522 "Execute",
523 side_effect=[response])
524 with self.assertRaises(errors.GetGceZoneError):
525 self.compute_client.GetZoneByInstance(instance_1)
526
527 def testGetZonesByInstances(self):
528 """Test GetZonesByInstances."""
529 instances = ["instance_1", "instance_2"]
530 # Test instances in the same zone.
531 self.Patch(
532 gcompute_client.ComputeClient,
533 "GetZoneByInstance",
534 side_effect=["zone_1", "zone_1"])
535 expected_result = {"zone_1": ["instance_1", "instance_2"]}
536 self.assertEqual(self.compute_client.GetZonesByInstances(instances),
537 expected_result)
538
539 # Test instances in different zones.
540 self.Patch(
541 gcompute_client.ComputeClient,
542 "GetZoneByInstance",
543 side_effect=["zone_1", "zone_2"])
544 expected_result = {"zone_1": ["instance_1"],
545 "zone_2": ["instance_2"]}
546 self.assertEqual(self.compute_client.GetZonesByInstances(instances),
547 expected_result)
548
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700549 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
550 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700551 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700552 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
553 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800554 @mock.patch("getpass.getuser", return_value="fake_user")
555 def testCreateInstance(self, _get_user, mock_wait, mock_get_mach_type,
Kevin Cheng480e1212018-10-24 00:23:30 -0700556 mock_get_subnetwork_url, mock_get_network_url,
557 mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700558 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700559 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
560 mock_get_network_url.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700561 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700562 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700563 resource_mock = mock.MagicMock()
564 self.compute_client._service.instances = mock.MagicMock(
565 return_value=resource_mock)
566 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000567 self.Patch(
568 self.compute_client,
569 "_GetExtraDiskArgs",
570 return_value=[{"fake_extra_arg": "fake_extra_value"}])
571 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
572 expected_disk_args = [self._disk_args]
573 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Kevin Chengc330f6f2019-05-13 09:32:42 -0700574 expected_scope = []
575 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
576 expected_scope.extend(self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700577
578 expected_body = {
579 "machineType": self.MACHINE_TYPE_URL,
580 "name": self.INSTANCE,
581 "networkInterfaces": [
582 {
583 "network": self.NETWORK_URL,
Kevin Cheng480e1212018-10-24 00:23:30 -0700584 "subnetwork": self.SUBNETWORK_URL,
Tri Vo29ac1822016-10-01 17:06:29 -0700585 "accessConfigs": [
586 {"name": "External NAT",
587 "type": "ONE_TO_ONE_NAT"}
588 ],
589 }
590 ],
herbertxue308f7662018-05-18 03:25:58 +0000591 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700592 "serviceAccounts": [
593 {"email": "default",
Kevin Chengc330f6f2019-05-13 09:32:42 -0700594 "scopes": expected_scope}
Tri Vo29ac1822016-10-01 17:06:29 -0700595 ],
596 "metadata": {
597 "items": [{"key": self.METADATA[0],
598 "value": self.METADATA[1]}],
599 },
cylanc2f98802019-08-15 17:47:30 +0800600 "labels":{constants.LABEL_CREATE_BY: "fake_user"},
Tri Vo29ac1822016-10-01 17:06:29 -0700601 }
602
603 self.compute_client.CreateInstance(
604 instance=self.INSTANCE,
605 image_name=self.IMAGE,
606 machine_type=self.MACHINE_TYPE,
607 metadata={self.METADATA[0]: self.METADATA[1]},
608 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000609 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700610 extra_disk_name=extra_disk_name,
611 extra_scopes=self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700612
613 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700614 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700615 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700616 mock.ANY,
617 operation_scope=gcompute_client.OperationScope.ZONE,
618 scope_name=self.ZONE)
619
Erwin Jansenf39798d2019-05-14 21:06:44 -0700620
621 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
622 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
623 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
624 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
625 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800626 @mock.patch("getpass.getuser", return_value="fake_user")
herbertxue1512f8a2019-06-27 13:56:23 +0800627 def testCreateInstanceWithTags(self,
cylanc2f98802019-08-15 17:47:30 +0800628 _get_user,
herbertxue1512f8a2019-06-27 13:56:23 +0800629 mock_wait,
630 mock_get_mach_type,
631 mock_get_subnetwork_url,
632 mock_get_network_url,
633 mock_get_image):
Erwin Jansenf39798d2019-05-14 21:06:44 -0700634 """Test CreateInstance."""
635 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
636 mock_get_network_url.return_value = self.NETWORK_URL
637 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
638 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
639 resource_mock = mock.MagicMock()
640 self.compute_client._service.instances = mock.MagicMock(
641 return_value=resource_mock)
642 resource_mock.insert = mock.MagicMock()
643 self.Patch(
644 self.compute_client,
645 "_GetExtraDiskArgs",
646 return_value=[{"fake_extra_arg": "fake_extra_value"}])
647 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
648 expected_disk_args = [self._disk_args]
649 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
650 expected_scope = []
651 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
652 expected_scope.extend(self.EXTRA_SCOPES)
653
654 expected_body = {
655 "machineType": self.MACHINE_TYPE_URL,
656 "name": self.INSTANCE,
657 "networkInterfaces": [
658 {
659 "network": self.NETWORK_URL,
660 "subnetwork": self.SUBNETWORK_URL,
661 "accessConfigs": [
662 {"name": "External NAT",
663 "type": "ONE_TO_ONE_NAT"}
664 ],
665 }
666 ],
667 'tags': {'items': ['https-server']},
668 "disks": expected_disk_args,
669 "serviceAccounts": [
670 {"email": "default",
671 "scopes": expected_scope}
672 ],
673 "metadata": {
674 "items": [{"key": self.METADATA[0],
675 "value": self.METADATA[1]}],
676 },
cylanc2f98802019-08-15 17:47:30 +0800677 "labels":{'created_by': "fake_user"},
Erwin Jansenf39798d2019-05-14 21:06:44 -0700678 }
679
680 self.compute_client.CreateInstance(
681 instance=self.INSTANCE,
682 image_name=self.IMAGE,
683 machine_type=self.MACHINE_TYPE,
684 metadata={self.METADATA[0]: self.METADATA[1]},
685 network=self.NETWORK,
686 zone=self.ZONE,
687 extra_disk_name=extra_disk_name,
688 tags=["https-server"],
689 extra_scopes=self.EXTRA_SCOPES)
690
691 resource_mock.insert.assert_called_with(
692 project=PROJECT, zone=self.ZONE, body=expected_body)
693 mock_wait.assert_called_with(
694 mock.ANY,
695 operation_scope=gcompute_client.OperationScope.ZONE,
696 scope_name=self.ZONE)
697
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700698 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
699 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
700 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700701 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700702 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
703 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800704 @mock.patch("getpass.getuser", return_value="fake_user")
705 def testCreateInstanceWithGpu(self, _get_user, mock_wait, mock_get_mach,
Kevin Cheng480e1212018-10-24 00:23:30 -0700706 mock_get_subnetwork, mock_get_network,
707 mock_get_image, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700708 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700709 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
710 mock_get_network.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700711 mock_get_subnetwork.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700712 mock_get_accel.return_value = self.ACCELERATOR_URL
713 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700714
715 resource_mock = mock.MagicMock()
716 self.compute_client._service.instances = mock.MagicMock(
717 return_value=resource_mock)
718 resource_mock.insert = mock.MagicMock()
719
720 expected_body = {
721 "machineType":
722 self.MACHINE_TYPE_URL,
723 "name":
724 self.INSTANCE,
725 "networkInterfaces": [{
Kevin Cheng480e1212018-10-24 00:23:30 -0700726 "network": self.NETWORK_URL,
727 "subnetwork": self.SUBNETWORK_URL,
Kevin Chengb5963882018-05-09 00:06:27 -0700728 "accessConfigs": [{
729 "name": "External NAT",
730 "type": "ONE_TO_ONE_NAT"
731 }],
732 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700733 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700734 "serviceAccounts": [{
735 "email": "default",
736 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
737 }],
738 "scheduling": {
739 "onHostMaintenance": "terminate"
740 },
741 "guestAccelerators": [{
742 "acceleratorCount": 1,
743 "acceleratorType": "http://speedy-gpu"
744 }],
745 "metadata": {
746 "items": [{
747 "key": self.METADATA[0],
748 "value": self.METADATA[1]
749 }],
750 },
cylanc2f98802019-08-15 17:47:30 +0800751 "labels":{'created_by': "fake_user"},
Kevin Chengb5963882018-05-09 00:06:27 -0700752 }
753
754 self.compute_client.CreateInstance(
755 instance=self.INSTANCE,
756 image_name=self.IMAGE,
757 machine_type=self.MACHINE_TYPE,
758 metadata={self.METADATA[0]: self.METADATA[1]},
759 network=self.NETWORK,
760 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700761 gpu=self.GPU,
762 extra_scopes=None)
Kevin Chengb5963882018-05-09 00:06:27 -0700763
764 resource_mock.insert.assert_called_with(
765 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700766 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700767 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
768 scope_name=self.ZONE)
769
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700770 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
771 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700772 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700773 resource_mock = mock.MagicMock()
774 self.compute_client._service.instances = mock.MagicMock(
775 return_value=resource_mock)
776 resource_mock.delete = mock.MagicMock()
777 self.compute_client.DeleteInstance(
778 instance=self.INSTANCE, zone=self.ZONE)
779 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700780 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700781 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700782 mock.ANY,
783 operation_scope=gcompute_client.OperationScope.ZONE,
784 scope_name=self.ZONE)
785
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700786 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
787 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700788 """Test DeleteInstances."""
789 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700790 fake_instances = ["fake_instance_1", "fake_instance_2"]
791 mock_api = mock.MagicMock()
792 resource_mock = mock.MagicMock()
793 self.compute_client._service.instances = mock.MagicMock(
794 return_value=resource_mock)
795 resource_mock.delete = mock.MagicMock(return_value=mock_api)
796 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
797 fake_instances, self.ZONE)
798 calls = [
799 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700800 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700801 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700802 zone=self.ZONE),
803 mock.call(
804 project=PROJECT,
805 instance="fake_instance_2",
806 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700807 ]
808 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700809 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700810 self.assertEqual(error_msgs, [])
811 self.assertEqual(failed, [])
812 self.assertEqual(set(deleted), set(fake_instances))
813
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700814 def testCreateDiskWithProject(self):
815 """Test CreateDisk with images using a set project."""
816 source_project = "fake-image-project"
817 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700818 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700819 resource_mock = mock.MagicMock()
820 self.compute_client._service.disks = mock.MagicMock(
821 return_value=resource_mock)
822 resource_mock.insert = mock.MagicMock()
823 self.compute_client.CreateDisk(
824 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
825 resource_mock.insert.assert_called_with(
826 project=PROJECT,
827 zone=self.ZONE,
828 sourceImage="projects/%s/global/images/fake_image" %
829 expected_project_to_use,
830 body={
831 "name":
832 "fake_disk",
833 "sizeGb":
834 10,
835 "type":
836 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
837 self.ZONE)
838 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700839 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700840
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700841 def testCreateDiskWithNoSourceProject(self):
842 """Test CreateDisk with images with no set project."""
843 source_project = None
844 expected_project_to_use = PROJECT
845 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
846 resource_mock = mock.MagicMock()
847 self.compute_client._service.disks = mock.MagicMock(
848 return_value=resource_mock)
849 resource_mock.insert = mock.MagicMock()
850 self.compute_client.CreateDisk(
851 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
852 resource_mock.insert.assert_called_with(
853 project=PROJECT,
854 zone=self.ZONE,
855 sourceImage="projects/%s/global/images/fake_image" %
856 expected_project_to_use,
857 body={
858 "name":
859 "fake_disk",
860 "sizeGb":
861 10,
862 "type":
863 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
864 self.ZONE)
865 })
866 self.assertTrue(mock_wait.called)
867
868 def testCreateDiskWithTypeStandard(self):
869 """Test CreateDisk with images using standard."""
870 disk_type = gcompute_client.PersistentDiskType.STANDARD
871 expected_disk_type_string = "pd-standard"
872 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
873 resource_mock = mock.MagicMock()
874 self.compute_client._service.disks = mock.MagicMock(
875 return_value=resource_mock)
876 resource_mock.insert = mock.MagicMock()
877 self.compute_client.CreateDisk(
878 "fake_disk",
879 "fake_image",
880 10,
881 self.ZONE,
882 source_project="fake-project",
883 disk_type=disk_type)
884 resource_mock.insert.assert_called_with(
885 project=PROJECT,
886 zone=self.ZONE,
887 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
888 body={
889 "name":
890 "fake_disk",
891 "sizeGb":
892 10,
893 "type":
894 "projects/%s/zones/%s/diskTypes/%s" %
895 (PROJECT, self.ZONE, expected_disk_type_string)
896 })
897 self.assertTrue(mock_wait.called)
898
899 def testCreateDiskWithTypeSSD(self):
900 """Test CreateDisk with images using standard."""
901 disk_type = gcompute_client.PersistentDiskType.SSD
902 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700903 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700904 resource_mock = mock.MagicMock()
905 self.compute_client._service.disks = mock.MagicMock(
906 return_value=resource_mock)
907 resource_mock.insert = mock.MagicMock()
908 self.compute_client.CreateDisk(
909 "fake_disk",
910 "fake_image",
911 10,
912 self.ZONE,
913 source_project="fake-project",
914 disk_type=disk_type)
915 resource_mock.insert.assert_called_with(
916 project=PROJECT,
917 zone=self.ZONE,
918 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
919 body={
920 "name":
921 "fake_disk",
922 "sizeGb":
923 10,
924 "type":
925 "projects/%s/zones/%s/diskTypes/%s" %
926 (PROJECT, self.ZONE, expected_disk_type_string)
927 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700928 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700929
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700930 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
931 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700932 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700933 resource_mock = mock.MagicMock()
934 self.compute_client._service.instances = mock.MagicMock(
935 return_value=resource_mock)
936 resource_mock.attachDisk = mock.MagicMock()
937 self.compute_client.AttachDisk(
938 "fake_instance_1", self.ZONE, deviceName="fake_disk",
939 source="fake-selfLink")
940 resource_mock.attachDisk.assert_called_with(
941 project=PROJECT,
942 zone=self.ZONE,
943 instance="fake_instance_1",
944 body={
945 "deviceName": "fake_disk",
946 "source": "fake-selfLink"
947 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700948 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700949
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700950 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
951 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700952 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700953 resource_mock = mock.MagicMock()
954 self.compute_client._service.instances = mock.MagicMock(
955 return_value=resource_mock)
956 resource_mock.detachDisk = mock.MagicMock()
957 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
958 resource_mock.detachDisk.assert_called_with(
959 project=PROJECT,
960 zone=self.ZONE,
961 instance="fake_instance_1",
962 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700963 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700964
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700965 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
966 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
967 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700968 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700969 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700970 resource_mock = mock.MagicMock()
971 self.compute_client._service.instances = mock.MagicMock(
972 return_value=resource_mock)
973 resource_mock.attachAccelerator = mock.MagicMock()
974 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
975 "nvidia-tesla-k80")
976 resource_mock.setMachineResources.assert_called_with(
977 project=PROJECT,
978 zone=self.ZONE,
979 instance="fake_instance_1",
980 body={
981 "guestAccelerators": [{
982 "acceleratorType": self.ACCELERATOR_URL,
983 "acceleratorCount": 1
984 }]
985 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700986 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700987
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700988 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
989 def testBatchExecuteOnInstances(self, mock_wait):
990 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700991 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700992 action = mock.MagicMock(return_value=mock.MagicMock())
993 fake_instances = ["fake_instance_1", "fake_instance_2"]
994 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
995 fake_instances, self.ZONE, action)
996 calls = [mock.call(instance="fake_instance_1"),
997 mock.call(instance="fake_instance_2")]
998 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700999 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001000 self.assertEqual(set(done), set(fake_instances))
1001 self.assertEqual(error_msgs, [])
1002 self.assertEqual(failed, [])
1003
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001004 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1005 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001006 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -07001007 resource_mock = mock.MagicMock()
1008 self.compute_client._service.instances = mock.MagicMock(
1009 return_value=resource_mock)
1010 resource_mock.reset = mock.MagicMock()
1011 self.compute_client.ResetInstance(
1012 instance=self.INSTANCE, zone=self.ZONE)
1013 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001014 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001015 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -07001016 mock.ANY,
1017 operation_scope=gcompute_client.OperationScope.ZONE,
1018 scope_name=self.ZONE)
1019
1020 def _CompareMachineSizeTestHelper(self,
1021 machine_info_1,
1022 machine_info_2,
1023 expected_result=None,
1024 expected_error_type=None):
1025 """Helper class for testing CompareMachineSize.
1026
Kevin Chengb5963882018-05-09 00:06:27 -07001027 Args:
1028 machine_info_1: A dictionary representing the first machine size.
1029 machine_info_2: A dictionary representing the second machine size.
1030 expected_result: An integer, 0, 1 or -1, or None if not set.
1031 expected_error_type: An exception type, if set will check for exception.
1032 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001033 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -07001034 gcompute_client.ComputeClient,
1035 "GetMachineType",
1036 side_effect=[machine_info_1, machine_info_2])
1037 if expected_error_type:
1038 self.assertRaises(expected_error_type,
1039 self.compute_client.CompareMachineSize, "name1",
1040 "name2", self.ZONE)
1041 else:
1042 result = self.compute_client.CompareMachineSize("name1", "name2",
1043 self.ZONE)
1044 self.assertEqual(result, expected_result)
1045
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001046 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -07001047 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
1048
1049 def testCompareMachineSizeSmall(self):
1050 """Test CompareMachineSize where the first one is smaller."""
1051 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
1052 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1053 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1054
Kevin Cheng4ae42772018-10-02 11:39:48 -07001055 def testCompareMachineSizeSmallSmallerOnSecond(self):
1056 """Test CompareMachineSize where the first one is smaller."""
1057 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
1058 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1059 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1060
Tri Vo29ac1822016-10-01 17:06:29 -07001061 def testCompareMachineSizeLarge(self):
1062 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -07001063 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
1064 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1065 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1066
1067 def testCompareMachineSizeLargeWithEqualElement(self):
1068 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -07001069 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
1070 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1071 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1072
1073 def testCompareMachineSizeEqual(self):
1074 """Test CompareMachineSize where two machine sizes are equal."""
1075 machine_info = {"guestCpus": 10, "memoryMb": 100}
1076 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
1077
1078 def testCompareMachineSizeBadMetric(self):
1079 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -07001080 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -07001081 self._CompareMachineSizeTestHelper(
1082 machine_info, machine_info, expected_error_type=errors.DriverError)
1083
1084 def testGetMachineType(self):
1085 """Test GetMachineType."""
1086 resource_mock = mock.MagicMock()
1087 mock_api = mock.MagicMock()
1088 self.compute_client._service.machineTypes = mock.MagicMock(
1089 return_value=resource_mock)
1090 resource_mock.get = mock.MagicMock(return_value=mock_api)
1091 mock_api.execute = mock.MagicMock(
1092 return_value={"name": self.MACHINE_TYPE})
1093 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
1094 self.ZONE)
1095 self.assertEqual(result, {"name": self.MACHINE_TYPE})
1096 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001097 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001098 zone=self.ZONE,
1099 machineType=self.MACHINE_TYPE)
1100
1101 def _GetSerialPortOutputTestHelper(self, response):
1102 """Helper function for testing GetSerialPortOutput.
1103
Kevin Chengb5963882018-05-09 00:06:27 -07001104 Args:
1105 response: A dictionary representing a fake response.
1106 """
Tri Vo29ac1822016-10-01 17:06:29 -07001107 resource_mock = mock.MagicMock()
1108 mock_api = mock.MagicMock()
1109 self.compute_client._service.instances = mock.MagicMock(
1110 return_value=resource_mock)
1111 resource_mock.getSerialPortOutput = mock.MagicMock(
1112 return_value=mock_api)
1113 mock_api.execute = mock.MagicMock(return_value=response)
1114
1115 if "contents" in response:
1116 result = self.compute_client.GetSerialPortOutput(
1117 instance=self.INSTANCE, zone=self.ZONE)
1118 self.assertEqual(result, "fake contents")
1119 else:
1120 self.assertRaisesRegexp(
1121 errors.DriverError,
1122 "Malformed response.*",
1123 self.compute_client.GetSerialPortOutput,
1124 instance=self.INSTANCE,
1125 zone=self.ZONE)
1126 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001127 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001128 zone=self.ZONE,
1129 instance=self.INSTANCE,
1130 port=1)
1131
1132 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001133 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -07001134 response = {"contents": "fake contents"}
1135 self._GetSerialPortOutputTestHelper(response)
1136
1137 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001138 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -07001139 response = {"malformed": "fake contents"}
1140 self._GetSerialPortOutputTestHelper(response)
1141
1142 def testGetInstanceNamesByIPs(self):
1143 """Test GetInstanceNamesByIPs."""
1144 good_instance = {
1145 "name": "instance_1",
1146 "networkInterfaces": [
1147 {
1148 "accessConfigs": [
1149 {"natIP": "172.22.22.22"},
1150 ],
1151 },
1152 ],
1153 }
1154 bad_instance = {"name": "instance_2"}
1155 self.Patch(
1156 gcompute_client.ComputeClient,
1157 "ListInstances",
1158 return_value=[good_instance, bad_instance])
1159 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
herbertxue7a501212019-08-29 15:37:13 +08001160 ips=["172.22.22.22", "172.22.22.23"])
Tri Vo29ac1822016-10-01 17:06:29 -07001161 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1162 "172.22.22.23": None})
1163
cylan64af2db2019-01-17 15:13:59 +08001164 def testRsaNotInMetadata(self):
1165 """Test rsa not in metadata."""
Tri Vo29ac1822016-10-01 17:06:29 -07001166 fake_user = "fake_user"
cylan64af2db2019-01-17 15:13:59 +08001167 fake_ssh_key = "fake_ssh"
1168 metadata = {
1169 "kind": "compute#metadata",
1170 "fingerprint": "a-23icsyx4E=",
1171 "items": [
1172 {
1173 "key": "sshKeys",
1174 "value": "%s:%s" % (fake_user, self.SSHKEY)
1175 }
1176 ]
1177 }
1178 # Test rsa doesn't exist in metadata.
1179 new_entry = "%s:%s" % (fake_user, fake_ssh_key)
1180 self.assertEqual(True, gcompute_client.RsaNotInMetadata(metadata, new_entry))
1181
1182 # Test rsa exists in metadata.
1183 exist_entry = "%s:%s" %(fake_user, self.SSHKEY)
1184 self.assertEqual(False, gcompute_client.RsaNotInMetadata(metadata, exist_entry))
1185
1186 def testGetSshKeyFromMetadata(self):
1187 """Test get ssh key from metadata."""
1188 fake_user = "fake_user"
1189 metadata_key_exist_value_is_empty = {
1190 "kind": "compute#metadata",
1191 "fingerprint": "a-23icsyx4E=",
1192 "items": [
1193 {
1194 "key": "sshKeys",
1195 "value": ""
1196 }
1197 ]
1198 }
1199 metadata_key_exist = {
1200 "kind": "compute#metadata",
1201 "fingerprint": "a-23icsyx4E=",
1202 "items": [
1203 {
1204 "key": "sshKeys",
1205 "value": "%s:%s" % (fake_user, self.SSHKEY)
1206 }
1207 ]
1208 }
1209 metadata_key_not_exist = {
1210 "kind": "compute#metadata",
1211 "fingerprint": "a-23icsyx4E=",
1212 "items": [
1213 {
1214 }
1215 ]
1216 }
1217 expected_key_exist_value_is_empty = {
1218 "key": "sshKeys",
1219 "value": ""
1220 }
1221 expected_key_exist = {
1222 "key": "sshKeys",
1223 "value": "%s:%s" % (fake_user, self.SSHKEY)
1224 }
1225 self.assertEqual(expected_key_exist_value_is_empty,
1226 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist_value_is_empty))
1227 self.assertEqual(expected_key_exist,
1228 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist))
1229 self.assertEqual(None,
1230 gcompute_client.GetSshKeyFromMetadata(metadata_key_not_exist))
1231
1232
1233 def testGetRsaKeyPathExistsFalse(self):
1234 """Test the rsa key path not exists."""
1235 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1236 self.Patch(os.path, "exists", return_value=False)
1237 self.assertRaisesRegexp(errors.DriverError,
1238 "RSA file %s does not exist." % fake_ssh_rsa_path,
1239 gcompute_client.GetRsaKey,
1240 ssh_rsa_path=fake_ssh_rsa_path)
1241
1242 def testGetRsaKey(self):
1243 """Test get the rsa key."""
1244 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1245 self.Patch(os.path, "exists", return_value=True)
1246 m = mock.mock_open(read_data=self.SSHKEY)
1247 with mock.patch("__builtin__.open", m):
1248 result = gcompute_client.GetRsaKey(fake_ssh_rsa_path)
1249 self.assertEqual(self.SSHKEY, result)
1250
1251 def testUpdateRsaInMetadata(self):
1252 """Test update rsa in metadata."""
1253 fake_ssh_key = "fake_ssh"
1254 fake_metadata_sshkeys_not_exist = {
1255 "kind": "compute#metadata",
1256 "fingerprint": "a-23icsyx4E=",
1257 "items": [
1258 {
1259 "key": "not_sshKeys",
1260 "value": ""
1261 }
1262 ]
1263 }
1264 new_entry = "new_user:%s" % fake_ssh_key
1265 expected = {
1266 "kind": "compute#metadata",
1267 "fingerprint": "a-23icsyx4E=",
1268 "items": [
1269 {
1270 "key": "not_sshKeys",
1271 "value": ""
1272 },
1273 {
1274 "key": "sshKeys",
1275 "value": new_entry
1276 }
1277 ]
1278 }
1279 self.Patch(os.path, "exists", return_value=True)
1280 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1281 resource_mock = mock.MagicMock()
1282 self.compute_client.SetInstanceMetadata = mock.MagicMock(
1283 return_value=resource_mock)
1284 # Test the key item not exists in the metadata.
1285 self.compute_client.UpdateRsaInMetadata(
1286 "fake_zone",
1287 "fake_instance",
1288 fake_metadata_sshkeys_not_exist,
1289 new_entry)
1290 self.compute_client.SetInstanceMetadata.assert_called_with(
1291 "fake_zone",
1292 "fake_instance",
1293 expected)
1294
1295 # Test the key item exists in the metadata.
1296 fake_metadata_ssh_keys_exists = {
1297 "kind": "compute#metadata",
1298 "fingerprint": "a-23icsyx4E=",
1299 "items": [
1300 {
1301 "key": "sshKeys",
1302 "value": "old_user:%s" % self.SSHKEY
1303 }
1304 ]
1305 }
1306 expected_ssh_keys_exists = {
1307 "kind": "compute#metadata",
1308 "fingerprint": "a-23icsyx4E=",
1309 "items": [
1310 {
1311 "key": "sshKeys",
1312 "value": "old_user:%s\n%s" % (self.SSHKEY, new_entry)
1313 }
1314 ]
1315 }
1316
1317 self.compute_client.UpdateRsaInMetadata(
1318 "fake_zone",
1319 "fake_instance",
1320 fake_metadata_ssh_keys_exists,
1321 new_entry)
1322 self.compute_client.SetInstanceMetadata.assert_called_with(
1323 "fake_zone",
1324 "fake_instance",
1325 expected_ssh_keys_exists)
1326
1327 def testAddSshRsaToInstance(self):
1328 """Test add ssh rsa key to instance."""
1329 fake_user = "fake_user"
1330 instance_metadata_key_not_exist = {
1331 "metadata": {
Tri Vo29ac1822016-10-01 17:06:29 -07001332 "kind": "compute#metadata",
1333 "fingerprint": "a-23icsyx4E=",
1334 "items": [
1335 {
1336 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001337 "value": ""
1338 }
1339 ]
1340 }
1341 }
1342 instance_metadata_key_exist = {
1343 "metadata": {
1344 "kind": "compute#metadata",
1345 "fingerprint": "a-23icsyx4E=",
1346 "items": [
1347 {
1348 "key": "sshKeys",
1349 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001350 }
1351 ]
1352 }
1353 }
1354 expected = {
1355 "kind": "compute#metadata",
1356 "fingerprint": "a-23icsyx4E=",
1357 "items": [
1358 {
1359 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001360 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001361 }
1362 ]
1363 }
1364
1365 self.Patch(os.path, "exists", return_value=True)
cylan64af2db2019-01-17 15:13:59 +08001366 m = mock.mock_open(read_data=self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001367 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
herbertxue7a501212019-08-29 15:37:13 +08001368 self.Patch(gcompute_client.ComputeClient, "GetZoneByInstance",
1369 return_value="fake_zone")
Tri Vo29ac1822016-10-01 17:06:29 -07001370 resource_mock = mock.MagicMock()
cylan64af2db2019-01-17 15:13:59 +08001371 self.compute_client._service.instances = mock.MagicMock(
Tri Vo29ac1822016-10-01 17:06:29 -07001372 return_value=resource_mock)
cylan64af2db2019-01-17 15:13:59 +08001373 resource_mock.setMetadata = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001374
cylan64af2db2019-01-17 15:13:59 +08001375 # Test the key not exists in the metadata.
Tri Vo29ac1822016-10-01 17:06:29 -07001376 self.Patch(
cylan64af2db2019-01-17 15:13:59 +08001377 gcompute_client.ComputeClient, "GetInstance",
1378 return_value=instance_metadata_key_not_exist)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001379 with mock.patch("__builtin__.open", m):
cylan64af2db2019-01-17 15:13:59 +08001380 self.compute_client.AddSshRsaInstanceMetadata(
cylan64af2db2019-01-17 15:13:59 +08001381 fake_user,
1382 "/path/to/test_rsa.pub",
1383 "fake_instance")
1384 resource_mock.setMetadata.assert_called_with(
1385 project=PROJECT,
1386 zone="fake_zone",
1387 instance="fake_instance",
1388 body=expected)
1389
1390 # Test the key already exists in the metadata.
1391 resource_mock.setMetadata.call_count = 0
1392 self.Patch(
1393 gcompute_client.ComputeClient, "GetInstance",
1394 return_value=instance_metadata_key_exist)
1395 with mock.patch("__builtin__.open", m):
1396 self.compute_client.AddSshRsaInstanceMetadata(
cylan64af2db2019-01-17 15:13:59 +08001397 fake_user,
1398 "/path/to/test_rsa.pub",
1399 "fake_instance")
1400 resource_mock.setMetadata.assert_not_called()
Tri Vo29ac1822016-10-01 17:06:29 -07001401
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001402 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1403 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001404 """Test DeleteDisks."""
1405 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001406 fake_disks = ["fake_disk_1", "fake_disk_2"]
1407 mock_api = mock.MagicMock()
1408 resource_mock = mock.MagicMock()
1409 self.compute_client._service.disks = mock.MagicMock(
1410 return_value=resource_mock)
1411 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1412 # Call the API.
1413 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1414 fake_disks, zone=self.ZONE)
1415 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001416 calls = [
1417 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1418 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1419 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001420 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001421 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001422 self.assertEqual(error_msgs, [])
1423 self.assertEqual(failed, [])
1424 self.assertEqual(set(deleted), set(fake_disks))
1425
Kevin Chengb5963882018-05-09 00:06:27 -07001426 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001427 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001428 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1429 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001430 """Raise 412 HTTP exception."""
1431 if not sentinel.hitFingerPrintConflict.called:
1432 sentinel.hitFingerPrintConflict()
1433 raise errors.HttpError(412, "resource labels have changed")
1434 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001435
1436 sentinel = mock.MagicMock()
1437 result = Raise412(sentinel)
1438 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1439 self.assertEqual("Passed", result)
1440
Tri Vo29ac1822016-10-01 17:06:29 -07001441
1442if __name__ == "__main__":
1443 unittest.main()