blob: 4571f110f987895c0488f8350ec86ef11ab2c97a [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
herbertxuece12e232019-10-23 17:40:49 +080023import six
Tri Vo29ac1822016-10-01 17:06:29 -070024import mock
Kevin Cheng5c124ec2018-05-16 13:28:51 -070025
26# pylint: disable=import-error
Kevin Chengda4f07a2018-06-26 10:25:05 -070027import apiclient.http
Tri Vo29ac1822016-10-01 17:06:29 -070028
Sam Chiu7de3b232018-12-06 19:45:52 +080029from acloud import errors
cylanc2f98802019-08-15 17:47:30 +080030from acloud.internal import constants
Tri Vo29ac1822016-10-01 17:06:29 -070031from acloud.internal.lib import driver_test_lib
32from acloud.internal.lib import gcompute_client
33from acloud.internal.lib import utils
Tri Vo29ac1822016-10-01 17:06:29 -070034
herbertxue1512f8a2019-06-27 13:56:23 +080035
Kevin Chengb5963882018-05-09 00:06:27 -070036GS_IMAGE_SOURCE_URI = "https://storage.googleapis.com/fake-bucket/fake.tar.gz"
37GS_IMAGE_SOURCE_DISK = (
38 "https://www.googleapis.com/compute/v1/projects/fake-project/zones/"
39 "us-east1-d/disks/fake-disk")
40PROJECT = "fake-project"
Tri Vo29ac1822016-10-01 17:06:29 -070041
herbertxue1512f8a2019-06-27 13:56:23 +080042
Kevin Cheng5c124ec2018-05-16 13:28:51 -070043# pylint: disable=protected-access, too-many-public-methods
Kevin Cheng070ae5c2018-08-02 16:03:00 -070044class ComputeClientTest(driver_test_lib.BaseDriverTest):
Tri Vo29ac1822016-10-01 17:06:29 -070045 """Test ComputeClient."""
46
Kevin Chengb5963882018-05-09 00:06:27 -070047 PROJECT_OTHER = "fake-project-other"
Tri Vo29ac1822016-10-01 17:06:29 -070048 INSTANCE = "fake-instance"
49 IMAGE = "fake-image"
50 IMAGE_URL = "http://fake-image-url"
Kevin Chengb5963882018-05-09 00:06:27 -070051 IMAGE_OTHER = "fake-image-other"
Tri Vo29ac1822016-10-01 17:06:29 -070052 MACHINE_TYPE = "fake-machine-type"
53 MACHINE_TYPE_URL = "http://fake-machine-type-url"
54 METADATA = ("metadata_key", "metadata_value")
Kevin Chengb5963882018-05-09 00:06:27 -070055 ACCELERATOR_URL = "http://speedy-gpu"
Tri Vo29ac1822016-10-01 17:06:29 -070056 NETWORK = "fake-network"
57 NETWORK_URL = "http://fake-network-url"
Kevin Cheng480e1212018-10-24 00:23:30 -070058 SUBNETWORK_URL = "http://fake-subnetwork-url"
Tri Vo29ac1822016-10-01 17:06:29 -070059 ZONE = "fake-zone"
60 REGION = "fake-region"
61 OPERATION_NAME = "fake-op"
Kevin Chengb5963882018-05-09 00:06:27 -070062 IMAGE_FINGERPRINT = "L_NWHuz7wTY="
63 GPU = "fancy-graphics"
cylan64af2db2019-01-17 15:13:59 +080064 SSHKEY = (
65 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
66 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
67 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
68 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
69 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
70 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
71 "ApiihqNL1111 test@test1.org")
Kevin Chengc330f6f2019-05-13 09:32:42 -070072 EXTRA_SCOPES = ["scope1"]
Tri Vo29ac1822016-10-01 17:06:29 -070073
74 def setUp(self):
75 """Set up test."""
76 super(ComputeClientTest, self).setUp()
77 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
78 fake_cfg = mock.MagicMock()
Kevin Chengb5963882018-05-09 00:06:27 -070079 fake_cfg.project = PROJECT
Kevin Chengc330f6f2019-05-13 09:32:42 -070080 fake_cfg.extra_scopes = self.EXTRA_SCOPES
Kevin Chengb5963882018-05-09 00:06:27 -070081 self.compute_client = gcompute_client.ComputeClient(
82 fake_cfg, mock.MagicMock())
Tri Vo29ac1822016-10-01 17:06:29 -070083 self.compute_client._service = mock.MagicMock()
84
Kevin Cheng5c124ec2018-05-16 13:28:51 -070085 self._disk_args = copy.deepcopy(gcompute_client.BASE_DISK_ARGS)
86 self._disk_args["initializeParams"] = {"diskName": self.INSTANCE,
87 "sourceImage": self.IMAGE_URL}
88
89 # pylint: disable=invalid-name
Tri Vo29ac1822016-10-01 17:06:29 -070090 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
91 """A helper class for setting up mocks for testGetOperationStatus*.
92
Kevin Chengb5963882018-05-09 00:06:27 -070093 Args:
94 mock_result: The result to return by _GetOperationStatus.
95 operation_scope: A value of OperationScope.
Tri Vo29ac1822016-10-01 17:06:29 -070096
Kevin Chengb5963882018-05-09 00:06:27 -070097 Returns:
98 A mock for Resource object.
99 """
Tri Vo29ac1822016-10-01 17:06:29 -0700100 resource_mock = mock.MagicMock()
101 mock_api = mock.MagicMock()
102 if operation_scope == gcompute_client.OperationScope.GLOBAL:
103 self.compute_client._service.globalOperations = mock.MagicMock(
104 return_value=resource_mock)
105 elif operation_scope == gcompute_client.OperationScope.ZONE:
106 self.compute_client._service.zoneOperations = mock.MagicMock(
107 return_value=resource_mock)
108 elif operation_scope == gcompute_client.OperationScope.REGION:
109 self.compute_client._service.regionOperations = mock.MagicMock(
110 return_value=resource_mock)
111 resource_mock.get = mock.MagicMock(return_value=mock_api)
112 mock_api.execute = mock.MagicMock(return_value=mock_result)
113 return resource_mock
114
115 def testGetOperationStatusGlobal(self):
116 """Test _GetOperationStatus for global."""
117 resource_mock = self._SetupMocksForGetOperationStatus(
118 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
119 status = self.compute_client._GetOperationStatus(
120 {"name": self.OPERATION_NAME},
121 gcompute_client.OperationScope.GLOBAL)
122 self.assertEqual(status, "GOOD")
123 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700124 project=PROJECT, operation=self.OPERATION_NAME)
Tri Vo29ac1822016-10-01 17:06:29 -0700125
126 def testGetOperationStatusZone(self):
127 """Test _GetOperationStatus for zone."""
128 resource_mock = self._SetupMocksForGetOperationStatus(
129 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
130 status = self.compute_client._GetOperationStatus(
131 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
132 self.ZONE)
133 self.assertEqual(status, "GOOD")
134 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700135 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700136 operation=self.OPERATION_NAME,
137 zone=self.ZONE)
138
139 def testGetOperationStatusRegion(self):
140 """Test _GetOperationStatus for region."""
141 resource_mock = self._SetupMocksForGetOperationStatus(
142 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
143 self.compute_client._GetOperationStatus(
144 {"name": self.OPERATION_NAME},
145 gcompute_client.OperationScope.REGION, self.REGION)
146 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700147 project=PROJECT, operation=self.OPERATION_NAME, region=self.REGION)
Tri Vo29ac1822016-10-01 17:06:29 -0700148
149 def testGetOperationStatusError(self):
150 """Test _GetOperationStatus failed."""
151 self._SetupMocksForGetOperationStatus(
152 {"error": {"errors": ["error1", "error2"]}},
153 gcompute_client.OperationScope.GLOBAL)
herbertxuece12e232019-10-23 17:40:49 +0800154 six.assertRaisesRegex(self,
155 errors.DriverError,
156 "Get operation state failed.*error1.*error2",
157 self.compute_client._GetOperationStatus,
158 {"name": self.OPERATION_NAME},
159 gcompute_client.OperationScope.GLOBAL)
Tri Vo29ac1822016-10-01 17:06:29 -0700160
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700161 @mock.patch.object(errors, "GceOperationTimeoutError")
162 @mock.patch.object(utils, "PollAndWait")
163 def testWaitOnOperation(self, mock_poll, mock_gce_operation_timeout_error):
Tri Vo29ac1822016-10-01 17:06:29 -0700164 """Test WaitOnOperation."""
165 mock_error = mock.MagicMock()
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700166 mock_gce_operation_timeout_error.return_value = mock_error
Tri Vo29ac1822016-10-01 17:06:29 -0700167 self.compute_client.WaitOnOperation(
168 operation={"name": self.OPERATION_NAME},
169 operation_scope=gcompute_client.OperationScope.REGION,
170 scope_name=self.REGION)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700171 mock_poll.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700172 func=self.compute_client._GetOperationStatus,
173 expected_return="DONE",
174 timeout_exception=mock_error,
175 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
Kevin Chengb5963882018-05-09 00:06:27 -0700176 sleep_interval_secs=self.compute_client.OPERATION_POLL_INTERVAL_SECS,
Tri Vo29ac1822016-10-01 17:06:29 -0700177 operation={"name": self.OPERATION_NAME},
178 operation_scope=gcompute_client.OperationScope.REGION,
179 scope_name=self.REGION)
180
Kevin Chengb5963882018-05-09 00:06:27 -0700181 def testGetImage(self):
182 """Test GetImage."""
183 resource_mock = mock.MagicMock()
184 mock_api = mock.MagicMock()
185 self.compute_client._service.images = mock.MagicMock(
186 return_value=resource_mock)
187 resource_mock.get = mock.MagicMock(return_value=mock_api)
188 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
189 result = self.compute_client.GetImage(self.IMAGE)
190 self.assertEqual(result, {"name": self.IMAGE})
191 resource_mock.get.assert_called_with(project=PROJECT, image=self.IMAGE)
192
193 def testGetImageOther(self):
194 """Test GetImage with other project."""
195 resource_mock = mock.MagicMock()
196 mock_api = mock.MagicMock()
197 self.compute_client._service.images = mock.MagicMock(
198 return_value=resource_mock)
199 resource_mock.get = mock.MagicMock(return_value=mock_api)
200 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE_OTHER})
201 result = self.compute_client.GetImage(
202 image_name=self.IMAGE_OTHER,
203 image_project=self.PROJECT_OTHER)
204 self.assertEqual(result, {"name": self.IMAGE_OTHER})
205 resource_mock.get.assert_called_with(
206 project=self.PROJECT_OTHER, image=self.IMAGE_OTHER)
207
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700208 def testCreateImageWithSourceURI(self):
209 """Test CreateImage with src uri."""
210 source_uri = GS_IMAGE_SOURCE_URI
211 source_disk = None
212 labels = None
213 expected_body = {"name": self.IMAGE,
214 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}
215 mock_check = self.Patch(gcompute_client.ComputeClient,
216 "CheckImageExists",
217 return_value=False)
218 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
219 resource_mock = mock.MagicMock()
220 self.compute_client._service.images = mock.MagicMock(
221 return_value=resource_mock)
222 resource_mock.insert = mock.MagicMock()
223 self.compute_client.CreateImage(
224 image_name=self.IMAGE, source_uri=source_uri,
225 source_disk=source_disk, labels=labels)
226 resource_mock.insert.assert_called_with(
227 project=PROJECT, body=expected_body)
228 mock_wait.assert_called_with(
229 operation=mock.ANY,
230 operation_scope=gcompute_client.OperationScope.GLOBAL)
231 mock_check.assert_called_with(self.IMAGE)
232
233 def testCreateImageWithSourceDisk(self):
234 """Test CreateImage with src disk."""
235 source_uri = None
236 source_disk = GS_IMAGE_SOURCE_DISK
237 labels = None
238 expected_body = {"name": self.IMAGE,
239 "sourceDisk": GS_IMAGE_SOURCE_DISK}
240 mock_check = self.Patch(gcompute_client.ComputeClient,
241 "CheckImageExists",
242 return_value=False)
243 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
244 resource_mock = mock.MagicMock()
245 self.compute_client._service.images = mock.MagicMock(
246 return_value=resource_mock)
247 resource_mock.insert = mock.MagicMock()
248 self.compute_client.CreateImage(
249 image_name=self.IMAGE, source_uri=source_uri,
250 source_disk=source_disk, labels=labels)
251 resource_mock.insert.assert_called_with(
252 project=PROJECT, body=expected_body)
253 mock_wait.assert_called_with(
254 operation=mock.ANY,
255 operation_scope=gcompute_client.OperationScope.GLOBAL)
256 mock_check.assert_called_with(self.IMAGE)
257
258 def testCreateImageWithSourceDiskAndLabel(self):
259 """Test CreateImage with src disk and label."""
260 source_uri = None
261 source_disk = GS_IMAGE_SOURCE_DISK
262 labels = {"label1": "xxx"}
263 expected_body = {"name": self.IMAGE,
264 "sourceDisk": GS_IMAGE_SOURCE_DISK,
265 "labels": {"label1": "xxx"}}
herbertxue308f7662018-05-18 03:25:58 +0000266 mock_check = self.Patch(gcompute_client.ComputeClient,
267 "CheckImageExists",
268 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700269 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700270 resource_mock = mock.MagicMock()
271 self.compute_client._service.images = mock.MagicMock(
272 return_value=resource_mock)
273 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700274 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700275 image_name=self.IMAGE, source_uri=source_uri,
276 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700277 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700278 project=PROJECT, body=expected_body)
279 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700280 operation=mock.ANY,
281 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000282 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700283
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700284 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
285 def testSetImageLabel(self, mock_get_image):
286 """Test SetImageLabel."""
287 with mock.patch.object(self.compute_client._service, "images",
288 return_value=mock.MagicMock(
289 setLabels=mock.MagicMock())) as _:
290 image = {"name": self.IMAGE,
291 "sourceDisk": GS_IMAGE_SOURCE_DISK,
292 "labelFingerprint": self.IMAGE_FINGERPRINT,
293 "labels": {"a": "aaa", "b": "bbb"}}
294 mock_get_image.return_value = image
295 new_labels = {"a": "xxx", "c": "ccc"}
296 # Test
297 self.compute_client.SetImageLabels(
298 self.IMAGE, new_labels)
299 # Check result
300 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
301 self.compute_client._service.images().setLabels.assert_called_with(
302 project=PROJECT,
303 resource=self.IMAGE,
304 body={
305 "labels": expected_labels,
306 "labelFingerprint": self.IMAGE_FINGERPRINT
307 })
Kevin Chengb5963882018-05-09 00:06:27 -0700308
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700309 def testCreateImageRaiseDriverErrorWithValidInput(self):
310 """Test CreateImage with valid input."""
311 source_uri = GS_IMAGE_SOURCE_URI
312 source_disk = GS_IMAGE_SOURCE_DISK
herbertxue308f7662018-05-18 03:25:58 +0000313 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700314 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
315 image_name=self.IMAGE, source_uri=source_uri,
316 source_disk=source_disk)
317
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700318 def testCreateImageRaiseDriverErrorWithInvalidInput(self):
319 """Test CreateImage with valid input."""
320 source_uri = None
321 source_disk = None
322 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
323 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
324 image_name=self.IMAGE, source_uri=source_uri,
325 source_disk=source_disk)
Tri Vo29ac1822016-10-01 17:06:29 -0700326
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700327 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
328 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000329 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700330 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
331 side_effect=errors.DriverError("Expected fake error"))
332 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
333 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700334 resource_mock = mock.MagicMock()
335 self.compute_client._service.images = mock.MagicMock(
336 return_value=resource_mock)
337 resource_mock.insert = mock.MagicMock()
338
339 expected_body = {
340 "name": self.IMAGE,
341 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700342 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700343 },
344 }
herbertxuece12e232019-10-23 17:40:49 +0800345 six.assertRaisesRegex(
346 self,
Tri Vo29ac1822016-10-01 17:06:29 -0700347 errors.DriverError,
348 "Expected fake error",
349 self.compute_client.CreateImage,
350 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700351 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700352 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700353 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700354 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700355 operation=mock.ANY,
356 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700357 mock_check.assert_called_with(self.IMAGE)
358 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700359
360 def testCheckImageExistsTrue(self):
361 """Test CheckImageExists return True."""
362 resource_mock = mock.MagicMock()
363 mock_api = mock.MagicMock()
364 self.compute_client._service.images = mock.MagicMock(
365 return_value=resource_mock)
366 resource_mock.get = mock.MagicMock(return_value=mock_api)
367 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
368 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
369
370 def testCheckImageExistsFalse(self):
371 """Test CheckImageExists return False."""
372 resource_mock = mock.MagicMock()
373 mock_api = mock.MagicMock()
374 self.compute_client._service.images = mock.MagicMock(
375 return_value=resource_mock)
376 resource_mock.get = mock.MagicMock(return_value=mock_api)
377 mock_api.execute = mock.MagicMock(
378 side_effect=errors.ResourceNotFoundError(404, "no image"))
379 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
380
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700381 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
382 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700383 """Test DeleteImage."""
Tri Vo29ac1822016-10-01 17:06:29 -0700384 resource_mock = mock.MagicMock()
385 self.compute_client._service.images = mock.MagicMock(
386 return_value=resource_mock)
387 resource_mock.delete = mock.MagicMock()
388 self.compute_client.DeleteImage(self.IMAGE)
389 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700390 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700391 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700392
393 def _SetupBatchHttpRequestMock(self):
394 """Setup BatchHttpRequest mock."""
395 requests = {}
396
397 def _Add(request, callback, request_id):
398 requests[request_id] = (request, callback)
399
400 def _Execute():
401 for rid in requests:
402 _, callback = requests[rid]
403 callback(
404 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700405 mock_batch = mock.MagicMock()
406 mock_batch.add = _Add
407 mock_batch.execute = _Execute
408 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
409
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700410 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
411 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700412 """Test DeleteImages."""
413 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700414 fake_images = ["fake_image_1", "fake_image_2"]
415 mock_api = mock.MagicMock()
416 resource_mock = mock.MagicMock()
417 self.compute_client._service.images = mock.MagicMock(
418 return_value=resource_mock)
419 resource_mock.delete = mock.MagicMock(return_value=mock_api)
420 # Call the API.
421 deleted, failed, error_msgs = self.compute_client.DeleteImages(
422 fake_images)
423 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700424 calls = [
425 mock.call(project=PROJECT, image="fake_image_1"),
426 mock.call(project=PROJECT, image="fake_image_2")
427 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700428 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700429 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700430 self.assertEqual(error_msgs, [])
431 self.assertEqual(failed, [])
432 self.assertEqual(set(deleted), set(fake_images))
433
434 def testListImages(self):
435 """Test ListImages."""
436 fake_token = "fake_next_page_token"
437 image_1 = "image_1"
438 image_2 = "image_2"
439 response_1 = {"items": [image_1], "nextPageToken": fake_token}
440 response_2 = {"items": [image_2]}
441 self.Patch(
442 gcompute_client.ComputeClient,
443 "Execute",
444 side_effect=[response_1, response_2])
445 resource_mock = mock.MagicMock()
446 self.compute_client._service.images = mock.MagicMock(
447 return_value=resource_mock)
448 resource_mock.list = mock.MagicMock()
449 images = self.compute_client.ListImages()
450 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700451 mock.call(project=PROJECT, filter=None, pageToken=None),
452 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700453 ]
454 resource_mock.list.assert_has_calls(calls)
455 self.assertEqual(images, [image_1, image_2])
456
Kevin Chengb5963882018-05-09 00:06:27 -0700457 def testListImagesFromExternalProject(self):
458 """Test ListImages which accepts different project."""
459 image = "image_1"
460 response = {"items": [image]}
461 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
462 resource_mock = mock.MagicMock()
463 self.compute_client._service.images = mock.MagicMock(
464 return_value=resource_mock)
465 resource_mock.list = mock.MagicMock()
466 images = self.compute_client.ListImages(
467 image_project="fake-project-2")
468 calls = [
469 mock.call(project="fake-project-2", filter=None, pageToken=None)]
470 resource_mock.list.assert_has_calls(calls)
471 self.assertEqual(images, [image])
472
Tri Vo29ac1822016-10-01 17:06:29 -0700473 def testGetInstance(self):
474 """Test GetInstance."""
475 resource_mock = mock.MagicMock()
476 mock_api = mock.MagicMock()
477 self.compute_client._service.instances = mock.MagicMock(
478 return_value=resource_mock)
479 resource_mock.get = mock.MagicMock(return_value=mock_api)
480 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
481 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
482 self.assertEqual(result, {"name": self.INSTANCE})
483 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700484 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700485
486 def testListInstances(self):
487 """Test ListInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700488 instance_1 = "instance_1"
489 instance_2 = "instance_2"
herbertxue7a501212019-08-29 15:37:13 +0800490 response = {"items": {'zones/fake_zone': {"instances": [instance_1, instance_2]}}}
Tri Vo29ac1822016-10-01 17:06:29 -0700491 self.Patch(
492 gcompute_client.ComputeClient,
493 "Execute",
herbertxue7a501212019-08-29 15:37:13 +0800494 side_effect=[response])
Tri Vo29ac1822016-10-01 17:06:29 -0700495 resource_mock = mock.MagicMock()
496 self.compute_client._service.instances = mock.MagicMock(
497 return_value=resource_mock)
herbertxue7a501212019-08-29 15:37:13 +0800498 resource_mock.aggregatedList = mock.MagicMock()
499 instances = self.compute_client.ListInstances()
Tri Vo29ac1822016-10-01 17:06:29 -0700500 calls = [
501 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700502 project=PROJECT,
Kevin Cheng05945e42019-11-15 16:15:13 -0800503 filter=None,
504 pageToken=None),
Tri Vo29ac1822016-10-01 17:06:29 -0700505 ]
herbertxue7a501212019-08-29 15:37:13 +0800506 resource_mock.aggregatedList.assert_has_calls(calls)
Tri Vo29ac1822016-10-01 17:06:29 -0700507 self.assertEqual(instances, [instance_1, instance_2])
508
herbertxue7a501212019-08-29 15:37:13 +0800509 def testGetZoneByInstance(self):
510 """Test GetZoneByInstance."""
511 instance_1 = "instance_1"
512 response = {"items": {'zones/fake_zone': {"instances": [instance_1]}}}
513 self.Patch(
514 gcompute_client.ComputeClient,
515 "Execute",
516 side_effect=[response])
517 expected_zone = "fake_zone"
518 self.assertEqual(self.compute_client.GetZoneByInstance(instance_1),
519 expected_zone)
520
521 # Test unable to find 'zone' from instance name.
522 response = {"items": {'zones/fake_zone': {"warning": "No instances."}}}
523 self.Patch(
524 gcompute_client.ComputeClient,
525 "Execute",
526 side_effect=[response])
527 with self.assertRaises(errors.GetGceZoneError):
528 self.compute_client.GetZoneByInstance(instance_1)
529
530 def testGetZonesByInstances(self):
531 """Test GetZonesByInstances."""
532 instances = ["instance_1", "instance_2"]
533 # Test instances in the same zone.
534 self.Patch(
535 gcompute_client.ComputeClient,
536 "GetZoneByInstance",
537 side_effect=["zone_1", "zone_1"])
538 expected_result = {"zone_1": ["instance_1", "instance_2"]}
539 self.assertEqual(self.compute_client.GetZonesByInstances(instances),
540 expected_result)
541
542 # Test instances in different zones.
543 self.Patch(
544 gcompute_client.ComputeClient,
545 "GetZoneByInstance",
546 side_effect=["zone_1", "zone_2"])
547 expected_result = {"zone_1": ["instance_1"],
548 "zone_2": ["instance_2"]}
549 self.assertEqual(self.compute_client.GetZonesByInstances(instances),
550 expected_result)
551
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700552 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
553 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700554 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700555 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
556 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800557 @mock.patch("getpass.getuser", return_value="fake_user")
558 def testCreateInstance(self, _get_user, mock_wait, mock_get_mach_type,
Kevin Cheng480e1212018-10-24 00:23:30 -0700559 mock_get_subnetwork_url, mock_get_network_url,
560 mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700561 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700562 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
563 mock_get_network_url.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700564 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700565 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700566 resource_mock = mock.MagicMock()
567 self.compute_client._service.instances = mock.MagicMock(
568 return_value=resource_mock)
569 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000570 self.Patch(
571 self.compute_client,
572 "_GetExtraDiskArgs",
573 return_value=[{"fake_extra_arg": "fake_extra_value"}])
574 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
575 expected_disk_args = [self._disk_args]
576 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Kevin Chengc330f6f2019-05-13 09:32:42 -0700577 expected_scope = []
578 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
579 expected_scope.extend(self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700580
581 expected_body = {
582 "machineType": self.MACHINE_TYPE_URL,
583 "name": self.INSTANCE,
584 "networkInterfaces": [
585 {
586 "network": self.NETWORK_URL,
Kevin Cheng480e1212018-10-24 00:23:30 -0700587 "subnetwork": self.SUBNETWORK_URL,
Tri Vo29ac1822016-10-01 17:06:29 -0700588 "accessConfigs": [
589 {"name": "External NAT",
590 "type": "ONE_TO_ONE_NAT"}
591 ],
592 }
593 ],
herbertxue308f7662018-05-18 03:25:58 +0000594 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700595 "serviceAccounts": [
596 {"email": "default",
Kevin Chengc330f6f2019-05-13 09:32:42 -0700597 "scopes": expected_scope}
Tri Vo29ac1822016-10-01 17:06:29 -0700598 ],
599 "metadata": {
600 "items": [{"key": self.METADATA[0],
601 "value": self.METADATA[1]}],
602 },
cylanc2f98802019-08-15 17:47:30 +0800603 "labels":{constants.LABEL_CREATE_BY: "fake_user"},
Tri Vo29ac1822016-10-01 17:06:29 -0700604 }
605
606 self.compute_client.CreateInstance(
607 instance=self.INSTANCE,
608 image_name=self.IMAGE,
609 machine_type=self.MACHINE_TYPE,
610 metadata={self.METADATA[0]: self.METADATA[1]},
611 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000612 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700613 extra_disk_name=extra_disk_name,
614 extra_scopes=self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700615
616 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700617 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700618 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700619 mock.ANY,
620 operation_scope=gcompute_client.OperationScope.ZONE,
621 scope_name=self.ZONE)
622
Erwin Jansenf39798d2019-05-14 21:06:44 -0700623
624 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
625 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
626 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
627 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
628 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800629 @mock.patch("getpass.getuser", return_value="fake_user")
herbertxue1512f8a2019-06-27 13:56:23 +0800630 def testCreateInstanceWithTags(self,
cylanc2f98802019-08-15 17:47:30 +0800631 _get_user,
herbertxue1512f8a2019-06-27 13:56:23 +0800632 mock_wait,
633 mock_get_mach_type,
634 mock_get_subnetwork_url,
635 mock_get_network_url,
636 mock_get_image):
Erwin Jansenf39798d2019-05-14 21:06:44 -0700637 """Test CreateInstance."""
638 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
639 mock_get_network_url.return_value = self.NETWORK_URL
640 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
641 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
642 resource_mock = mock.MagicMock()
643 self.compute_client._service.instances = mock.MagicMock(
644 return_value=resource_mock)
645 resource_mock.insert = mock.MagicMock()
646 self.Patch(
647 self.compute_client,
648 "_GetExtraDiskArgs",
649 return_value=[{"fake_extra_arg": "fake_extra_value"}])
650 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
651 expected_disk_args = [self._disk_args]
652 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
653 expected_scope = []
654 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
655 expected_scope.extend(self.EXTRA_SCOPES)
656
657 expected_body = {
658 "machineType": self.MACHINE_TYPE_URL,
659 "name": self.INSTANCE,
660 "networkInterfaces": [
661 {
662 "network": self.NETWORK_URL,
663 "subnetwork": self.SUBNETWORK_URL,
664 "accessConfigs": [
665 {"name": "External NAT",
666 "type": "ONE_TO_ONE_NAT"}
667 ],
668 }
669 ],
670 'tags': {'items': ['https-server']},
671 "disks": expected_disk_args,
672 "serviceAccounts": [
673 {"email": "default",
674 "scopes": expected_scope}
675 ],
676 "metadata": {
677 "items": [{"key": self.METADATA[0],
678 "value": self.METADATA[1]}],
679 },
cylanc2f98802019-08-15 17:47:30 +0800680 "labels":{'created_by': "fake_user"},
Erwin Jansenf39798d2019-05-14 21:06:44 -0700681 }
682
683 self.compute_client.CreateInstance(
684 instance=self.INSTANCE,
685 image_name=self.IMAGE,
686 machine_type=self.MACHINE_TYPE,
687 metadata={self.METADATA[0]: self.METADATA[1]},
688 network=self.NETWORK,
689 zone=self.ZONE,
690 extra_disk_name=extra_disk_name,
691 tags=["https-server"],
692 extra_scopes=self.EXTRA_SCOPES)
693
694 resource_mock.insert.assert_called_with(
695 project=PROJECT, zone=self.ZONE, body=expected_body)
696 mock_wait.assert_called_with(
697 mock.ANY,
698 operation_scope=gcompute_client.OperationScope.ZONE,
699 scope_name=self.ZONE)
700
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700701 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
702 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
703 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700704 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700705 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
706 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800707 @mock.patch("getpass.getuser", return_value="fake_user")
708 def testCreateInstanceWithGpu(self, _get_user, mock_wait, mock_get_mach,
Kevin Cheng480e1212018-10-24 00:23:30 -0700709 mock_get_subnetwork, mock_get_network,
710 mock_get_image, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700711 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700712 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
713 mock_get_network.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700714 mock_get_subnetwork.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700715 mock_get_accel.return_value = self.ACCELERATOR_URL
716 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700717
718 resource_mock = mock.MagicMock()
719 self.compute_client._service.instances = mock.MagicMock(
720 return_value=resource_mock)
721 resource_mock.insert = mock.MagicMock()
722
723 expected_body = {
724 "machineType":
725 self.MACHINE_TYPE_URL,
726 "name":
727 self.INSTANCE,
728 "networkInterfaces": [{
Kevin Cheng480e1212018-10-24 00:23:30 -0700729 "network": self.NETWORK_URL,
730 "subnetwork": self.SUBNETWORK_URL,
Kevin Chengb5963882018-05-09 00:06:27 -0700731 "accessConfigs": [{
732 "name": "External NAT",
733 "type": "ONE_TO_ONE_NAT"
734 }],
735 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700736 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700737 "serviceAccounts": [{
738 "email": "default",
739 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
740 }],
741 "scheduling": {
742 "onHostMaintenance": "terminate"
743 },
744 "guestAccelerators": [{
745 "acceleratorCount": 1,
746 "acceleratorType": "http://speedy-gpu"
747 }],
748 "metadata": {
749 "items": [{
750 "key": self.METADATA[0],
751 "value": self.METADATA[1]
752 }],
753 },
cylanc2f98802019-08-15 17:47:30 +0800754 "labels":{'created_by': "fake_user"},
Kevin Chengb5963882018-05-09 00:06:27 -0700755 }
756
757 self.compute_client.CreateInstance(
758 instance=self.INSTANCE,
759 image_name=self.IMAGE,
760 machine_type=self.MACHINE_TYPE,
761 metadata={self.METADATA[0]: self.METADATA[1]},
762 network=self.NETWORK,
763 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700764 gpu=self.GPU,
765 extra_scopes=None)
Kevin Chengb5963882018-05-09 00:06:27 -0700766
767 resource_mock.insert.assert_called_with(
768 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700769 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700770 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
771 scope_name=self.ZONE)
772
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700773 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
774 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700775 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700776 resource_mock = mock.MagicMock()
777 self.compute_client._service.instances = mock.MagicMock(
778 return_value=resource_mock)
779 resource_mock.delete = mock.MagicMock()
780 self.compute_client.DeleteInstance(
781 instance=self.INSTANCE, zone=self.ZONE)
782 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700783 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700784 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700785 mock.ANY,
786 operation_scope=gcompute_client.OperationScope.ZONE,
787 scope_name=self.ZONE)
788
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700789 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
790 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700791 """Test DeleteInstances."""
792 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700793 fake_instances = ["fake_instance_1", "fake_instance_2"]
794 mock_api = mock.MagicMock()
795 resource_mock = mock.MagicMock()
796 self.compute_client._service.instances = mock.MagicMock(
797 return_value=resource_mock)
798 resource_mock.delete = mock.MagicMock(return_value=mock_api)
799 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
800 fake_instances, self.ZONE)
801 calls = [
802 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700803 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700804 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700805 zone=self.ZONE),
806 mock.call(
807 project=PROJECT,
808 instance="fake_instance_2",
809 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700810 ]
811 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700812 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700813 self.assertEqual(error_msgs, [])
814 self.assertEqual(failed, [])
815 self.assertEqual(set(deleted), set(fake_instances))
816
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700817 def testCreateDiskWithProject(self):
818 """Test CreateDisk with images using a set project."""
819 source_project = "fake-image-project"
820 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700821 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700822 resource_mock = mock.MagicMock()
823 self.compute_client._service.disks = mock.MagicMock(
824 return_value=resource_mock)
825 resource_mock.insert = mock.MagicMock()
826 self.compute_client.CreateDisk(
827 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
828 resource_mock.insert.assert_called_with(
829 project=PROJECT,
830 zone=self.ZONE,
831 sourceImage="projects/%s/global/images/fake_image" %
832 expected_project_to_use,
833 body={
834 "name":
835 "fake_disk",
836 "sizeGb":
837 10,
838 "type":
839 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
840 self.ZONE)
841 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700842 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700843
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700844 def testCreateDiskWithNoSourceProject(self):
845 """Test CreateDisk with images with no set project."""
846 source_project = None
847 expected_project_to_use = PROJECT
848 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
849 resource_mock = mock.MagicMock()
850 self.compute_client._service.disks = mock.MagicMock(
851 return_value=resource_mock)
852 resource_mock.insert = mock.MagicMock()
853 self.compute_client.CreateDisk(
854 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
855 resource_mock.insert.assert_called_with(
856 project=PROJECT,
857 zone=self.ZONE,
858 sourceImage="projects/%s/global/images/fake_image" %
859 expected_project_to_use,
860 body={
861 "name":
862 "fake_disk",
863 "sizeGb":
864 10,
865 "type":
866 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
867 self.ZONE)
868 })
869 self.assertTrue(mock_wait.called)
870
871 def testCreateDiskWithTypeStandard(self):
872 """Test CreateDisk with images using standard."""
873 disk_type = gcompute_client.PersistentDiskType.STANDARD
874 expected_disk_type_string = "pd-standard"
875 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
876 resource_mock = mock.MagicMock()
877 self.compute_client._service.disks = mock.MagicMock(
878 return_value=resource_mock)
879 resource_mock.insert = mock.MagicMock()
880 self.compute_client.CreateDisk(
881 "fake_disk",
882 "fake_image",
883 10,
884 self.ZONE,
885 source_project="fake-project",
886 disk_type=disk_type)
887 resource_mock.insert.assert_called_with(
888 project=PROJECT,
889 zone=self.ZONE,
890 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
891 body={
892 "name":
893 "fake_disk",
894 "sizeGb":
895 10,
896 "type":
897 "projects/%s/zones/%s/diskTypes/%s" %
898 (PROJECT, self.ZONE, expected_disk_type_string)
899 })
900 self.assertTrue(mock_wait.called)
901
902 def testCreateDiskWithTypeSSD(self):
903 """Test CreateDisk with images using standard."""
904 disk_type = gcompute_client.PersistentDiskType.SSD
905 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700906 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700907 resource_mock = mock.MagicMock()
908 self.compute_client._service.disks = mock.MagicMock(
909 return_value=resource_mock)
910 resource_mock.insert = mock.MagicMock()
911 self.compute_client.CreateDisk(
912 "fake_disk",
913 "fake_image",
914 10,
915 self.ZONE,
916 source_project="fake-project",
917 disk_type=disk_type)
918 resource_mock.insert.assert_called_with(
919 project=PROJECT,
920 zone=self.ZONE,
921 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
922 body={
923 "name":
924 "fake_disk",
925 "sizeGb":
926 10,
927 "type":
928 "projects/%s/zones/%s/diskTypes/%s" %
929 (PROJECT, self.ZONE, expected_disk_type_string)
930 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700931 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700932
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700933 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
934 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700935 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700936 resource_mock = mock.MagicMock()
937 self.compute_client._service.instances = mock.MagicMock(
938 return_value=resource_mock)
939 resource_mock.attachDisk = mock.MagicMock()
940 self.compute_client.AttachDisk(
941 "fake_instance_1", self.ZONE, deviceName="fake_disk",
942 source="fake-selfLink")
943 resource_mock.attachDisk.assert_called_with(
944 project=PROJECT,
945 zone=self.ZONE,
946 instance="fake_instance_1",
947 body={
948 "deviceName": "fake_disk",
949 "source": "fake-selfLink"
950 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700951 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700952
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700953 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
954 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700955 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700956 resource_mock = mock.MagicMock()
957 self.compute_client._service.instances = mock.MagicMock(
958 return_value=resource_mock)
959 resource_mock.detachDisk = mock.MagicMock()
960 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
961 resource_mock.detachDisk.assert_called_with(
962 project=PROJECT,
963 zone=self.ZONE,
964 instance="fake_instance_1",
965 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700966 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700967
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700968 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
969 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
970 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700971 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700972 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700973 resource_mock = mock.MagicMock()
974 self.compute_client._service.instances = mock.MagicMock(
975 return_value=resource_mock)
976 resource_mock.attachAccelerator = mock.MagicMock()
977 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
978 "nvidia-tesla-k80")
979 resource_mock.setMachineResources.assert_called_with(
980 project=PROJECT,
981 zone=self.ZONE,
982 instance="fake_instance_1",
983 body={
984 "guestAccelerators": [{
985 "acceleratorType": self.ACCELERATOR_URL,
986 "acceleratorCount": 1
987 }]
988 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700989 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700990
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700991 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
992 def testBatchExecuteOnInstances(self, mock_wait):
993 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700994 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700995 action = mock.MagicMock(return_value=mock.MagicMock())
996 fake_instances = ["fake_instance_1", "fake_instance_2"]
997 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
998 fake_instances, self.ZONE, action)
999 calls = [mock.call(instance="fake_instance_1"),
1000 mock.call(instance="fake_instance_2")]
1001 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001002 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001003 self.assertEqual(set(done), set(fake_instances))
1004 self.assertEqual(error_msgs, [])
1005 self.assertEqual(failed, [])
1006
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001007 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1008 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001009 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -07001010 resource_mock = mock.MagicMock()
1011 self.compute_client._service.instances = mock.MagicMock(
1012 return_value=resource_mock)
1013 resource_mock.reset = mock.MagicMock()
1014 self.compute_client.ResetInstance(
1015 instance=self.INSTANCE, zone=self.ZONE)
1016 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001017 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001018 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -07001019 mock.ANY,
1020 operation_scope=gcompute_client.OperationScope.ZONE,
1021 scope_name=self.ZONE)
1022
1023 def _CompareMachineSizeTestHelper(self,
1024 machine_info_1,
1025 machine_info_2,
1026 expected_result=None,
1027 expected_error_type=None):
1028 """Helper class for testing CompareMachineSize.
1029
Kevin Chengb5963882018-05-09 00:06:27 -07001030 Args:
1031 machine_info_1: A dictionary representing the first machine size.
1032 machine_info_2: A dictionary representing the second machine size.
1033 expected_result: An integer, 0, 1 or -1, or None if not set.
1034 expected_error_type: An exception type, if set will check for exception.
1035 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001036 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -07001037 gcompute_client.ComputeClient,
1038 "GetMachineType",
1039 side_effect=[machine_info_1, machine_info_2])
1040 if expected_error_type:
1041 self.assertRaises(expected_error_type,
1042 self.compute_client.CompareMachineSize, "name1",
1043 "name2", self.ZONE)
1044 else:
1045 result = self.compute_client.CompareMachineSize("name1", "name2",
1046 self.ZONE)
1047 self.assertEqual(result, expected_result)
1048
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001049 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -07001050 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
1051
1052 def testCompareMachineSizeSmall(self):
1053 """Test CompareMachineSize where the first one is smaller."""
1054 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
1055 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1056 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1057
Kevin Cheng4ae42772018-10-02 11:39:48 -07001058 def testCompareMachineSizeSmallSmallerOnSecond(self):
1059 """Test CompareMachineSize where the first one is smaller."""
1060 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
1061 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1062 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1063
Tri Vo29ac1822016-10-01 17:06:29 -07001064 def testCompareMachineSizeLarge(self):
1065 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -07001066 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
1067 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1068 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1069
1070 def testCompareMachineSizeLargeWithEqualElement(self):
1071 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -07001072 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
1073 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1074 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1075
1076 def testCompareMachineSizeEqual(self):
1077 """Test CompareMachineSize where two machine sizes are equal."""
1078 machine_info = {"guestCpus": 10, "memoryMb": 100}
1079 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
1080
1081 def testCompareMachineSizeBadMetric(self):
1082 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -07001083 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -07001084 self._CompareMachineSizeTestHelper(
1085 machine_info, machine_info, expected_error_type=errors.DriverError)
1086
1087 def testGetMachineType(self):
1088 """Test GetMachineType."""
1089 resource_mock = mock.MagicMock()
1090 mock_api = mock.MagicMock()
1091 self.compute_client._service.machineTypes = mock.MagicMock(
1092 return_value=resource_mock)
1093 resource_mock.get = mock.MagicMock(return_value=mock_api)
1094 mock_api.execute = mock.MagicMock(
1095 return_value={"name": self.MACHINE_TYPE})
1096 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
1097 self.ZONE)
1098 self.assertEqual(result, {"name": self.MACHINE_TYPE})
1099 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001100 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001101 zone=self.ZONE,
1102 machineType=self.MACHINE_TYPE)
1103
1104 def _GetSerialPortOutputTestHelper(self, response):
1105 """Helper function for testing GetSerialPortOutput.
1106
Kevin Chengb5963882018-05-09 00:06:27 -07001107 Args:
1108 response: A dictionary representing a fake response.
1109 """
Tri Vo29ac1822016-10-01 17:06:29 -07001110 resource_mock = mock.MagicMock()
1111 mock_api = mock.MagicMock()
1112 self.compute_client._service.instances = mock.MagicMock(
1113 return_value=resource_mock)
1114 resource_mock.getSerialPortOutput = mock.MagicMock(
1115 return_value=mock_api)
1116 mock_api.execute = mock.MagicMock(return_value=response)
1117
1118 if "contents" in response:
1119 result = self.compute_client.GetSerialPortOutput(
1120 instance=self.INSTANCE, zone=self.ZONE)
1121 self.assertEqual(result, "fake contents")
1122 else:
herbertxuece12e232019-10-23 17:40:49 +08001123 six.assertRaisesRegex(
1124 self,
Tri Vo29ac1822016-10-01 17:06:29 -07001125 errors.DriverError,
1126 "Malformed response.*",
1127 self.compute_client.GetSerialPortOutput,
1128 instance=self.INSTANCE,
1129 zone=self.ZONE)
1130 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001131 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001132 zone=self.ZONE,
1133 instance=self.INSTANCE,
1134 port=1)
1135
1136 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001137 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -07001138 response = {"contents": "fake contents"}
1139 self._GetSerialPortOutputTestHelper(response)
1140
1141 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001142 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -07001143 response = {"malformed": "fake contents"}
1144 self._GetSerialPortOutputTestHelper(response)
1145
1146 def testGetInstanceNamesByIPs(self):
1147 """Test GetInstanceNamesByIPs."""
1148 good_instance = {
1149 "name": "instance_1",
1150 "networkInterfaces": [
1151 {
1152 "accessConfigs": [
1153 {"natIP": "172.22.22.22"},
1154 ],
1155 },
1156 ],
1157 }
1158 bad_instance = {"name": "instance_2"}
1159 self.Patch(
1160 gcompute_client.ComputeClient,
1161 "ListInstances",
1162 return_value=[good_instance, bad_instance])
1163 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
herbertxue7a501212019-08-29 15:37:13 +08001164 ips=["172.22.22.22", "172.22.22.23"])
Tri Vo29ac1822016-10-01 17:06:29 -07001165 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1166 "172.22.22.23": None})
1167
cylan64af2db2019-01-17 15:13:59 +08001168 def testRsaNotInMetadata(self):
1169 """Test rsa not in metadata."""
Tri Vo29ac1822016-10-01 17:06:29 -07001170 fake_user = "fake_user"
cylan64af2db2019-01-17 15:13:59 +08001171 fake_ssh_key = "fake_ssh"
1172 metadata = {
1173 "kind": "compute#metadata",
1174 "fingerprint": "a-23icsyx4E=",
1175 "items": [
1176 {
1177 "key": "sshKeys",
1178 "value": "%s:%s" % (fake_user, self.SSHKEY)
1179 }
1180 ]
1181 }
1182 # Test rsa doesn't exist in metadata.
1183 new_entry = "%s:%s" % (fake_user, fake_ssh_key)
1184 self.assertEqual(True, gcompute_client.RsaNotInMetadata(metadata, new_entry))
1185
1186 # Test rsa exists in metadata.
1187 exist_entry = "%s:%s" %(fake_user, self.SSHKEY)
1188 self.assertEqual(False, gcompute_client.RsaNotInMetadata(metadata, exist_entry))
1189
1190 def testGetSshKeyFromMetadata(self):
1191 """Test get ssh key from metadata."""
1192 fake_user = "fake_user"
1193 metadata_key_exist_value_is_empty = {
1194 "kind": "compute#metadata",
1195 "fingerprint": "a-23icsyx4E=",
1196 "items": [
1197 {
1198 "key": "sshKeys",
1199 "value": ""
1200 }
1201 ]
1202 }
1203 metadata_key_exist = {
1204 "kind": "compute#metadata",
1205 "fingerprint": "a-23icsyx4E=",
1206 "items": [
1207 {
1208 "key": "sshKeys",
1209 "value": "%s:%s" % (fake_user, self.SSHKEY)
1210 }
1211 ]
1212 }
1213 metadata_key_not_exist = {
1214 "kind": "compute#metadata",
1215 "fingerprint": "a-23icsyx4E=",
1216 "items": [
1217 {
1218 }
1219 ]
1220 }
1221 expected_key_exist_value_is_empty = {
1222 "key": "sshKeys",
1223 "value": ""
1224 }
1225 expected_key_exist = {
1226 "key": "sshKeys",
1227 "value": "%s:%s" % (fake_user, self.SSHKEY)
1228 }
1229 self.assertEqual(expected_key_exist_value_is_empty,
1230 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist_value_is_empty))
1231 self.assertEqual(expected_key_exist,
1232 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist))
1233 self.assertEqual(None,
1234 gcompute_client.GetSshKeyFromMetadata(metadata_key_not_exist))
1235
1236
1237 def testGetRsaKeyPathExistsFalse(self):
1238 """Test the rsa key path not exists."""
1239 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1240 self.Patch(os.path, "exists", return_value=False)
herbertxuece12e232019-10-23 17:40:49 +08001241 six.assertRaisesRegex(self,
1242 errors.DriverError,
1243 "RSA file %s does not exist." % fake_ssh_rsa_path,
1244 gcompute_client.GetRsaKey,
1245 ssh_rsa_path=fake_ssh_rsa_path)
cylan64af2db2019-01-17 15:13:59 +08001246
1247 def testGetRsaKey(self):
1248 """Test get the rsa key."""
1249 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1250 self.Patch(os.path, "exists", return_value=True)
1251 m = mock.mock_open(read_data=self.SSHKEY)
1252 with mock.patch("__builtin__.open", m):
1253 result = gcompute_client.GetRsaKey(fake_ssh_rsa_path)
1254 self.assertEqual(self.SSHKEY, result)
1255
1256 def testUpdateRsaInMetadata(self):
1257 """Test update rsa in metadata."""
1258 fake_ssh_key = "fake_ssh"
1259 fake_metadata_sshkeys_not_exist = {
1260 "kind": "compute#metadata",
1261 "fingerprint": "a-23icsyx4E=",
1262 "items": [
1263 {
1264 "key": "not_sshKeys",
1265 "value": ""
1266 }
1267 ]
1268 }
1269 new_entry = "new_user:%s" % fake_ssh_key
1270 expected = {
1271 "kind": "compute#metadata",
1272 "fingerprint": "a-23icsyx4E=",
1273 "items": [
1274 {
1275 "key": "not_sshKeys",
1276 "value": ""
1277 },
1278 {
1279 "key": "sshKeys",
1280 "value": new_entry
1281 }
1282 ]
1283 }
1284 self.Patch(os.path, "exists", return_value=True)
1285 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1286 resource_mock = mock.MagicMock()
1287 self.compute_client.SetInstanceMetadata = mock.MagicMock(
1288 return_value=resource_mock)
1289 # Test the key item not exists in the metadata.
1290 self.compute_client.UpdateRsaInMetadata(
1291 "fake_zone",
1292 "fake_instance",
1293 fake_metadata_sshkeys_not_exist,
1294 new_entry)
1295 self.compute_client.SetInstanceMetadata.assert_called_with(
1296 "fake_zone",
1297 "fake_instance",
1298 expected)
1299
1300 # Test the key item exists in the metadata.
1301 fake_metadata_ssh_keys_exists = {
1302 "kind": "compute#metadata",
1303 "fingerprint": "a-23icsyx4E=",
1304 "items": [
1305 {
1306 "key": "sshKeys",
1307 "value": "old_user:%s" % self.SSHKEY
1308 }
1309 ]
1310 }
1311 expected_ssh_keys_exists = {
1312 "kind": "compute#metadata",
1313 "fingerprint": "a-23icsyx4E=",
1314 "items": [
1315 {
1316 "key": "sshKeys",
1317 "value": "old_user:%s\n%s" % (self.SSHKEY, new_entry)
1318 }
1319 ]
1320 }
1321
1322 self.compute_client.UpdateRsaInMetadata(
1323 "fake_zone",
1324 "fake_instance",
1325 fake_metadata_ssh_keys_exists,
1326 new_entry)
1327 self.compute_client.SetInstanceMetadata.assert_called_with(
1328 "fake_zone",
1329 "fake_instance",
1330 expected_ssh_keys_exists)
1331
1332 def testAddSshRsaToInstance(self):
1333 """Test add ssh rsa key to instance."""
1334 fake_user = "fake_user"
1335 instance_metadata_key_not_exist = {
1336 "metadata": {
Tri Vo29ac1822016-10-01 17:06:29 -07001337 "kind": "compute#metadata",
1338 "fingerprint": "a-23icsyx4E=",
1339 "items": [
1340 {
1341 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001342 "value": ""
1343 }
1344 ]
1345 }
1346 }
1347 instance_metadata_key_exist = {
1348 "metadata": {
1349 "kind": "compute#metadata",
1350 "fingerprint": "a-23icsyx4E=",
1351 "items": [
1352 {
1353 "key": "sshKeys",
1354 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001355 }
1356 ]
1357 }
1358 }
1359 expected = {
1360 "kind": "compute#metadata",
1361 "fingerprint": "a-23icsyx4E=",
1362 "items": [
1363 {
1364 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001365 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001366 }
1367 ]
1368 }
1369
1370 self.Patch(os.path, "exists", return_value=True)
cylan64af2db2019-01-17 15:13:59 +08001371 m = mock.mock_open(read_data=self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001372 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
herbertxue7a501212019-08-29 15:37:13 +08001373 self.Patch(gcompute_client.ComputeClient, "GetZoneByInstance",
1374 return_value="fake_zone")
Tri Vo29ac1822016-10-01 17:06:29 -07001375 resource_mock = mock.MagicMock()
cylan64af2db2019-01-17 15:13:59 +08001376 self.compute_client._service.instances = mock.MagicMock(
Tri Vo29ac1822016-10-01 17:06:29 -07001377 return_value=resource_mock)
cylan64af2db2019-01-17 15:13:59 +08001378 resource_mock.setMetadata = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001379
cylan64af2db2019-01-17 15:13:59 +08001380 # Test the key not exists in the metadata.
Tri Vo29ac1822016-10-01 17:06:29 -07001381 self.Patch(
cylan64af2db2019-01-17 15:13:59 +08001382 gcompute_client.ComputeClient, "GetInstance",
1383 return_value=instance_metadata_key_not_exist)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001384 with mock.patch("__builtin__.open", m):
cylan64af2db2019-01-17 15:13:59 +08001385 self.compute_client.AddSshRsaInstanceMetadata(
cylan64af2db2019-01-17 15:13:59 +08001386 fake_user,
1387 "/path/to/test_rsa.pub",
1388 "fake_instance")
1389 resource_mock.setMetadata.assert_called_with(
1390 project=PROJECT,
1391 zone="fake_zone",
1392 instance="fake_instance",
1393 body=expected)
1394
1395 # Test the key already exists in the metadata.
1396 resource_mock.setMetadata.call_count = 0
1397 self.Patch(
1398 gcompute_client.ComputeClient, "GetInstance",
1399 return_value=instance_metadata_key_exist)
1400 with mock.patch("__builtin__.open", m):
1401 self.compute_client.AddSshRsaInstanceMetadata(
cylan64af2db2019-01-17 15:13:59 +08001402 fake_user,
1403 "/path/to/test_rsa.pub",
1404 "fake_instance")
1405 resource_mock.setMetadata.assert_not_called()
Tri Vo29ac1822016-10-01 17:06:29 -07001406
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001407 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1408 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001409 """Test DeleteDisks."""
1410 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001411 fake_disks = ["fake_disk_1", "fake_disk_2"]
1412 mock_api = mock.MagicMock()
1413 resource_mock = mock.MagicMock()
1414 self.compute_client._service.disks = mock.MagicMock(
1415 return_value=resource_mock)
1416 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1417 # Call the API.
1418 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1419 fake_disks, zone=self.ZONE)
1420 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001421 calls = [
1422 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1423 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1424 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001425 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001426 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001427 self.assertEqual(error_msgs, [])
1428 self.assertEqual(failed, [])
1429 self.assertEqual(set(deleted), set(fake_disks))
1430
Kevin Chengb5963882018-05-09 00:06:27 -07001431 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001432 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001433 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1434 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001435 """Raise 412 HTTP exception."""
1436 if not sentinel.hitFingerPrintConflict.called:
1437 sentinel.hitFingerPrintConflict()
1438 raise errors.HttpError(412, "resource labels have changed")
1439 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001440
1441 sentinel = mock.MagicMock()
1442 result = Raise412(sentinel)
1443 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1444 self.assertEqual("Passed", result)
1445
Sam Chiuf5e03732019-11-29 16:29:43 +08001446 def testCheckAccess(self):
1447 """Test CheckAccess."""
1448 # Checking non-403 should raise error
1449 error = errors.HttpError(503, "fake retriable error.")
1450 self.Patch(
1451 gcompute_client.ComputeClient, "Execute",
1452 side_effect=error)
1453
1454 with self.assertRaises(errors.HttpError):
1455 self.compute_client.CheckAccess()
1456
1457 # Checking 403 should return False
1458 error = errors.HttpError(403, "fake retriable error.")
1459 self.Patch(
1460 gcompute_client.ComputeClient, "Execute",
1461 side_effect=error)
1462 self.assertFalse(self.compute_client.CheckAccess())
1463
Tri Vo29ac1822016-10-01 17:06:29 -07001464
1465if __name__ == "__main__":
1466 unittest.main()