blob: f9ed0c791bbb0b2d2813ab431a5491a2f147d4aa [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
Tri Vo29ac1822016-10-01 17:06:29 -070029from acloud.internal.lib import driver_test_lib
30from acloud.internal.lib import gcompute_client
31from acloud.internal.lib import utils
Tri Vo29ac1822016-10-01 17:06:29 -070032
Kevin Chengb5963882018-05-09 00:06:27 -070033GS_IMAGE_SOURCE_URI = "https://storage.googleapis.com/fake-bucket/fake.tar.gz"
34GS_IMAGE_SOURCE_DISK = (
35 "https://www.googleapis.com/compute/v1/projects/fake-project/zones/"
36 "us-east1-d/disks/fake-disk")
37PROJECT = "fake-project"
Tri Vo29ac1822016-10-01 17:06:29 -070038
Kevin Cheng5c124ec2018-05-16 13:28:51 -070039# pylint: disable=protected-access, too-many-public-methods
Kevin Cheng070ae5c2018-08-02 16:03:00 -070040class ComputeClientTest(driver_test_lib.BaseDriverTest):
Tri Vo29ac1822016-10-01 17:06:29 -070041 """Test ComputeClient."""
42
Kevin Chengb5963882018-05-09 00:06:27 -070043 PROJECT_OTHER = "fake-project-other"
Tri Vo29ac1822016-10-01 17:06:29 -070044 INSTANCE = "fake-instance"
45 IMAGE = "fake-image"
46 IMAGE_URL = "http://fake-image-url"
Kevin Chengb5963882018-05-09 00:06:27 -070047 IMAGE_OTHER = "fake-image-other"
Tri Vo29ac1822016-10-01 17:06:29 -070048 MACHINE_TYPE = "fake-machine-type"
49 MACHINE_TYPE_URL = "http://fake-machine-type-url"
50 METADATA = ("metadata_key", "metadata_value")
Kevin Chengb5963882018-05-09 00:06:27 -070051 ACCELERATOR_URL = "http://speedy-gpu"
Tri Vo29ac1822016-10-01 17:06:29 -070052 NETWORK = "fake-network"
53 NETWORK_URL = "http://fake-network-url"
Kevin Cheng480e1212018-10-24 00:23:30 -070054 SUBNETWORK_URL = "http://fake-subnetwork-url"
Tri Vo29ac1822016-10-01 17:06:29 -070055 ZONE = "fake-zone"
56 REGION = "fake-region"
57 OPERATION_NAME = "fake-op"
Kevin Chengb5963882018-05-09 00:06:27 -070058 IMAGE_FINGERPRINT = "L_NWHuz7wTY="
59 GPU = "fancy-graphics"
cylan64af2db2019-01-17 15:13:59 +080060 SSHKEY = (
61 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
62 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
63 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
64 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
65 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
66 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
67 "ApiihqNL1111 test@test1.org")
Tri Vo29ac1822016-10-01 17:06:29 -070068
69 def setUp(self):
70 """Set up test."""
71 super(ComputeClientTest, self).setUp()
72 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
73 fake_cfg = mock.MagicMock()
Kevin Chengb5963882018-05-09 00:06:27 -070074 fake_cfg.project = PROJECT
75 self.compute_client = gcompute_client.ComputeClient(
76 fake_cfg, mock.MagicMock())
Tri Vo29ac1822016-10-01 17:06:29 -070077 self.compute_client._service = mock.MagicMock()
78
Kevin Cheng5c124ec2018-05-16 13:28:51 -070079 self._disk_args = copy.deepcopy(gcompute_client.BASE_DISK_ARGS)
80 self._disk_args["initializeParams"] = {"diskName": self.INSTANCE,
81 "sourceImage": self.IMAGE_URL}
82
83 # pylint: disable=invalid-name
Tri Vo29ac1822016-10-01 17:06:29 -070084 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
85 """A helper class for setting up mocks for testGetOperationStatus*.
86
Kevin Chengb5963882018-05-09 00:06:27 -070087 Args:
88 mock_result: The result to return by _GetOperationStatus.
89 operation_scope: A value of OperationScope.
Tri Vo29ac1822016-10-01 17:06:29 -070090
Kevin Chengb5963882018-05-09 00:06:27 -070091 Returns:
92 A mock for Resource object.
93 """
Tri Vo29ac1822016-10-01 17:06:29 -070094 resource_mock = mock.MagicMock()
95 mock_api = mock.MagicMock()
96 if operation_scope == gcompute_client.OperationScope.GLOBAL:
97 self.compute_client._service.globalOperations = mock.MagicMock(
98 return_value=resource_mock)
99 elif operation_scope == gcompute_client.OperationScope.ZONE:
100 self.compute_client._service.zoneOperations = mock.MagicMock(
101 return_value=resource_mock)
102 elif operation_scope == gcompute_client.OperationScope.REGION:
103 self.compute_client._service.regionOperations = mock.MagicMock(
104 return_value=resource_mock)
105 resource_mock.get = mock.MagicMock(return_value=mock_api)
106 mock_api.execute = mock.MagicMock(return_value=mock_result)
107 return resource_mock
108
109 def testGetOperationStatusGlobal(self):
110 """Test _GetOperationStatus for global."""
111 resource_mock = self._SetupMocksForGetOperationStatus(
112 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
113 status = self.compute_client._GetOperationStatus(
114 {"name": self.OPERATION_NAME},
115 gcompute_client.OperationScope.GLOBAL)
116 self.assertEqual(status, "GOOD")
117 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700118 project=PROJECT, operation=self.OPERATION_NAME)
Tri Vo29ac1822016-10-01 17:06:29 -0700119
120 def testGetOperationStatusZone(self):
121 """Test _GetOperationStatus for zone."""
122 resource_mock = self._SetupMocksForGetOperationStatus(
123 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
124 status = self.compute_client._GetOperationStatus(
125 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
126 self.ZONE)
127 self.assertEqual(status, "GOOD")
128 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700129 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700130 operation=self.OPERATION_NAME,
131 zone=self.ZONE)
132
133 def testGetOperationStatusRegion(self):
134 """Test _GetOperationStatus for region."""
135 resource_mock = self._SetupMocksForGetOperationStatus(
136 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
137 self.compute_client._GetOperationStatus(
138 {"name": self.OPERATION_NAME},
139 gcompute_client.OperationScope.REGION, self.REGION)
140 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700141 project=PROJECT, operation=self.OPERATION_NAME, region=self.REGION)
Tri Vo29ac1822016-10-01 17:06:29 -0700142
143 def testGetOperationStatusError(self):
144 """Test _GetOperationStatus failed."""
145 self._SetupMocksForGetOperationStatus(
146 {"error": {"errors": ["error1", "error2"]}},
147 gcompute_client.OperationScope.GLOBAL)
148 self.assertRaisesRegexp(errors.DriverError,
149 "Get operation state failed.*error1.*error2",
150 self.compute_client._GetOperationStatus,
151 {"name": self.OPERATION_NAME},
152 gcompute_client.OperationScope.GLOBAL)
153
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700154 @mock.patch.object(errors, "GceOperationTimeoutError")
155 @mock.patch.object(utils, "PollAndWait")
156 def testWaitOnOperation(self, mock_poll, mock_gce_operation_timeout_error):
Tri Vo29ac1822016-10-01 17:06:29 -0700157 """Test WaitOnOperation."""
158 mock_error = mock.MagicMock()
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700159 mock_gce_operation_timeout_error.return_value = mock_error
Tri Vo29ac1822016-10-01 17:06:29 -0700160 self.compute_client.WaitOnOperation(
161 operation={"name": self.OPERATION_NAME},
162 operation_scope=gcompute_client.OperationScope.REGION,
163 scope_name=self.REGION)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700164 mock_poll.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700165 func=self.compute_client._GetOperationStatus,
166 expected_return="DONE",
167 timeout_exception=mock_error,
168 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
Kevin Chengb5963882018-05-09 00:06:27 -0700169 sleep_interval_secs=self.compute_client.OPERATION_POLL_INTERVAL_SECS,
Tri Vo29ac1822016-10-01 17:06:29 -0700170 operation={"name": self.OPERATION_NAME},
171 operation_scope=gcompute_client.OperationScope.REGION,
172 scope_name=self.REGION)
173
Kevin Chengb5963882018-05-09 00:06:27 -0700174 def testGetImage(self):
175 """Test GetImage."""
176 resource_mock = mock.MagicMock()
177 mock_api = mock.MagicMock()
178 self.compute_client._service.images = mock.MagicMock(
179 return_value=resource_mock)
180 resource_mock.get = mock.MagicMock(return_value=mock_api)
181 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
182 result = self.compute_client.GetImage(self.IMAGE)
183 self.assertEqual(result, {"name": self.IMAGE})
184 resource_mock.get.assert_called_with(project=PROJECT, image=self.IMAGE)
185
186 def testGetImageOther(self):
187 """Test GetImage with other project."""
188 resource_mock = mock.MagicMock()
189 mock_api = mock.MagicMock()
190 self.compute_client._service.images = mock.MagicMock(
191 return_value=resource_mock)
192 resource_mock.get = mock.MagicMock(return_value=mock_api)
193 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE_OTHER})
194 result = self.compute_client.GetImage(
195 image_name=self.IMAGE_OTHER,
196 image_project=self.PROJECT_OTHER)
197 self.assertEqual(result, {"name": self.IMAGE_OTHER})
198 resource_mock.get.assert_called_with(
199 project=self.PROJECT_OTHER, image=self.IMAGE_OTHER)
200
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700201 def testCreateImageWithSourceURI(self):
202 """Test CreateImage with src uri."""
203 source_uri = GS_IMAGE_SOURCE_URI
204 source_disk = None
205 labels = None
206 expected_body = {"name": self.IMAGE,
207 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}
208 mock_check = self.Patch(gcompute_client.ComputeClient,
209 "CheckImageExists",
210 return_value=False)
211 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
212 resource_mock = mock.MagicMock()
213 self.compute_client._service.images = mock.MagicMock(
214 return_value=resource_mock)
215 resource_mock.insert = mock.MagicMock()
216 self.compute_client.CreateImage(
217 image_name=self.IMAGE, source_uri=source_uri,
218 source_disk=source_disk, labels=labels)
219 resource_mock.insert.assert_called_with(
220 project=PROJECT, body=expected_body)
221 mock_wait.assert_called_with(
222 operation=mock.ANY,
223 operation_scope=gcompute_client.OperationScope.GLOBAL)
224 mock_check.assert_called_with(self.IMAGE)
225
226 def testCreateImageWithSourceDisk(self):
227 """Test CreateImage with src disk."""
228 source_uri = None
229 source_disk = GS_IMAGE_SOURCE_DISK
230 labels = None
231 expected_body = {"name": self.IMAGE,
232 "sourceDisk": GS_IMAGE_SOURCE_DISK}
233 mock_check = self.Patch(gcompute_client.ComputeClient,
234 "CheckImageExists",
235 return_value=False)
236 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
237 resource_mock = mock.MagicMock()
238 self.compute_client._service.images = mock.MagicMock(
239 return_value=resource_mock)
240 resource_mock.insert = mock.MagicMock()
241 self.compute_client.CreateImage(
242 image_name=self.IMAGE, source_uri=source_uri,
243 source_disk=source_disk, labels=labels)
244 resource_mock.insert.assert_called_with(
245 project=PROJECT, body=expected_body)
246 mock_wait.assert_called_with(
247 operation=mock.ANY,
248 operation_scope=gcompute_client.OperationScope.GLOBAL)
249 mock_check.assert_called_with(self.IMAGE)
250
251 def testCreateImageWithSourceDiskAndLabel(self):
252 """Test CreateImage with src disk and label."""
253 source_uri = None
254 source_disk = GS_IMAGE_SOURCE_DISK
255 labels = {"label1": "xxx"}
256 expected_body = {"name": self.IMAGE,
257 "sourceDisk": GS_IMAGE_SOURCE_DISK,
258 "labels": {"label1": "xxx"}}
herbertxue308f7662018-05-18 03:25:58 +0000259 mock_check = self.Patch(gcompute_client.ComputeClient,
260 "CheckImageExists",
261 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700262 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700263 resource_mock = mock.MagicMock()
264 self.compute_client._service.images = mock.MagicMock(
265 return_value=resource_mock)
266 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700267 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700268 image_name=self.IMAGE, source_uri=source_uri,
269 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700270 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700271 project=PROJECT, body=expected_body)
272 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700273 operation=mock.ANY,
274 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000275 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700276
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700277 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
278 def testSetImageLabel(self, mock_get_image):
279 """Test SetImageLabel."""
280 with mock.patch.object(self.compute_client._service, "images",
281 return_value=mock.MagicMock(
282 setLabels=mock.MagicMock())) as _:
283 image = {"name": self.IMAGE,
284 "sourceDisk": GS_IMAGE_SOURCE_DISK,
285 "labelFingerprint": self.IMAGE_FINGERPRINT,
286 "labels": {"a": "aaa", "b": "bbb"}}
287 mock_get_image.return_value = image
288 new_labels = {"a": "xxx", "c": "ccc"}
289 # Test
290 self.compute_client.SetImageLabels(
291 self.IMAGE, new_labels)
292 # Check result
293 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
294 self.compute_client._service.images().setLabels.assert_called_with(
295 project=PROJECT,
296 resource=self.IMAGE,
297 body={
298 "labels": expected_labels,
299 "labelFingerprint": self.IMAGE_FINGERPRINT
300 })
Kevin Chengb5963882018-05-09 00:06:27 -0700301
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700302 def testCreateImageRaiseDriverErrorWithValidInput(self):
303 """Test CreateImage with valid input."""
304 source_uri = GS_IMAGE_SOURCE_URI
305 source_disk = GS_IMAGE_SOURCE_DISK
herbertxue308f7662018-05-18 03:25:58 +0000306 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700307 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
308 image_name=self.IMAGE, source_uri=source_uri,
309 source_disk=source_disk)
310
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700311 def testCreateImageRaiseDriverErrorWithInvalidInput(self):
312 """Test CreateImage with valid input."""
313 source_uri = None
314 source_disk = None
315 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
316 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
317 image_name=self.IMAGE, source_uri=source_uri,
318 source_disk=source_disk)
Tri Vo29ac1822016-10-01 17:06:29 -0700319
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700320 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
321 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000322 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700323 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
324 side_effect=errors.DriverError("Expected fake error"))
325 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
326 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700327 resource_mock = mock.MagicMock()
328 self.compute_client._service.images = mock.MagicMock(
329 return_value=resource_mock)
330 resource_mock.insert = mock.MagicMock()
331
332 expected_body = {
333 "name": self.IMAGE,
334 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700335 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700336 },
337 }
338 self.assertRaisesRegexp(
339 errors.DriverError,
340 "Expected fake error",
341 self.compute_client.CreateImage,
342 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700343 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700344 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700345 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700346 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700347 operation=mock.ANY,
348 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700349 mock_check.assert_called_with(self.IMAGE)
350 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700351
352 def testCheckImageExistsTrue(self):
353 """Test CheckImageExists return True."""
354 resource_mock = mock.MagicMock()
355 mock_api = mock.MagicMock()
356 self.compute_client._service.images = mock.MagicMock(
357 return_value=resource_mock)
358 resource_mock.get = mock.MagicMock(return_value=mock_api)
359 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
360 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
361
362 def testCheckImageExistsFalse(self):
363 """Test CheckImageExists return False."""
364 resource_mock = mock.MagicMock()
365 mock_api = mock.MagicMock()
366 self.compute_client._service.images = mock.MagicMock(
367 return_value=resource_mock)
368 resource_mock.get = mock.MagicMock(return_value=mock_api)
369 mock_api.execute = mock.MagicMock(
370 side_effect=errors.ResourceNotFoundError(404, "no image"))
371 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
372
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700373 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
374 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700375 """Test DeleteImage."""
Tri Vo29ac1822016-10-01 17:06:29 -0700376 resource_mock = mock.MagicMock()
377 self.compute_client._service.images = mock.MagicMock(
378 return_value=resource_mock)
379 resource_mock.delete = mock.MagicMock()
380 self.compute_client.DeleteImage(self.IMAGE)
381 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700382 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700383 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700384
385 def _SetupBatchHttpRequestMock(self):
386 """Setup BatchHttpRequest mock."""
387 requests = {}
388
389 def _Add(request, callback, request_id):
390 requests[request_id] = (request, callback)
391
392 def _Execute():
393 for rid in requests:
394 _, callback = requests[rid]
395 callback(
396 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700397 mock_batch = mock.MagicMock()
398 mock_batch.add = _Add
399 mock_batch.execute = _Execute
400 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
401
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700402 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
403 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700404 """Test DeleteImages."""
405 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700406 fake_images = ["fake_image_1", "fake_image_2"]
407 mock_api = mock.MagicMock()
408 resource_mock = mock.MagicMock()
409 self.compute_client._service.images = mock.MagicMock(
410 return_value=resource_mock)
411 resource_mock.delete = mock.MagicMock(return_value=mock_api)
412 # Call the API.
413 deleted, failed, error_msgs = self.compute_client.DeleteImages(
414 fake_images)
415 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700416 calls = [
417 mock.call(project=PROJECT, image="fake_image_1"),
418 mock.call(project=PROJECT, image="fake_image_2")
419 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700420 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700421 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700422 self.assertEqual(error_msgs, [])
423 self.assertEqual(failed, [])
424 self.assertEqual(set(deleted), set(fake_images))
425
426 def testListImages(self):
427 """Test ListImages."""
428 fake_token = "fake_next_page_token"
429 image_1 = "image_1"
430 image_2 = "image_2"
431 response_1 = {"items": [image_1], "nextPageToken": fake_token}
432 response_2 = {"items": [image_2]}
433 self.Patch(
434 gcompute_client.ComputeClient,
435 "Execute",
436 side_effect=[response_1, response_2])
437 resource_mock = mock.MagicMock()
438 self.compute_client._service.images = mock.MagicMock(
439 return_value=resource_mock)
440 resource_mock.list = mock.MagicMock()
441 images = self.compute_client.ListImages()
442 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700443 mock.call(project=PROJECT, filter=None, pageToken=None),
444 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700445 ]
446 resource_mock.list.assert_has_calls(calls)
447 self.assertEqual(images, [image_1, image_2])
448
Kevin Chengb5963882018-05-09 00:06:27 -0700449 def testListImagesFromExternalProject(self):
450 """Test ListImages which accepts different project."""
451 image = "image_1"
452 response = {"items": [image]}
453 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
454 resource_mock = mock.MagicMock()
455 self.compute_client._service.images = mock.MagicMock(
456 return_value=resource_mock)
457 resource_mock.list = mock.MagicMock()
458 images = self.compute_client.ListImages(
459 image_project="fake-project-2")
460 calls = [
461 mock.call(project="fake-project-2", filter=None, pageToken=None)]
462 resource_mock.list.assert_has_calls(calls)
463 self.assertEqual(images, [image])
464
Tri Vo29ac1822016-10-01 17:06:29 -0700465 def testGetInstance(self):
466 """Test GetInstance."""
467 resource_mock = mock.MagicMock()
468 mock_api = mock.MagicMock()
469 self.compute_client._service.instances = mock.MagicMock(
470 return_value=resource_mock)
471 resource_mock.get = mock.MagicMock(return_value=mock_api)
472 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
473 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
474 self.assertEqual(result, {"name": self.INSTANCE})
475 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700476 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700477
478 def testListInstances(self):
479 """Test ListInstances."""
480 fake_token = "fake_next_page_token"
481 instance_1 = "instance_1"
482 instance_2 = "instance_2"
483 response_1 = {"items": [instance_1], "nextPageToken": fake_token}
484 response_2 = {"items": [instance_2]}
485 self.Patch(
486 gcompute_client.ComputeClient,
487 "Execute",
488 side_effect=[response_1, response_2])
489 resource_mock = mock.MagicMock()
490 self.compute_client._service.instances = mock.MagicMock(
491 return_value=resource_mock)
492 resource_mock.list = mock.MagicMock()
493 instances = self.compute_client.ListInstances(self.ZONE)
494 calls = [
495 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700496 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700497 zone=self.ZONE,
498 filter=None,
499 pageToken=None),
500 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700501 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700502 zone=self.ZONE,
503 filter=None,
504 pageToken=fake_token),
505 ]
506 resource_mock.list.assert_has_calls(calls)
507 self.assertEqual(instances, [instance_1, instance_2])
508
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700509 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
510 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700511 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700512 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
513 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
514 def testCreateInstance(self, mock_wait, mock_get_mach_type,
Kevin Cheng480e1212018-10-24 00:23:30 -0700515 mock_get_subnetwork_url, mock_get_network_url,
516 mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700517 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700518 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
519 mock_get_network_url.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700520 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700521 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700522 resource_mock = mock.MagicMock()
523 self.compute_client._service.instances = mock.MagicMock(
524 return_value=resource_mock)
525 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000526 self.Patch(
527 self.compute_client,
528 "_GetExtraDiskArgs",
529 return_value=[{"fake_extra_arg": "fake_extra_value"}])
530 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
531 expected_disk_args = [self._disk_args]
532 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Tri Vo29ac1822016-10-01 17:06:29 -0700533
534 expected_body = {
535 "machineType": self.MACHINE_TYPE_URL,
536 "name": self.INSTANCE,
537 "networkInterfaces": [
538 {
539 "network": self.NETWORK_URL,
Kevin Cheng480e1212018-10-24 00:23:30 -0700540 "subnetwork": self.SUBNETWORK_URL,
Tri Vo29ac1822016-10-01 17:06:29 -0700541 "accessConfigs": [
542 {"name": "External NAT",
543 "type": "ONE_TO_ONE_NAT"}
544 ],
545 }
546 ],
herbertxue308f7662018-05-18 03:25:58 +0000547 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700548 "serviceAccounts": [
549 {"email": "default",
550 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE}
551 ],
552 "metadata": {
553 "items": [{"key": self.METADATA[0],
554 "value": self.METADATA[1]}],
555 },
556 }
557
558 self.compute_client.CreateInstance(
559 instance=self.INSTANCE,
560 image_name=self.IMAGE,
561 machine_type=self.MACHINE_TYPE,
562 metadata={self.METADATA[0]: self.METADATA[1]},
563 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000564 zone=self.ZONE,
565 extra_disk_name=extra_disk_name)
Tri Vo29ac1822016-10-01 17:06:29 -0700566
567 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700568 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700569 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700570 mock.ANY,
571 operation_scope=gcompute_client.OperationScope.ZONE,
572 scope_name=self.ZONE)
573
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700574 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
575 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
576 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700577 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700578 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
579 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
580 def testCreateInstanceWithGpu(self, mock_wait, mock_get_mach,
Kevin Cheng480e1212018-10-24 00:23:30 -0700581 mock_get_subnetwork, mock_get_network,
582 mock_get_image, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700583 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700584 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
585 mock_get_network.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700586 mock_get_subnetwork.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700587 mock_get_accel.return_value = self.ACCELERATOR_URL
588 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700589
590 resource_mock = mock.MagicMock()
591 self.compute_client._service.instances = mock.MagicMock(
592 return_value=resource_mock)
593 resource_mock.insert = mock.MagicMock()
594
595 expected_body = {
596 "machineType":
597 self.MACHINE_TYPE_URL,
598 "name":
599 self.INSTANCE,
600 "networkInterfaces": [{
Kevin Cheng480e1212018-10-24 00:23:30 -0700601 "network": self.NETWORK_URL,
602 "subnetwork": self.SUBNETWORK_URL,
Kevin Chengb5963882018-05-09 00:06:27 -0700603 "accessConfigs": [{
604 "name": "External NAT",
605 "type": "ONE_TO_ONE_NAT"
606 }],
607 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700608 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700609 "serviceAccounts": [{
610 "email": "default",
611 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
612 }],
613 "scheduling": {
614 "onHostMaintenance": "terminate"
615 },
616 "guestAccelerators": [{
617 "acceleratorCount": 1,
618 "acceleratorType": "http://speedy-gpu"
619 }],
620 "metadata": {
621 "items": [{
622 "key": self.METADATA[0],
623 "value": self.METADATA[1]
624 }],
625 },
626 }
627
628 self.compute_client.CreateInstance(
629 instance=self.INSTANCE,
630 image_name=self.IMAGE,
631 machine_type=self.MACHINE_TYPE,
632 metadata={self.METADATA[0]: self.METADATA[1]},
633 network=self.NETWORK,
634 zone=self.ZONE,
635 gpu=self.GPU)
636
637 resource_mock.insert.assert_called_with(
638 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700639 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700640 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
641 scope_name=self.ZONE)
642
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700643 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
644 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700645 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700646 resource_mock = mock.MagicMock()
647 self.compute_client._service.instances = mock.MagicMock(
648 return_value=resource_mock)
649 resource_mock.delete = mock.MagicMock()
650 self.compute_client.DeleteInstance(
651 instance=self.INSTANCE, zone=self.ZONE)
652 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700653 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700654 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700655 mock.ANY,
656 operation_scope=gcompute_client.OperationScope.ZONE,
657 scope_name=self.ZONE)
658
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700659 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
660 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700661 """Test DeleteInstances."""
662 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700663 fake_instances = ["fake_instance_1", "fake_instance_2"]
664 mock_api = mock.MagicMock()
665 resource_mock = mock.MagicMock()
666 self.compute_client._service.instances = mock.MagicMock(
667 return_value=resource_mock)
668 resource_mock.delete = mock.MagicMock(return_value=mock_api)
669 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
670 fake_instances, self.ZONE)
671 calls = [
672 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700673 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700674 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700675 zone=self.ZONE),
676 mock.call(
677 project=PROJECT,
678 instance="fake_instance_2",
679 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700680 ]
681 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700682 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700683 self.assertEqual(error_msgs, [])
684 self.assertEqual(failed, [])
685 self.assertEqual(set(deleted), set(fake_instances))
686
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700687 def testCreateDiskWithProject(self):
688 """Test CreateDisk with images using a set project."""
689 source_project = "fake-image-project"
690 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700691 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700692 resource_mock = mock.MagicMock()
693 self.compute_client._service.disks = mock.MagicMock(
694 return_value=resource_mock)
695 resource_mock.insert = mock.MagicMock()
696 self.compute_client.CreateDisk(
697 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
698 resource_mock.insert.assert_called_with(
699 project=PROJECT,
700 zone=self.ZONE,
701 sourceImage="projects/%s/global/images/fake_image" %
702 expected_project_to_use,
703 body={
704 "name":
705 "fake_disk",
706 "sizeGb":
707 10,
708 "type":
709 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
710 self.ZONE)
711 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700712 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700713
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700714 def testCreateDiskWithNoSourceProject(self):
715 """Test CreateDisk with images with no set project."""
716 source_project = None
717 expected_project_to_use = PROJECT
718 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
719 resource_mock = mock.MagicMock()
720 self.compute_client._service.disks = mock.MagicMock(
721 return_value=resource_mock)
722 resource_mock.insert = mock.MagicMock()
723 self.compute_client.CreateDisk(
724 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
725 resource_mock.insert.assert_called_with(
726 project=PROJECT,
727 zone=self.ZONE,
728 sourceImage="projects/%s/global/images/fake_image" %
729 expected_project_to_use,
730 body={
731 "name":
732 "fake_disk",
733 "sizeGb":
734 10,
735 "type":
736 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
737 self.ZONE)
738 })
739 self.assertTrue(mock_wait.called)
740
741 def testCreateDiskWithTypeStandard(self):
742 """Test CreateDisk with images using standard."""
743 disk_type = gcompute_client.PersistentDiskType.STANDARD
744 expected_disk_type_string = "pd-standard"
745 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
746 resource_mock = mock.MagicMock()
747 self.compute_client._service.disks = mock.MagicMock(
748 return_value=resource_mock)
749 resource_mock.insert = mock.MagicMock()
750 self.compute_client.CreateDisk(
751 "fake_disk",
752 "fake_image",
753 10,
754 self.ZONE,
755 source_project="fake-project",
756 disk_type=disk_type)
757 resource_mock.insert.assert_called_with(
758 project=PROJECT,
759 zone=self.ZONE,
760 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
761 body={
762 "name":
763 "fake_disk",
764 "sizeGb":
765 10,
766 "type":
767 "projects/%s/zones/%s/diskTypes/%s" %
768 (PROJECT, self.ZONE, expected_disk_type_string)
769 })
770 self.assertTrue(mock_wait.called)
771
772 def testCreateDiskWithTypeSSD(self):
773 """Test CreateDisk with images using standard."""
774 disk_type = gcompute_client.PersistentDiskType.SSD
775 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700776 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700777 resource_mock = mock.MagicMock()
778 self.compute_client._service.disks = mock.MagicMock(
779 return_value=resource_mock)
780 resource_mock.insert = mock.MagicMock()
781 self.compute_client.CreateDisk(
782 "fake_disk",
783 "fake_image",
784 10,
785 self.ZONE,
786 source_project="fake-project",
787 disk_type=disk_type)
788 resource_mock.insert.assert_called_with(
789 project=PROJECT,
790 zone=self.ZONE,
791 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
792 body={
793 "name":
794 "fake_disk",
795 "sizeGb":
796 10,
797 "type":
798 "projects/%s/zones/%s/diskTypes/%s" %
799 (PROJECT, self.ZONE, expected_disk_type_string)
800 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700801 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700802
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700803 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
804 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700805 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700806 resource_mock = mock.MagicMock()
807 self.compute_client._service.instances = mock.MagicMock(
808 return_value=resource_mock)
809 resource_mock.attachDisk = mock.MagicMock()
810 self.compute_client.AttachDisk(
811 "fake_instance_1", self.ZONE, deviceName="fake_disk",
812 source="fake-selfLink")
813 resource_mock.attachDisk.assert_called_with(
814 project=PROJECT,
815 zone=self.ZONE,
816 instance="fake_instance_1",
817 body={
818 "deviceName": "fake_disk",
819 "source": "fake-selfLink"
820 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700821 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700822
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700823 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
824 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700825 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700826 resource_mock = mock.MagicMock()
827 self.compute_client._service.instances = mock.MagicMock(
828 return_value=resource_mock)
829 resource_mock.detachDisk = mock.MagicMock()
830 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
831 resource_mock.detachDisk.assert_called_with(
832 project=PROJECT,
833 zone=self.ZONE,
834 instance="fake_instance_1",
835 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700836 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700837
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700838 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
839 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
840 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700841 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700842 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700843 resource_mock = mock.MagicMock()
844 self.compute_client._service.instances = mock.MagicMock(
845 return_value=resource_mock)
846 resource_mock.attachAccelerator = mock.MagicMock()
847 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
848 "nvidia-tesla-k80")
849 resource_mock.setMachineResources.assert_called_with(
850 project=PROJECT,
851 zone=self.ZONE,
852 instance="fake_instance_1",
853 body={
854 "guestAccelerators": [{
855 "acceleratorType": self.ACCELERATOR_URL,
856 "acceleratorCount": 1
857 }]
858 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700859 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700860
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700861 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
862 def testBatchExecuteOnInstances(self, mock_wait):
863 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700864 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700865 action = mock.MagicMock(return_value=mock.MagicMock())
866 fake_instances = ["fake_instance_1", "fake_instance_2"]
867 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
868 fake_instances, self.ZONE, action)
869 calls = [mock.call(instance="fake_instance_1"),
870 mock.call(instance="fake_instance_2")]
871 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700872 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700873 self.assertEqual(set(done), set(fake_instances))
874 self.assertEqual(error_msgs, [])
875 self.assertEqual(failed, [])
876
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700877 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
878 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700879 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700880 resource_mock = mock.MagicMock()
881 self.compute_client._service.instances = mock.MagicMock(
882 return_value=resource_mock)
883 resource_mock.reset = mock.MagicMock()
884 self.compute_client.ResetInstance(
885 instance=self.INSTANCE, zone=self.ZONE)
886 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700887 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700888 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700889 mock.ANY,
890 operation_scope=gcompute_client.OperationScope.ZONE,
891 scope_name=self.ZONE)
892
893 def _CompareMachineSizeTestHelper(self,
894 machine_info_1,
895 machine_info_2,
896 expected_result=None,
897 expected_error_type=None):
898 """Helper class for testing CompareMachineSize.
899
Kevin Chengb5963882018-05-09 00:06:27 -0700900 Args:
901 machine_info_1: A dictionary representing the first machine size.
902 machine_info_2: A dictionary representing the second machine size.
903 expected_result: An integer, 0, 1 or -1, or None if not set.
904 expected_error_type: An exception type, if set will check for exception.
905 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700906 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -0700907 gcompute_client.ComputeClient,
908 "GetMachineType",
909 side_effect=[machine_info_1, machine_info_2])
910 if expected_error_type:
911 self.assertRaises(expected_error_type,
912 self.compute_client.CompareMachineSize, "name1",
913 "name2", self.ZONE)
914 else:
915 result = self.compute_client.CompareMachineSize("name1", "name2",
916 self.ZONE)
917 self.assertEqual(result, expected_result)
918
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700919 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -0700920 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
921
922 def testCompareMachineSizeSmall(self):
923 """Test CompareMachineSize where the first one is smaller."""
924 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
925 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
926 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
927
Kevin Cheng4ae42772018-10-02 11:39:48 -0700928 def testCompareMachineSizeSmallSmallerOnSecond(self):
929 """Test CompareMachineSize where the first one is smaller."""
930 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
931 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
932 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
933
Tri Vo29ac1822016-10-01 17:06:29 -0700934 def testCompareMachineSizeLarge(self):
935 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -0700936 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
937 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
938 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
939
940 def testCompareMachineSizeLargeWithEqualElement(self):
941 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -0700942 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
943 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
944 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
945
946 def testCompareMachineSizeEqual(self):
947 """Test CompareMachineSize where two machine sizes are equal."""
948 machine_info = {"guestCpus": 10, "memoryMb": 100}
949 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
950
951 def testCompareMachineSizeBadMetric(self):
952 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -0700953 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -0700954 self._CompareMachineSizeTestHelper(
955 machine_info, machine_info, expected_error_type=errors.DriverError)
956
957 def testGetMachineType(self):
958 """Test GetMachineType."""
959 resource_mock = mock.MagicMock()
960 mock_api = mock.MagicMock()
961 self.compute_client._service.machineTypes = mock.MagicMock(
962 return_value=resource_mock)
963 resource_mock.get = mock.MagicMock(return_value=mock_api)
964 mock_api.execute = mock.MagicMock(
965 return_value={"name": self.MACHINE_TYPE})
966 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
967 self.ZONE)
968 self.assertEqual(result, {"name": self.MACHINE_TYPE})
969 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700970 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700971 zone=self.ZONE,
972 machineType=self.MACHINE_TYPE)
973
974 def _GetSerialPortOutputTestHelper(self, response):
975 """Helper function for testing GetSerialPortOutput.
976
Kevin Chengb5963882018-05-09 00:06:27 -0700977 Args:
978 response: A dictionary representing a fake response.
979 """
Tri Vo29ac1822016-10-01 17:06:29 -0700980 resource_mock = mock.MagicMock()
981 mock_api = mock.MagicMock()
982 self.compute_client._service.instances = mock.MagicMock(
983 return_value=resource_mock)
984 resource_mock.getSerialPortOutput = mock.MagicMock(
985 return_value=mock_api)
986 mock_api.execute = mock.MagicMock(return_value=response)
987
988 if "contents" in response:
989 result = self.compute_client.GetSerialPortOutput(
990 instance=self.INSTANCE, zone=self.ZONE)
991 self.assertEqual(result, "fake contents")
992 else:
993 self.assertRaisesRegexp(
994 errors.DriverError,
995 "Malformed response.*",
996 self.compute_client.GetSerialPortOutput,
997 instance=self.INSTANCE,
998 zone=self.ZONE)
999 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001000 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001001 zone=self.ZONE,
1002 instance=self.INSTANCE,
1003 port=1)
1004
1005 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001006 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -07001007 response = {"contents": "fake contents"}
1008 self._GetSerialPortOutputTestHelper(response)
1009
1010 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001011 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -07001012 response = {"malformed": "fake contents"}
1013 self._GetSerialPortOutputTestHelper(response)
1014
1015 def testGetInstanceNamesByIPs(self):
1016 """Test GetInstanceNamesByIPs."""
1017 good_instance = {
1018 "name": "instance_1",
1019 "networkInterfaces": [
1020 {
1021 "accessConfigs": [
1022 {"natIP": "172.22.22.22"},
1023 ],
1024 },
1025 ],
1026 }
1027 bad_instance = {"name": "instance_2"}
1028 self.Patch(
1029 gcompute_client.ComputeClient,
1030 "ListInstances",
1031 return_value=[good_instance, bad_instance])
1032 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
1033 ips=["172.22.22.22", "172.22.22.23"], zone=self.ZONE)
1034 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1035 "172.22.22.23": None})
1036
cylan64af2db2019-01-17 15:13:59 +08001037 def testRsaNotInMetadata(self):
1038 """Test rsa not in metadata."""
Tri Vo29ac1822016-10-01 17:06:29 -07001039 fake_user = "fake_user"
cylan64af2db2019-01-17 15:13:59 +08001040 fake_ssh_key = "fake_ssh"
1041 metadata = {
1042 "kind": "compute#metadata",
1043 "fingerprint": "a-23icsyx4E=",
1044 "items": [
1045 {
1046 "key": "sshKeys",
1047 "value": "%s:%s" % (fake_user, self.SSHKEY)
1048 }
1049 ]
1050 }
1051 # Test rsa doesn't exist in metadata.
1052 new_entry = "%s:%s" % (fake_user, fake_ssh_key)
1053 self.assertEqual(True, gcompute_client.RsaNotInMetadata(metadata, new_entry))
1054
1055 # Test rsa exists in metadata.
1056 exist_entry = "%s:%s" %(fake_user, self.SSHKEY)
1057 self.assertEqual(False, gcompute_client.RsaNotInMetadata(metadata, exist_entry))
1058
1059 def testGetSshKeyFromMetadata(self):
1060 """Test get ssh key from metadata."""
1061 fake_user = "fake_user"
1062 metadata_key_exist_value_is_empty = {
1063 "kind": "compute#metadata",
1064 "fingerprint": "a-23icsyx4E=",
1065 "items": [
1066 {
1067 "key": "sshKeys",
1068 "value": ""
1069 }
1070 ]
1071 }
1072 metadata_key_exist = {
1073 "kind": "compute#metadata",
1074 "fingerprint": "a-23icsyx4E=",
1075 "items": [
1076 {
1077 "key": "sshKeys",
1078 "value": "%s:%s" % (fake_user, self.SSHKEY)
1079 }
1080 ]
1081 }
1082 metadata_key_not_exist = {
1083 "kind": "compute#metadata",
1084 "fingerprint": "a-23icsyx4E=",
1085 "items": [
1086 {
1087 }
1088 ]
1089 }
1090 expected_key_exist_value_is_empty = {
1091 "key": "sshKeys",
1092 "value": ""
1093 }
1094 expected_key_exist = {
1095 "key": "sshKeys",
1096 "value": "%s:%s" % (fake_user, self.SSHKEY)
1097 }
1098 self.assertEqual(expected_key_exist_value_is_empty,
1099 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist_value_is_empty))
1100 self.assertEqual(expected_key_exist,
1101 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist))
1102 self.assertEqual(None,
1103 gcompute_client.GetSshKeyFromMetadata(metadata_key_not_exist))
1104
1105
1106 def testGetRsaKeyPathExistsFalse(self):
1107 """Test the rsa key path not exists."""
1108 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1109 self.Patch(os.path, "exists", return_value=False)
1110 self.assertRaisesRegexp(errors.DriverError,
1111 "RSA file %s does not exist." % fake_ssh_rsa_path,
1112 gcompute_client.GetRsaKey,
1113 ssh_rsa_path=fake_ssh_rsa_path)
1114
1115 def testGetRsaKey(self):
1116 """Test get the rsa key."""
1117 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1118 self.Patch(os.path, "exists", return_value=True)
1119 m = mock.mock_open(read_data=self.SSHKEY)
1120 with mock.patch("__builtin__.open", m):
1121 result = gcompute_client.GetRsaKey(fake_ssh_rsa_path)
1122 self.assertEqual(self.SSHKEY, result)
1123
1124 def testUpdateRsaInMetadata(self):
1125 """Test update rsa in metadata."""
1126 fake_ssh_key = "fake_ssh"
1127 fake_metadata_sshkeys_not_exist = {
1128 "kind": "compute#metadata",
1129 "fingerprint": "a-23icsyx4E=",
1130 "items": [
1131 {
1132 "key": "not_sshKeys",
1133 "value": ""
1134 }
1135 ]
1136 }
1137 new_entry = "new_user:%s" % fake_ssh_key
1138 expected = {
1139 "kind": "compute#metadata",
1140 "fingerprint": "a-23icsyx4E=",
1141 "items": [
1142 {
1143 "key": "not_sshKeys",
1144 "value": ""
1145 },
1146 {
1147 "key": "sshKeys",
1148 "value": new_entry
1149 }
1150 ]
1151 }
1152 self.Patch(os.path, "exists", return_value=True)
1153 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1154 resource_mock = mock.MagicMock()
1155 self.compute_client.SetInstanceMetadata = mock.MagicMock(
1156 return_value=resource_mock)
1157 # Test the key item not exists in the metadata.
1158 self.compute_client.UpdateRsaInMetadata(
1159 "fake_zone",
1160 "fake_instance",
1161 fake_metadata_sshkeys_not_exist,
1162 new_entry)
1163 self.compute_client.SetInstanceMetadata.assert_called_with(
1164 "fake_zone",
1165 "fake_instance",
1166 expected)
1167
1168 # Test the key item exists in the metadata.
1169 fake_metadata_ssh_keys_exists = {
1170 "kind": "compute#metadata",
1171 "fingerprint": "a-23icsyx4E=",
1172 "items": [
1173 {
1174 "key": "sshKeys",
1175 "value": "old_user:%s" % self.SSHKEY
1176 }
1177 ]
1178 }
1179 expected_ssh_keys_exists = {
1180 "kind": "compute#metadata",
1181 "fingerprint": "a-23icsyx4E=",
1182 "items": [
1183 {
1184 "key": "sshKeys",
1185 "value": "old_user:%s\n%s" % (self.SSHKEY, new_entry)
1186 }
1187 ]
1188 }
1189
1190 self.compute_client.UpdateRsaInMetadata(
1191 "fake_zone",
1192 "fake_instance",
1193 fake_metadata_ssh_keys_exists,
1194 new_entry)
1195 self.compute_client.SetInstanceMetadata.assert_called_with(
1196 "fake_zone",
1197 "fake_instance",
1198 expected_ssh_keys_exists)
1199
1200 def testAddSshRsaToInstance(self):
1201 """Test add ssh rsa key to instance."""
1202 fake_user = "fake_user"
1203 instance_metadata_key_not_exist = {
1204 "metadata": {
Tri Vo29ac1822016-10-01 17:06:29 -07001205 "kind": "compute#metadata",
1206 "fingerprint": "a-23icsyx4E=",
1207 "items": [
1208 {
1209 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001210 "value": ""
1211 }
1212 ]
1213 }
1214 }
1215 instance_metadata_key_exist = {
1216 "metadata": {
1217 "kind": "compute#metadata",
1218 "fingerprint": "a-23icsyx4E=",
1219 "items": [
1220 {
1221 "key": "sshKeys",
1222 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001223 }
1224 ]
1225 }
1226 }
1227 expected = {
1228 "kind": "compute#metadata",
1229 "fingerprint": "a-23icsyx4E=",
1230 "items": [
1231 {
1232 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001233 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001234 }
1235 ]
1236 }
1237
1238 self.Patch(os.path, "exists", return_value=True)
cylan64af2db2019-01-17 15:13:59 +08001239 m = mock.mock_open(read_data=self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001240 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -07001241 resource_mock = mock.MagicMock()
cylan64af2db2019-01-17 15:13:59 +08001242 self.compute_client._service.instances = mock.MagicMock(
Tri Vo29ac1822016-10-01 17:06:29 -07001243 return_value=resource_mock)
cylan64af2db2019-01-17 15:13:59 +08001244 resource_mock.setMetadata = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001245
cylan64af2db2019-01-17 15:13:59 +08001246 # Test the key not exists in the metadata.
Tri Vo29ac1822016-10-01 17:06:29 -07001247 self.Patch(
cylan64af2db2019-01-17 15:13:59 +08001248 gcompute_client.ComputeClient, "GetInstance",
1249 return_value=instance_metadata_key_not_exist)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001250 with mock.patch("__builtin__.open", m):
cylan64af2db2019-01-17 15:13:59 +08001251 self.compute_client.AddSshRsaInstanceMetadata(
1252 "fake_zone",
1253 fake_user,
1254 "/path/to/test_rsa.pub",
1255 "fake_instance")
1256 resource_mock.setMetadata.assert_called_with(
1257 project=PROJECT,
1258 zone="fake_zone",
1259 instance="fake_instance",
1260 body=expected)
1261
1262 # Test the key already exists in the metadata.
1263 resource_mock.setMetadata.call_count = 0
1264 self.Patch(
1265 gcompute_client.ComputeClient, "GetInstance",
1266 return_value=instance_metadata_key_exist)
1267 with mock.patch("__builtin__.open", m):
1268 self.compute_client.AddSshRsaInstanceMetadata(
1269 "fake_zone",
1270 fake_user,
1271 "/path/to/test_rsa.pub",
1272 "fake_instance")
1273 resource_mock.setMetadata.assert_not_called()
Tri Vo29ac1822016-10-01 17:06:29 -07001274
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001275 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1276 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001277 """Test DeleteDisks."""
1278 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001279 fake_disks = ["fake_disk_1", "fake_disk_2"]
1280 mock_api = mock.MagicMock()
1281 resource_mock = mock.MagicMock()
1282 self.compute_client._service.disks = mock.MagicMock(
1283 return_value=resource_mock)
1284 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1285 # Call the API.
1286 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1287 fake_disks, zone=self.ZONE)
1288 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001289 calls = [
1290 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1291 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1292 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001293 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001294 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001295 self.assertEqual(error_msgs, [])
1296 self.assertEqual(failed, [])
1297 self.assertEqual(set(deleted), set(fake_disks))
1298
Kevin Chengb5963882018-05-09 00:06:27 -07001299 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001300 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001301 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1302 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001303 """Raise 412 HTTP exception."""
1304 if not sentinel.hitFingerPrintConflict.called:
1305 sentinel.hitFingerPrintConflict()
1306 raise errors.HttpError(412, "resource labels have changed")
1307 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001308
1309 sentinel = mock.MagicMock()
1310 result = Raise412(sentinel)
1311 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1312 self.assertEqual("Passed", result)
1313
Tri Vo29ac1822016-10-01 17:06:29 -07001314
1315if __name__ == "__main__":
1316 unittest.main()