gcloud 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data.tar.gz.sig +2 -3
  2. data/CHANGELOG +4 -0
  3. data/LICENSE +674 -0
  4. data/Manifest +111 -0
  5. data/README.md +4 -3
  6. data/bin/gcutil +53 -0
  7. data/gcloud.gemspec +4 -3
  8. data/packages/gcutil-1.7.1/CHANGELOG +197 -0
  9. data/packages/gcutil-1.7.1/LICENSE +202 -0
  10. data/packages/gcutil-1.7.1/VERSION +1 -0
  11. data/packages/gcutil-1.7.1/gcutil +53 -0
  12. data/packages/gcutil-1.7.1/lib/google_api_python_client/LICENSE +23 -0
  13. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/__init__.py +1 -0
  14. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/discovery.py +743 -0
  15. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/errors.py +123 -0
  16. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/ext/__init__.py +0 -0
  17. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/http.py +1443 -0
  18. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/mimeparse.py +172 -0
  19. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/model.py +385 -0
  20. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/schema.py +303 -0
  21. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/__init__.py +1 -0
  22. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/anyjson.py +32 -0
  23. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/appengine.py +528 -0
  24. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/client.py +1139 -0
  25. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/clientsecrets.py +105 -0
  26. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/crypt.py +244 -0
  27. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/django_orm.py +124 -0
  28. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/file.py +107 -0
  29. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/locked_file.py +343 -0
  30. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/multistore_file.py +379 -0
  31. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/tools.py +174 -0
  32. data/packages/gcutil-1.7.1/lib/google_api_python_client/uritemplate/__init__.py +147 -0
  33. data/packages/gcutil-1.7.1/lib/google_apputils/LICENSE +202 -0
  34. data/packages/gcutil-1.7.1/lib/google_apputils/google/__init__.py +3 -0
  35. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/__init__.py +3 -0
  36. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/app.py +356 -0
  37. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/appcommands.py +783 -0
  38. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/basetest.py +1260 -0
  39. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/datelib.py +421 -0
  40. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/debug.py +60 -0
  41. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/file_util.py +181 -0
  42. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/resources.py +67 -0
  43. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/run_script_module.py +217 -0
  44. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/setup_command.py +159 -0
  45. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/shellutil.py +49 -0
  46. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/stopwatch.py +204 -0
  47. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/__init__.py +0 -0
  48. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper.py +140 -0
  49. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper_test.py +149 -0
  50. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth.py +130 -0
  51. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth_test.py +75 -0
  52. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds.py +128 -0
  53. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds_test.py +111 -0
  54. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base.py +1808 -0
  55. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base_test.py +1651 -0
  56. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta13.json +2851 -0
  57. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta14.json +3361 -0
  58. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds.py +342 -0
  59. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds_test.py +474 -0
  60. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds.py +344 -0
  61. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds_test.py +231 -0
  62. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/flags_cache.py +274 -0
  63. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil +89 -0
  64. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil_logging.py +69 -0
  65. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds.py +262 -0
  66. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds_test.py +172 -0
  67. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds.py +1506 -0
  68. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds_test.py +1904 -0
  69. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds.py +91 -0
  70. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds_test.py +56 -0
  71. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds.py +106 -0
  72. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds_test.py +59 -0
  73. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata.py +96 -0
  74. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_lib.py +357 -0
  75. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_test.py +84 -0
  76. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_api.py +420 -0
  77. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_metadata.py +58 -0
  78. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.py +824 -0
  79. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds_test.py +307 -0
  80. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds.py +178 -0
  81. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds_test.py +133 -0
  82. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds.py +181 -0
  83. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds_test.py +196 -0
  84. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/path_initializer.py +38 -0
  85. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds.py +173 -0
  86. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds_test.py +111 -0
  87. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes.py +61 -0
  88. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes_test.py +50 -0
  89. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds.py +276 -0
  90. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds_test.py +260 -0
  91. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys.py +266 -0
  92. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys_test.py +128 -0
  93. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/table_formatter.py +563 -0
  94. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool.py +188 -0
  95. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool_test.py +88 -0
  96. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils.py +208 -0
  97. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils_test.py +193 -0
  98. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version.py +17 -0
  99. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker.py +246 -0
  100. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker_test.py +271 -0
  101. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds.py +151 -0
  102. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds_test.py +60 -0
  103. data/packages/gcutil-1.7.1/lib/httplib2/LICENSE +21 -0
  104. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/__init__.py +1630 -0
  105. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/cacerts.txt +714 -0
  106. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/iri2uri.py +110 -0
  107. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/socks.py +438 -0
  108. data/packages/gcutil-1.7.1/lib/iso8601/LICENSE +20 -0
  109. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/__init__.py +1 -0
  110. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/iso8601.py +102 -0
  111. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/test_iso8601.py +111 -0
  112. data/packages/gcutil-1.7.1/lib/python_gflags/AUTHORS +2 -0
  113. data/packages/gcutil-1.7.1/lib/python_gflags/LICENSE +28 -0
  114. data/packages/gcutil-1.7.1/lib/python_gflags/gflags.py +2862 -0
  115. data/packages/gcutil-1.7.1/lib/python_gflags/gflags2man.py +544 -0
  116. data/packages/gcutil-1.7.1/lib/python_gflags/gflags_validators.py +187 -0
  117. metadata +118 -5
  118. metadata.gz.sig +0 -0
@@ -0,0 +1,1904 @@
1
+ #!/usr/bin/python
2
+ #
3
+ # Copyright 2012 Google Inc. All Rights Reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ """Unit tests for the instance commands."""
18
+
19
+ from __future__ import with_statement
20
+
21
+
22
+
23
+ import path_initializer
24
+ path_initializer.InitializeSysPath()
25
+
26
+ import base64
27
+ import copy
28
+ import logging
29
+ import sys
30
+ import tempfile
31
+
32
+ from google.apputils import app
33
+ import gflags as flags
34
+ import unittest
35
+
36
+ from gcutil import command_base
37
+ from gcutil import gcutil_logging
38
+ from gcutil import instance_cmds
39
+ from gcutil import mock_api
40
+
41
+
42
+ FLAGS = flags.FLAGS
43
+ LOGGER = gcutil_logging.LOGGER
44
+
45
+
46
+ class InstanceCmdsTest(unittest.TestCase):
47
+
48
+ def setUp(self):
49
+ self._projects = mock_api.MockProjectsApi()
50
+ self._instances = mock_api.MockInstancesApi()
51
+ self._machine_types = mock_api.MockMachineTypesApi()
52
+ self._zones = mock_api.MockZonesApi()
53
+ self._disks = mock_api.MockDisksApi()
54
+ self._images = mock_api.MockImagesApi()
55
+
56
+ self._projects.get = mock_api.CommandExecutor(
57
+ {'externalIpAddresses': ['192.0.2.2', '192.0.2.3', '192.0.2.4']})
58
+
59
+ self._zones.list = mock_api.CommandExecutor(
60
+ {'kind': 'compute#zoneList',
61
+ 'items': [{'name': 'zone1'},
62
+ {'name': 'zone2'}]})
63
+
64
+ # This response is used for 'instances.list' on certain add calls.
65
+ self._instance_list = {
66
+ 'items': [
67
+ {'name': 'foo',
68
+ 'networkInterfaces': [{'accessConfigs': [{'type': 'ONE_TO_ONE_NAT',
69
+ 'natIP': '192.0.2.2'}]}]
70
+ },
71
+ {'name': 'bar',
72
+ 'networkInterfaces': [{'accessConfigs': [{'type': 'ONE_TO_ONE_NAT',
73
+ 'natIP': '192.0.2.3'}]}]
74
+ },
75
+ ]}
76
+
77
+ def _DoTestAddInstanceGeneratesCorrectRequest(self, service_version):
78
+ flag_values = copy.deepcopy(FLAGS)
79
+
80
+ command = instance_cmds.AddInstance('addinstance', flag_values)
81
+
82
+ expected_project = 'test_project'
83
+ expected_instance = 'test_instance'
84
+ expected_description = 'test instance'
85
+ submitted_image = 'expected_image'
86
+ submitted_kernel = 'expected_kernel'
87
+ submitted_machine_type = 'goes_to_11'
88
+ submitted_zone = 'copernicus-moon-base'
89
+
90
+ expected_authorized_ssh_keys = []
91
+ flag_values.service_version = service_version
92
+ flag_values.zone = submitted_zone
93
+ flag_values.machine_type = submitted_machine_type
94
+ flag_values.project = expected_project
95
+ flag_values.description = expected_description
96
+ flag_values.image = submitted_image
97
+ flag_values.kernel = submitted_kernel
98
+ flag_values.use_compute_key = False
99
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
100
+ flag_values.add_compute_key_to_project = False
101
+
102
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
103
+
104
+ command.SetFlags(flag_values)
105
+ command._projects_api = self._projects
106
+ command._instances_api = self._instances
107
+ command._zones_api = self._zones
108
+ command._credential = mock_api.MockCredential()
109
+
110
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
111
+ 'images',
112
+ submitted_image)
113
+ expected_kernel = command.NormalizeGlobalResourceName(expected_project,
114
+ 'kernels',
115
+ submitted_kernel)
116
+
117
+ expected_zone = command.NormalizeTopLevelResourceName(
118
+ expected_project,
119
+ 'zones',
120
+ submitted_zone)
121
+
122
+ (results, exceptions) = command.Handle(expected_instance)
123
+ result = results['items'][0]
124
+
125
+ expected_kind = command._GetResourceApiKind('instance')
126
+
127
+ self.assertEqual(result['project'], expected_project)
128
+ self.assertEqual(result['body']['kind'], expected_kind)
129
+ self.assertEqual(result['body']['name'], expected_instance)
130
+ self.assertEqual(result['body']['description'], expected_description)
131
+ self.assertEqual(result['body']['image'], expected_image)
132
+ self.assertEqual(result['body']['kernel'], expected_kernel)
133
+ self.assertFalse(
134
+ 'natIP' in result['body']['networkInterfaces'][0]['accessConfigs'][0],
135
+ result)
136
+ self.assertEqual(exceptions, [])
137
+
138
+ self.assertEqual(result['body'].get('metadata'), {
139
+ 'kind': 'compute#metadata',
140
+ 'items': []})
141
+
142
+ instance_tags = result['body'].get('tags', [])
143
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
144
+ instance_tags = result['body'].get('tags', {}).get('items', [])
145
+ self.assertEqual(instance_tags, [])
146
+
147
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
148
+ self.assertEqual(submitted_zone, result['zone'])
149
+ self.assertFalse('zone' in result['body'])
150
+ else:
151
+ self.assertFalse('zone' in result)
152
+ self.assertEqual(result['body']['zone'], expected_zone)
153
+
154
+ def testAddInstanceGeneratesCorrectRequest(self):
155
+ for version in command_base.SUPPORTED_VERSIONS:
156
+ self._DoTestAddInstanceGeneratesCorrectRequest(version)
157
+
158
+ def _DoTestAddMultipleInstances(self, service_version):
159
+ flag_values = copy.deepcopy(FLAGS)
160
+
161
+ command = instance_cmds.AddInstance('addinstance', flag_values)
162
+
163
+ expected_project = 'test_project'
164
+ expected_instances = ['test-instance-%02d' % i for i in xrange(100)]
165
+ expected_description = 'test instance'
166
+ submitted_image = 'expected_image'
167
+ submitted_machine_type = 'goes_to_11'
168
+ submitted_zone = 'copernicus-moon-base'
169
+
170
+ expected_authorized_ssh_keys = []
171
+ flag_values.service_version = service_version
172
+ flag_values.zone = submitted_zone
173
+ flag_values.machine_type = submitted_machine_type
174
+ flag_values.project = expected_project
175
+ flag_values.description = expected_description
176
+ flag_values.image = submitted_image
177
+ flag_values.use_compute_key = False
178
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
179
+ flag_values.add_compute_key_to_project = False
180
+
181
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
182
+
183
+ command.SetFlags(flag_values)
184
+ command._projects_api = self._projects
185
+ command._instances_api = self._instances
186
+ command._zones_api = self._zones
187
+ command._credential = mock_api.MockCredential()
188
+
189
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
190
+ 'images',
191
+ submitted_image)
192
+
193
+ expected_zone = command.NormalizeTopLevelResourceName(
194
+ expected_project,
195
+ 'zones',
196
+ submitted_zone)
197
+
198
+ (results, exceptions) = command.Handle(*expected_instances)
199
+
200
+ self.assertEqual(exceptions, [])
201
+ results = results['items']
202
+ self.assertEqual(len(results), len(expected_instances))
203
+
204
+ for (expected_instance, result) in zip(expected_instances, results):
205
+ expected_kind = command._GetResourceApiKind('instance')
206
+
207
+ self.assertEqual(result['project'], expected_project)
208
+ self.assertEqual(result['body']['kind'], expected_kind)
209
+ self.assertEqual(result['body']['name'], expected_instance)
210
+ self.assertEqual(result['body']['description'], expected_description)
211
+ self.assertEqual(result['body']['image'], expected_image)
212
+ self.assertFalse(
213
+ 'natIP' in result['body']['networkInterfaces'][0]['accessConfigs'][0],
214
+ result)
215
+
216
+ self.assertEqual(result['body'].get('metadata'), {
217
+ 'kind': 'compute#metadata',
218
+ 'items': []})
219
+
220
+ instance_tags = result['body'].get('tags', [])
221
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
222
+ instance_tags = result['body'].get('tags', {}).get('items', [])
223
+ self.assertFalse('zone' in result['body'])
224
+ else:
225
+ self.assertEqual(result['body']['zone'], expected_zone)
226
+ self.assertEqual(instance_tags, [])
227
+
228
+ def testAddMultipleInstances(self):
229
+ for version in command_base.SUPPORTED_VERSIONS:
230
+ self._DoTestAddMultipleInstances(version)
231
+
232
+
233
+ def testAddInstanceWithDiskOptionsGeneratesCorrectRequest(self):
234
+ flag_values = copy.deepcopy(FLAGS)
235
+
236
+ command = instance_cmds.AddInstance('addinstance', flag_values)
237
+
238
+ service_version = command_base.CURRENT_VERSION
239
+ expected_instance = 'test_instance'
240
+ submitted_image = 'image-foo'
241
+ submitted_zone = 'copernicus-moon-base'
242
+ submitted_disk_old_name = 'disk123:name123'
243
+ submitted_disk_name = 'disk234,deviceName=name234'
244
+ submitted_disk_read_only = 'disk345,mode=READ_ONLY'
245
+ submitted_disk_read_write = 'disk456,mode=READ_WRITE'
246
+ submitted_disk_name_read_only = 'disk567,deviceName=name567,mode=READ_ONLY'
247
+ submitted_disk_no_name = 'disk678'
248
+ submitted_disk_full_name = ('http://www.googleapis.com/compute/v1beta13/'
249
+ 'projects/google.com:test/disks/disk789')
250
+ submitted_disk_ro = 'disk890,mode=ro'
251
+ submitted_disk_rw = 'disk90A,mode=rw'
252
+ submitted_machine_type = 'goes_to_11'
253
+
254
+ expected_authorized_ssh_keys = []
255
+ flag_values.service_version = service_version
256
+
257
+ flag_values.disk = [submitted_disk_old_name,
258
+ submitted_disk_name,
259
+ submitted_disk_read_only,
260
+ submitted_disk_read_write,
261
+ submitted_disk_name_read_only,
262
+ submitted_disk_no_name,
263
+ submitted_disk_full_name + ',mode=READ_WRITE',
264
+ submitted_disk_ro,
265
+ submitted_disk_rw]
266
+ flag_values.machine_type = submitted_machine_type
267
+ flag_values.use_compute_key = False
268
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
269
+ flag_values.add_compute_key_to_project = False
270
+ flag_values.image = submitted_image
271
+ flag_values.zone = submitted_zone
272
+
273
+ disk_zone = 'zones/copernicus-moon-base'
274
+
275
+ self._disks.get = mock_api.CommandExecutor(
276
+ {'zone': disk_zone})
277
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
278
+ command._zones_api = self._zones
279
+
280
+ command.SetFlags(flag_values)
281
+ command._projects_api = self._projects
282
+ command._instances_api = self._instances
283
+ command._disks_api = self._disks
284
+ command._zones_api = self._zones
285
+ command._images_api = self._images
286
+ command._credential = mock_api.MockCredential()
287
+
288
+ (results, exceptions) = command.Handle(expected_instance)
289
+ result = results['items'][0]
290
+
291
+ disk = result['body']['disks'][0]
292
+ self.assertEqual(disk['deviceName'], 'name123')
293
+ self.assertEqual(disk['mode'], 'READ_WRITE')
294
+ disk = result['body']['disks'][1]
295
+ self.assertEqual(disk['deviceName'], 'name234')
296
+ self.assertEqual(disk['mode'], 'READ_WRITE')
297
+ disk = result['body']['disks'][2]
298
+ self.assertEqual(disk['deviceName'], 'disk345')
299
+ self.assertEqual(disk['mode'], 'READ_ONLY')
300
+ disk = result['body']['disks'][3]
301
+ self.assertEqual(disk['deviceName'], 'disk456')
302
+ self.assertEqual(disk['mode'], 'READ_WRITE')
303
+ disk = result['body']['disks'][4]
304
+ self.assertEqual(disk['deviceName'], 'name567')
305
+ self.assertEqual(disk['mode'], 'READ_ONLY')
306
+ disk = result['body']['disks'][5]
307
+ self.assertEqual(disk['deviceName'], submitted_disk_no_name)
308
+ self.assertEqual(disk['mode'], 'READ_WRITE')
309
+ disk = result['body']['disks'][6]
310
+ self.assertEqual(disk['deviceName'], submitted_disk_full_name)
311
+ self.assertEqual(disk['mode'], 'READ_WRITE')
312
+ disk = result['body']['disks'][7]
313
+ self.assertEqual(disk['deviceName'], 'disk890')
314
+ self.assertEqual(disk['mode'], 'READ_ONLY')
315
+ disk = result['body']['disks'][8]
316
+ self.assertEqual(disk['deviceName'], 'disk90A')
317
+ self.assertEqual(disk['mode'], 'READ_WRITE')
318
+ self.assertEqual(exceptions, [])
319
+
320
+ def testAddInstanceWithBootDiskOptionsGeneratesCorrectRequest(self):
321
+ flag_values = copy.deepcopy(FLAGS)
322
+
323
+ command = instance_cmds.AddInstance('addinstance', flag_values)
324
+
325
+ service_version = 'v1beta14'
326
+ expected_instance = 'test_instance'
327
+ submitted_boot_disk_unqualified = 'diskA,boot'
328
+ submitted_boot_disk_ro = 'diskB,mode=ro,boot'
329
+ submitted_boot_disk_rw = 'diskC,mode=rw,boot'
330
+ submitted_non_boot_disk = 'diskD'
331
+ submitted_machine_type = 'goes_to_11'
332
+ submitted_kernel = 'projects/google/kernels/some-kernel'
333
+
334
+ expected_authorized_ssh_keys = []
335
+ flag_values.service_version = service_version
336
+
337
+ flag_values.disk = [submitted_boot_disk_unqualified,
338
+ submitted_boot_disk_ro,
339
+ submitted_boot_disk_rw,
340
+ submitted_non_boot_disk]
341
+ flag_values.machine_type = submitted_machine_type
342
+ flag_values.use_compute_key = False
343
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
344
+ flag_values.add_compute_key_to_project = False
345
+ flag_values.kernel = submitted_kernel
346
+
347
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
348
+
349
+ # When no zone is provided, GCUtil will do a list
350
+ disk_zone = 'zone1'
351
+ disk_list_with_zone = {
352
+ 'items': [
353
+ {'selfLink': 'projects/foo/zones/%s/disks/baz' % disk_zone},
354
+ ]}
355
+ self._disks.list = mock_api.CommandExecutor(disk_list_with_zone)
356
+
357
+ # Override to return a single zone so that we don't find multiple
358
+ # disks with the same name
359
+ self._zones.list = mock_api.CommandExecutor(
360
+ {'kind': 'compute#zoneList',
361
+ 'items': [{'name': 'zone1'}]})
362
+
363
+ command.SetFlags(flag_values)
364
+ command._projects_api = self._projects
365
+ command._instances_api = self._instances
366
+ command._disks_api = self._disks
367
+ command._zones_api = self._zones
368
+ command._credential = mock_api.MockCredential()
369
+
370
+ (results, exceptions) = command.Handle(expected_instance)
371
+ result = results['items'][0]
372
+
373
+ disk = result['body']['disks'][0]
374
+ self.assertEqual(disk['deviceName'], 'diskA')
375
+ self.assertEqual(disk['mode'], 'READ_WRITE')
376
+ self.assertEqual(disk['boot'], True)
377
+
378
+ disk = result['body']['disks'][1]
379
+ self.assertEqual(disk['deviceName'], 'diskB')
380
+ self.assertEqual(disk['mode'], 'READ_ONLY')
381
+ self.assertEqual(disk['boot'], True)
382
+
383
+ disk = result['body']['disks'][2]
384
+ self.assertEqual(disk['deviceName'], 'diskC')
385
+ self.assertEqual(disk['mode'], 'READ_WRITE')
386
+ self.assertEqual(disk['boot'], True)
387
+
388
+ disk = result['body']['disks'][3]
389
+ self.assertEqual(disk['deviceName'], 'diskD')
390
+ self.assertEqual(disk['mode'], 'READ_WRITE')
391
+ self.assertEqual(disk['boot'], False)
392
+ self.assertEqual(exceptions, [])
393
+
394
+ # Make sure we got the zone for the right disk.
395
+ self.assertEqual(2, self._disks.list._parameters['maxResults'])
396
+ self.assertEqual('name eq diskA', self._disks.list._parameters['filter'])
397
+
398
+ expected_kernel = command.NormalizeGlobalResourceName('google',
399
+ 'kernels',
400
+ submitted_kernel)
401
+ self.assertEqual(expected_kernel, result['body']['kernel'])
402
+ self.assertEqual(disk_zone, result['zone'])
403
+
404
+ def testPersistentBootDisk(self):
405
+ flag_values = copy.deepcopy(FLAGS)
406
+
407
+ command = instance_cmds.AddInstance('addinstance', flag_values)
408
+
409
+ service_version = 'v1beta14'
410
+ expected_instance = 'test_instance'
411
+ submitted_machine_type = 'machine-type1'
412
+ submitted_zone = 'zone1'
413
+ submitted_image = 'projects/google/global/images/some-image'
414
+ submitted_project = 'test_project_name'
415
+ image_kernel = 'projects/google/global/kernels/image-kernel'
416
+
417
+ expected_authorized_ssh_keys = []
418
+ flag_values.service_version = service_version
419
+ flag_values.project = submitted_project
420
+ flag_values.machine_type = submitted_machine_type
421
+ flag_values.zone = submitted_zone
422
+ flag_values.use_compute_key = False
423
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
424
+ flag_values.add_compute_key_to_project = False
425
+ flag_values.image = submitted_image
426
+ flag_values.persistent_boot_disk = True
427
+
428
+ self._images.get = mock_api.CommandExecutor(
429
+ {'preferredKernel': image_kernel})
430
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
431
+
432
+ command.SetFlags(flag_values)
433
+ command._projects_api = self._projects
434
+ command._instances_api = self._instances
435
+ command._disks_api = self._disks
436
+ command._images_api = self._images
437
+ command._zones_api = self._zones
438
+ command._credential = mock_api.MockCredential()
439
+
440
+ (results, exceptions) = command.Handle(expected_instance)
441
+ result = results['items'][0]
442
+
443
+ # Make sure boot PD was created from image.
444
+ self.assertEqual(1, len(command._disks_api.requests))
445
+
446
+ disk_insert = command._disks_api.requests[0].request_payload
447
+ expected_disk_name = 'boot-%s' % (expected_instance)
448
+ expected_image = command.NormalizeGlobalResourceName('google',
449
+ 'images',
450
+ submitted_image)
451
+ expected_zone = command.NormalizeTopLevelResourceName(submitted_project,
452
+ 'zones',
453
+ submitted_zone)
454
+ self.assertEqual(expected_disk_name, disk_insert['body']['name'])
455
+ self.assertEqual(expected_image, disk_insert['sourceImage'])
456
+ self.assertEqual('google', self._images.get._parameters['project'])
457
+ self.assertEqual('some-image', self._images.get._parameters['image'])
458
+
459
+ # Make sure the disk was attached to the instance.
460
+ disk = result['body']['disks'][0]
461
+ self.assertEqual(disk['deviceName'], 'boot-' + expected_instance)
462
+ self.assertEqual(disk['mode'], 'READ_WRITE')
463
+ self.assertEqual(disk['boot'], True)
464
+ self.assertEqual(exceptions, [])
465
+
466
+ # Make sure the kernel was set from the image.
467
+ expected_kernel = command.NormalizeGlobalResourceName('google',
468
+ 'kernels',
469
+ image_kernel)
470
+ self.assertEqual(expected_kernel, result['body']['kernel'])
471
+
472
+ # Make sure image was not set.
473
+ self.assertFalse('image' in result['body'])
474
+
475
+ def testAddInstanceWithDiskGeneratesCorrectRequest(self):
476
+ flag_values = copy.deepcopy(FLAGS)
477
+
478
+ command = instance_cmds.AddInstance('addinstance', flag_values)
479
+ service_version = command_base.CURRENT_VERSION
480
+
481
+ expected_project = 'test_project'
482
+ expected_instance = 'test_instance'
483
+ expected_description = 'test instance'
484
+ submitted_image = 'expected_image'
485
+ submitted_disk = 'disk123'
486
+ submitted_machine_type = 'goes_to_11'
487
+ submitted_zone = 'copernicus-moon-base'
488
+
489
+ expected_authorized_ssh_keys = []
490
+ flag_values.service_version = service_version
491
+ flag_values.disk = [submitted_disk]
492
+ flag_values.project = expected_project
493
+ flag_values.description = expected_description
494
+ flag_values.image = submitted_image
495
+ flag_values.machine_type = submitted_machine_type
496
+ flag_values.use_compute_key = False
497
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
498
+ flag_values.add_compute_key_to_project = False
499
+
500
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
501
+
502
+ command.SetFlags(flag_values)
503
+ command._projects_api = self._projects
504
+ command._instances_api = self._instances
505
+ command._disks_api = self._disks
506
+ command._zones_api = self._zones
507
+ command._credential = mock_api.MockCredential()
508
+
509
+ zone_path = 'projects/test_project/zones/%s' % submitted_zone
510
+ self._disks.get = mock_api.CommandExecutor(
511
+ {'zone': zone_path})
512
+ self._zones.list = mock_api.CommandExecutor(
513
+ {'kind': 'compute#zoneList',
514
+ 'items': [{'name': submitted_zone}]})
515
+
516
+ expected_metadata = {'kind': 'compute#metadata',
517
+ 'items': []}
518
+
519
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
520
+ 'images',
521
+ submitted_image)
522
+
523
+ expected_disk = command.NormalizePerZoneResourceName(expected_project,
524
+ submitted_zone,
525
+ 'disks',
526
+ submitted_disk)
527
+
528
+ expected_zone = command.NormalizeTopLevelResourceName(
529
+ expected_project,
530
+ 'zones',
531
+ submitted_zone)
532
+
533
+ (results, exceptions) = command.Handle(expected_instance)
534
+ result = results['items'][0]
535
+
536
+ self.assertEqual(result['project'], expected_project)
537
+ self.assertEqual(result['body']['name'], expected_instance)
538
+ self.assertEqual(result['body']['description'], expected_description)
539
+ self.assertEqual(result['body']['image'], expected_image)
540
+ self.assertEqual(result['body']['disks'][0]['source'], expected_disk)
541
+ self.assertFalse(
542
+ 'natIP' in result['body']['networkInterfaces'][0]['accessConfigs'][0],
543
+ result)
544
+ self.assertEqual(result['body'].get('metadata', {}), expected_metadata)
545
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
546
+ instance_tags = result['body'].get('tags', {}).get('items', [])
547
+ self.assertEqual(submitted_zone, result['zone'])
548
+ self.assertFalse('zone' in result['body'])
549
+ else:
550
+ instance_tags = result['body'].get('tags', [])
551
+ self.assertFalse('zone' in result)
552
+ self.assertEqual(result['body']['zone'], expected_zone)
553
+ self.assertEqual(instance_tags, [])
554
+ self.assertEqual(exceptions, [])
555
+
556
+ def testAddInstanceGeneratesEphemeralIpRequestForProjectWithNoIps(self):
557
+ flag_values = copy.deepcopy(FLAGS)
558
+ command = instance_cmds.AddInstance('addinstance', flag_values)
559
+
560
+ service_version = command_base.CURRENT_VERSION
561
+ expected_project = 'test_project'
562
+ expected_instance = 'test_instance'
563
+ expected_description = 'test instance'
564
+ submitted_image = 'expected_image'
565
+ submitted_machine_type = 'goes_to_11'
566
+ submitted_zone = 'copernicus-moon-base'
567
+
568
+ expected_authorized_ssh_keys = []
569
+ flag_values.service_version = service_version
570
+ flag_values.zone = submitted_zone
571
+ flag_values.project = expected_project
572
+ flag_values.description = expected_description
573
+ flag_values.image = submitted_image
574
+ flag_values.machine_type = submitted_machine_type
575
+ flag_values.use_compute_key = False
576
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
577
+ flag_values.add_compute_key_to_project = False
578
+
579
+ self._projects.get = mock_api.CommandExecutor(
580
+ {'externalIpAddresses': []})
581
+ self._instances.list = mock_api.CommandExecutor({'items': []})
582
+
583
+ command.SetFlags(flag_values)
584
+ command._projects_api = self._projects
585
+ command._instances_api = self._instances
586
+ command._zones_api = self._zones
587
+ command._credential = mock_api.MockCredential()
588
+
589
+ expected_metadata = {'kind': 'compute#metadata',
590
+ 'items': []}
591
+
592
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
593
+ 'images',
594
+ submitted_image)
595
+
596
+ expected_zone = command.NormalizeTopLevelResourceName(
597
+ expected_project,
598
+ 'zones',
599
+ submitted_zone)
600
+
601
+ (results, exceptions) = command.Handle(expected_instance)
602
+ result = results['items'][0]
603
+
604
+ self.assertEqual(result['project'], expected_project)
605
+ self.assertEqual(result['body']['name'], expected_instance)
606
+ self.assertEqual(result['body']['description'], expected_description)
607
+ self.assertEqual(result['body']['image'], expected_image)
608
+ self.assertFalse('natIP' in
609
+ result['body']['networkInterfaces'][0]['accessConfigs'][0],
610
+ result)
611
+ self.assertEqual(result['body'].get('metadata'), expected_metadata)
612
+
613
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
614
+ instance_tags = result['body'].get('tags', {}).get('items', [])
615
+ self.assertEqual(submitted_zone, result['zone'])
616
+ self.assertFalse('zone' in result['body'])
617
+ else:
618
+ instance_tags = result['body'].get('tags', [])
619
+ self.assertFalse('zone' in result)
620
+ self.assertEqual(result['body']['zone'], expected_zone)
621
+
622
+ self.assertEqual(instance_tags, [])
623
+ self.assertEqual(exceptions, [])
624
+
625
+ def testAddInstanceNoExistingVmsRequest(self):
626
+ flag_values = copy.deepcopy(FLAGS)
627
+ command = instance_cmds.AddInstance('addinstance', flag_values)
628
+
629
+ service_version = command_base.CURRENT_VERSION
630
+ expected_project = 'test_project'
631
+ expected_instance = 'test_instance'
632
+ expected_description = 'test instance'
633
+ submitted_image = 'expected_image'
634
+ submitted_machine_type = 'goes_to_11'
635
+ submitted_zone = 'copernicus-moon-base'
636
+
637
+ expected_authorized_ssh_keys = []
638
+ flag_values.service_version = service_version
639
+ flag_values.zone = submitted_zone
640
+ flag_values.project = expected_project
641
+ flag_values.description = expected_description
642
+ flag_values.image = submitted_image
643
+ flag_values.machine_type = submitted_machine_type
644
+ flag_values.use_compute_key = False
645
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
646
+ flag_values.add_compute_key_to_project = False
647
+
648
+ self._projects.get = mock_api.CommandExecutor(
649
+ {'externalIpAddresses': ['192.0.2.2', '192.0.2.3']})
650
+ self._instances.list = mock_api.CommandExecutor(
651
+ {'kind': 'cloud#instances'})
652
+
653
+ command.SetFlags(flag_values)
654
+ command._projects_api = self._projects
655
+ command._instances_api = self._instances
656
+ command._zones_api = self._zones
657
+ command._credential = mock_api.MockCredential()
658
+
659
+ expected_metadata = {'kind': 'compute#metadata',
660
+ 'items': []}
661
+
662
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
663
+ 'images',
664
+ submitted_image)
665
+
666
+ expected_zone = command.NormalizeTopLevelResourceName(
667
+ expected_project,
668
+ 'zones',
669
+ submitted_zone)
670
+
671
+ (results, exceptions) = command.Handle(expected_instance)
672
+ result = results['items'][0]
673
+
674
+ self.assertEqual(result['project'], expected_project)
675
+ self.assertEqual(result['body']['name'], expected_instance)
676
+ self.assertEqual(result['body']['description'], expected_description)
677
+ self.assertEqual(result['body']['image'], expected_image)
678
+ self.assertFalse(
679
+ 'natIP' in result['body']['networkInterfaces'][0]['accessConfigs'][0],
680
+ result)
681
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
682
+ instance_tags = result['body'].get('tags', {}).get('items', [])
683
+ self.assertEqual(submitted_zone, result['zone'])
684
+ self.assertFalse('zone' in result['body'])
685
+ else:
686
+ instance_tags = result['body'].get('tags', [])
687
+ self.assertFalse('zone' in result)
688
+ self.assertEqual(result['body']['zone'], expected_zone)
689
+ self.assertEqual(result['body'].get('metadata'), expected_metadata)
690
+ self.assertEqual(instance_tags, [])
691
+ self.assertEqual(exceptions, [])
692
+
693
+ def testAddInstanceWithSpecifiedInternalAddress(self):
694
+ flag_values = copy.deepcopy(FLAGS)
695
+ command = instance_cmds.AddInstance('addinstance', flag_values)
696
+ service_version = command_base.CURRENT_VERSION
697
+ expected_project = 'test_project'
698
+ expected_instance = 'test_instance'
699
+ expected_description = 'test instance'
700
+ submitted_image = 'expected_image'
701
+ submitted_machine_type = 'goes_to_11'
702
+ submitted_zone = 'copernicus-moon-base'
703
+
704
+ expected_authorized_ssh_keys = []
705
+ expected_internal_ip = '10.0.0.1'
706
+ flag_values.service_version = service_version
707
+ flag_values.zone = submitted_zone
708
+ flag_values.project = expected_project
709
+ flag_values.description = expected_description
710
+ flag_values.image = submitted_image
711
+ flag_values.internal_ip_address = expected_internal_ip
712
+ flag_values.machine_type = submitted_machine_type
713
+ flag_values.use_compute_key = False
714
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
715
+ flag_values.add_compute_key_to_project = False
716
+
717
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
718
+
719
+ command.SetFlags(flag_values)
720
+ command._projects_api = self._projects
721
+ command._instances_api = self._instances
722
+ command._zones_api = self._zones
723
+ command._credential = mock_api.MockCredential()
724
+
725
+ expected_metadata = {'kind': 'compute#metadata',
726
+ 'items': []}
727
+
728
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
729
+ 'images',
730
+ submitted_image)
731
+
732
+ expected_zone = command.NormalizeTopLevelResourceName(
733
+ expected_project,
734
+ 'zones',
735
+ submitted_zone)
736
+
737
+ (results, exceptions) = command.Handle(expected_instance)
738
+ result = results['items'][0]
739
+
740
+ self.assertEqual(result['project'], expected_project)
741
+ self.assertEqual(result['body']['name'], expected_instance)
742
+ self.assertEqual(result['body']['description'], expected_description)
743
+ self.assertEqual(result['body']['image'], expected_image)
744
+ self.assertEqual(result['body']['networkInterfaces'][0]['networkIP'],
745
+ expected_internal_ip)
746
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
747
+ instance_tags = result['body'].get('tags', {}).get('items', [])
748
+ self.assertEqual(submitted_zone, result['zone'])
749
+ self.assertFalse('zone' in result['body'])
750
+ else:
751
+ instance_tags = result['body'].get('tags', [])
752
+ self.assertFalse('zone' in result)
753
+ self.assertEqual(result['body']['zone'], expected_zone)
754
+ self.assertEqual(result['body'].get('metadata'), expected_metadata)
755
+ self.assertEqual(instance_tags, [])
756
+ self.assertEqual(exceptions, [])
757
+
758
+ def testAddInstanceGeneratesNewIpRequest(self):
759
+ flag_values = copy.deepcopy(FLAGS)
760
+ command = instance_cmds.AddInstance('addinstance', flag_values)
761
+
762
+ service_version = command_base.CURRENT_VERSION
763
+ expected_project = 'test_project'
764
+ expected_instance = 'test_instance'
765
+ expected_description = 'test instance'
766
+ submitted_image = 'expected_image'
767
+ submitted_machine_type = 'goes_to_11'
768
+ submitted_zone = 'copernicus-moon-base'
769
+
770
+ expected_authorized_ssh_keys = []
771
+ flag_values.service_version = service_version
772
+ flag_values.zone = submitted_zone
773
+ flag_values.project = expected_project
774
+ flag_values.description = expected_description
775
+ flag_values.image = submitted_image
776
+ flag_values.external_ip_address = 'ephemeral'
777
+ flag_values.machine_type = submitted_machine_type
778
+ flag_values.use_compute_key = False
779
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
780
+ flag_values.add_compute_key_to_project = False
781
+
782
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
783
+
784
+ command.SetFlags(flag_values)
785
+ command._projects_api = self._projects
786
+ command._instances_api = self._instances
787
+ command._zones_api = self._zones
788
+ command._credential = mock_api.MockCredential()
789
+
790
+ expected_metadata = {'kind': 'compute#metadata',
791
+ 'items': []}
792
+
793
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
794
+ 'images',
795
+ submitted_image)
796
+
797
+ expected_zone = command.NormalizeTopLevelResourceName(
798
+ expected_project,
799
+ 'zones',
800
+ submitted_zone)
801
+
802
+ (results, exceptions) = command.Handle(expected_instance)
803
+ result = results['items'][0]
804
+
805
+ self.assertEqual(result['project'], expected_project)
806
+ self.assertEqual(result['body']['name'], expected_instance)
807
+ self.assertEqual(result['body']['description'], expected_description)
808
+ self.assertEqual(result['body']['image'], expected_image)
809
+ self.assertFalse('natIP' in
810
+ result['body']['networkInterfaces'][0]['accessConfigs'][0])
811
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
812
+ instance_tags = result['body'].get('tags', {}).get('items', [])
813
+ self.assertEqual(submitted_zone, result['zone'])
814
+ self.assertFalse('zone' in result['body'])
815
+ else:
816
+ instance_tags = result['body'].get('tags', [])
817
+ self.assertFalse('zone' in result)
818
+ self.assertEqual(result['body']['zone'], expected_zone)
819
+ self.assertEqual(result['body'].get('metadata'), expected_metadata)
820
+ self.assertEqual(instance_tags, [])
821
+ self.assertEqual(exceptions, [])
822
+
823
+ def testAddInstanceGeneratesNoExternalIpRequest(self):
824
+ flag_values = copy.deepcopy(FLAGS)
825
+ command = instance_cmds.AddInstance('addinstance', flag_values)
826
+ service_version = command_base.CURRENT_VERSION
827
+ expected_project = 'test_project'
828
+ expected_instance = 'test_instance'
829
+ expected_description = 'test instance'
830
+ submitted_image = 'expected_image'
831
+ submitted_machine_type = 'goes_to_11'
832
+ submitted_zone = 'copernicus-moon-base'
833
+
834
+ expected_authorized_ssh_keys = []
835
+ flag_values.service_version = service_version
836
+ flag_values.zone = submitted_zone
837
+ flag_values.project = expected_project
838
+ flag_values.description = expected_description
839
+ flag_values.image = submitted_image
840
+ flag_values.external_ip_address = 'None'
841
+ flag_values.machine_type = submitted_machine_type
842
+ flag_values.use_compute_key = False
843
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
844
+ flag_values.add_compute_key_to_project = False
845
+
846
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
847
+
848
+ command.SetFlags(flag_values)
849
+ command._projects_api = self._projects
850
+ command._instances_api = self._instances
851
+ command._zones_api = self._zones
852
+ command._credential = mock_api.MockCredential()
853
+
854
+ expected_metadata = {'kind': 'compute#metadata',
855
+ 'items': []}
856
+
857
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
858
+ 'images',
859
+ submitted_image)
860
+
861
+ expected_zone = command.NormalizeTopLevelResourceName(
862
+ expected_project,
863
+ 'zones',
864
+ submitted_zone)
865
+
866
+ (results, exceptions) = command.Handle(expected_instance)
867
+ result = results['items'][0]
868
+
869
+ self.assertEqual(result['project'], expected_project)
870
+ self.assertEqual(result['body']['name'], expected_instance)
871
+ self.assertEqual(result['body']['description'], expected_description)
872
+ self.assertEqual(result['body']['image'], expected_image)
873
+ self.assertFalse('accessConfigs' in result['body']['networkInterfaces'][0])
874
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
875
+ instance_tags = result['body'].get('tags', {}).get('items', [])
876
+ self.assertEqual(submitted_zone, result['zone'])
877
+ self.assertFalse('zone' in result['body'])
878
+ else:
879
+ instance_tags = result['body'].get('tags', [])
880
+ self.assertFalse('zone' in result)
881
+ self.assertEqual(result['body']['zone'], expected_zone)
882
+ self.assertEqual(result['body'].get('metadata'), expected_metadata)
883
+ self.assertEqual(instance_tags, [])
884
+ self.assertEqual(exceptions, [])
885
+
886
+ def testAddInstanceRequiresZone(self):
887
+ flag_values = copy.deepcopy(FLAGS)
888
+
889
+ command = instance_cmds.AddInstance('addinstance', flag_values)
890
+
891
+ service_version = command_base.CURRENT_VERSION
892
+ expected_project = 'test_project'
893
+ expected_instance = 'test_instance'
894
+ expected_description = 'test instance'
895
+ submitted_image = 'expected_image'
896
+ submitted_machine_type = 'goes_to_11'
897
+ submitted_zone = 'us-east-a'
898
+ expected_authorized_ssh_keys = []
899
+ flag_values.service_version = service_version
900
+ flag_values.project = expected_project
901
+ flag_values.description = expected_description
902
+ flag_values.image = submitted_image
903
+ flag_values.machine_type = submitted_machine_type
904
+ flag_values.use_compute_key = False
905
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
906
+ flag_values.add_compute_key_to_project = False
907
+
908
+ command.SetFlags(flag_values)
909
+ command._credential = mock_api.MockCredential()
910
+
911
+ mock_output = mock_api.MockOutput()
912
+ mock_input = mock_api.MockInput('1\n\r')
913
+
914
+ oldin = sys.stdin
915
+ sys.stdin = mock_input
916
+ oldout = sys.stdout
917
+ sys.stdout = mock_output
918
+
919
+ def GetZonePath(part_one, part_two, part_three):
920
+ return 'projects/test_project/zones/%s-%s-%s' % (part_one,
921
+ part_two,
922
+ part_three)
923
+
924
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
925
+ self._zones.list = mock_api.CommandExecutor(
926
+ {'items': [
927
+ {'name': GetZonePath('us', 'east', 'a')},
928
+ {'name': GetZonePath('us', 'east', 'b')},
929
+ {'name': GetZonePath('us', 'east', 'c')},
930
+ {'name': GetZonePath('us', 'west', 'a')}]})
931
+
932
+ command._projects_api = self._projects
933
+ command._instances_api = self._instances
934
+ command._zones_api = self._zones
935
+
936
+ expected_zone = command.NormalizeTopLevelResourceName(
937
+ expected_project,
938
+ 'zones',
939
+ submitted_zone)
940
+
941
+ (results, exceptions) = command.Handle(expected_instance)
942
+ result = results['items'][0]
943
+
944
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
945
+ self.assertEqual(submitted_zone, result['zone'])
946
+ self.assertFalse('zone' in result['body'])
947
+ else:
948
+ self.assertFalse('zone' in result)
949
+ self.assertEqual(result['body']['zone'], expected_zone)
950
+ self.assertEqual(exceptions, [])
951
+ sys.stdin = oldin
952
+ sys.stdout = oldout
953
+
954
+ def _DoTestAddInstanceWithServiceAccounts(self,
955
+ expected_service_account,
956
+ expected_scopes,
957
+ should_succeed):
958
+ flag_values = copy.deepcopy(FLAGS)
959
+ command = instance_cmds.AddInstance('addinstance', flag_values)
960
+
961
+ expected_project = 'test_project'
962
+ expected_instance = 'test_instance'
963
+ expected_description = 'test instance'
964
+ submitted_image = 'expected_image'
965
+ service_version = 'v1beta13'
966
+ submitted_machine_type = 'goes_to_11'
967
+ submitted_zone = 'copernicus-moon-base'
968
+ expected_authorized_ssh_keys = []
969
+ flag_values.service_version = service_version
970
+ flag_values.zone = submitted_zone
971
+ flag_values.project = expected_project
972
+ flag_values.description = expected_description
973
+ flag_values.image = submitted_image
974
+ flag_values.external_ip_address = 'None'
975
+ flag_values.machine_type = submitted_machine_type
976
+ flag_values.use_compute_key = False
977
+ flag_values.authorized_ssh_keys = expected_authorized_ssh_keys
978
+ if expected_service_account:
979
+ # addinstance command checks whether --service_account is explicitly
980
+ # given, so in this case, set the present flag along with the value.
981
+ flag_values['service_account'].present = True
982
+ flag_values.service_account = expected_service_account
983
+ else:
984
+ # The default 'default' will be expected after command.Handle.
985
+ expected_service_account = 'default'
986
+ if expected_scopes:
987
+ flag_values.service_account_scopes = expected_scopes
988
+ else:
989
+ # The default [] will be expected after command.Handle.
990
+ expected_scopes = []
991
+ flag_values.add_compute_key_to_project = False
992
+
993
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
994
+
995
+ command.SetFlags(flag_values)
996
+ command._projects_api = self._projects
997
+ command._instances_api = self._instances
998
+ command._zones_api = self._zones
999
+ command._credential = mock_api.MockCredential()
1000
+
1001
+ expected_metadata = {'kind': 'compute#metadata',
1002
+ 'items': []}
1003
+
1004
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
1005
+ 'images',
1006
+ submitted_image)
1007
+
1008
+ expected_zone = command.NormalizeTopLevelResourceName(
1009
+ expected_project,
1010
+ 'zones',
1011
+ submitted_zone)
1012
+
1013
+ if not should_succeed:
1014
+ self.assertRaises(app.UsageError,
1015
+ command.Handle,
1016
+ expected_instance)
1017
+ else:
1018
+ (results, exceptions) = command.Handle(expected_instance)
1019
+ result = results['items'][0]
1020
+
1021
+ self.assertEqual(result['project'], expected_project)
1022
+ self.assertEqual(result['body']['name'], expected_instance)
1023
+ self.assertEqual(result['body']['description'], expected_description)
1024
+ self.assertEqual(result['body']['image'], expected_image)
1025
+ self.assertFalse('accessConfigs' in
1026
+ result['body']['networkInterfaces'][0])
1027
+ self.assertEqual(result['body'].get('metadata'), expected_metadata)
1028
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
1029
+ instance_tags = result['body'].get('tags', {}).get('items', [])
1030
+ self.assertEqual(submitted_zone, result['zone'])
1031
+ self.assertFalse('zone' in result['body'])
1032
+ else:
1033
+ instance_tags = result['body'].get('tags', [])
1034
+ self.assertFalse('zone' in result)
1035
+ self.assertEqual(result['body']['zone'], expected_zone)
1036
+ self.assertEqual(instance_tags, [])
1037
+ self.assertEqual(result['body']['serviceAccounts'][0]['email'],
1038
+ expected_service_account)
1039
+ self.assertEqual(result['body']['serviceAccounts'][0]['scopes'],
1040
+ sorted(expected_scopes))
1041
+ self.assertEqual(exceptions, [])
1042
+
1043
+ def testAddInstanceWithServiceAccounts(self):
1044
+ email = 'random.default@developer.googleusercontent.com'
1045
+ scope1 = 'https://www.googleapis.com/auth/fake.product1'
1046
+ scope2 = 'https://www.googleapis.com/auth/fake.product2'
1047
+ self._DoTestAddInstanceWithServiceAccounts(None, [scope1], True)
1048
+ self._DoTestAddInstanceWithServiceAccounts(email, [scope1], True)
1049
+ self._DoTestAddInstanceWithServiceAccounts(email, [scope1, scope2], True)
1050
+ self._DoTestAddInstanceWithServiceAccounts(email, None, False)
1051
+
1052
+ def testAddInstanceWithUnknownKeyFile(self):
1053
+ flag_values = copy.deepcopy(FLAGS)
1054
+ command = instance_cmds.AddInstance('addinstance', flag_values)
1055
+
1056
+ submitted_machine_type = 'goes_to_11'
1057
+ submitted_zone = 'copernicus-moon-base'
1058
+ expected_instance = 'test_instance'
1059
+ flag_values.project = 'test_project'
1060
+ flag_values.zone = submitted_zone
1061
+ flag_values.description = 'test instance'
1062
+ flag_values.image = 'expected_image'
1063
+ flag_values.machine_type = submitted_machine_type
1064
+ flag_values.use_compute_key = False
1065
+ flag_values.authorized_ssh_keys = ['user:unknown-file']
1066
+ flag_values.add_compute_key_to_project = False
1067
+
1068
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
1069
+
1070
+ command.SetFlags(flag_values)
1071
+ command._projects_api = self._projects
1072
+ command._instances_api = self._instances
1073
+ command._zones_api = self._zones
1074
+ command._credential = mock_api.MockCredential()
1075
+
1076
+ self.assertRaises(IOError,
1077
+ command.Handle,
1078
+ expected_instance)
1079
+
1080
+ def testAddAuthorizedUserKeyToProject(self):
1081
+ flag_values = copy.deepcopy(FLAGS)
1082
+ flag_values.service_version = 'v1beta13'
1083
+ command = instance_cmds.AddInstance('addinstance', flag_values)
1084
+
1085
+ class SetCommonInstanceMetadata(object):
1086
+ def __init__(self, record):
1087
+ self.record = record
1088
+
1089
+ def __call__(self, project, body):
1090
+ self.record['project'] = project
1091
+ self.record['body'] = body
1092
+ return self
1093
+
1094
+ def execute(self):
1095
+ pass
1096
+
1097
+ ssh_keys = ''
1098
+ self._projects.get = mock_api.CommandExecutor(
1099
+ {'commonInstanceMetadata': {
1100
+ 'kind': 'compute#metadata',
1101
+ 'items': [{'key': 'sshKeys', 'value': ssh_keys}]}})
1102
+ call_record = {}
1103
+ self._projects.setCommonInstanceMetadata = SetCommonInstanceMetadata(
1104
+ call_record)
1105
+ expected_project = 'test_project'
1106
+
1107
+ flag_values.service_version = 'v1beta13'
1108
+ flag_values.project = expected_project
1109
+ command.SetFlags(flag_values)
1110
+ command._projects_api = self._projects
1111
+ command._credential = mock_api.MockCredential()
1112
+
1113
+ result = command._AddAuthorizedUserKeyToProject(
1114
+ {'user': 'foo', 'key': 'bar'})
1115
+ self.assertTrue(result)
1116
+ self.assertEquals(expected_project, call_record['project'])
1117
+ self.assertEquals(
1118
+ {'kind': 'compute#metadata',
1119
+ 'items': [{'key': 'sshKeys', 'value': 'foo:bar'}]},
1120
+ call_record['body'])
1121
+
1122
+ def testAddAuthorizedUserKeyAlreadyInProject(self):
1123
+ flag_values = copy.deepcopy(FLAGS)
1124
+ flag_values.service_version = 'v1beta13'
1125
+ command = instance_cmds.AddInstance('addinstance', flag_values)
1126
+
1127
+ class SetCommonInstanceMetadata(object):
1128
+ def __init__(self, record):
1129
+ self.record = record
1130
+
1131
+ def __call__(self, project, body):
1132
+ self.record['project'] = project
1133
+ self.record['body'] = body
1134
+ return self
1135
+
1136
+ def execute(self):
1137
+ pass
1138
+
1139
+ ssh_keys = 'baz:bat\nfoo:bar\ni:j'
1140
+ self._projects.get = mock_api.CommandExecutor(
1141
+ {'commonInstanceMetadata': {
1142
+ 'kind': 'compute#metadata',
1143
+ 'items': [{'key': 'sshKeys', 'value': ssh_keys}]}})
1144
+ call_record = {}
1145
+ self._projects.setCommonInstanceMetadata = SetCommonInstanceMetadata(
1146
+ call_record)
1147
+ expected_project = 'test_project'
1148
+
1149
+ flag_values.service_version = 'v1beta13'
1150
+ flag_values.project = expected_project
1151
+ command.SetFlags(flag_values)
1152
+ command._projects_api = self._projects
1153
+ command._credential = mock_api.MockCredential()
1154
+
1155
+ result = command._AddAuthorizedUserKeyToProject(
1156
+ {'user': 'foo', 'key': 'bar'})
1157
+ self.assertFalse(result)
1158
+
1159
+ def _testAddSshKeysToMetadataHelper(self,
1160
+ test_ssh_key_through_file,
1161
+ test_ssh_key_through_flags):
1162
+ flag_values = copy.deepcopy(FLAGS)
1163
+ command = instance_cmds.AddInstance('addinstance', flag_values)
1164
+ flag_values.use_compute_key = False
1165
+ ssh_rsa_key = ('ssh-rsa ' +
1166
+ base64.b64encode('\00\00\00\07ssh-rsa the ssh key') +
1167
+ ' comment')
1168
+
1169
+ with tempfile.NamedTemporaryFile() as metadata_file:
1170
+ with tempfile.NamedTemporaryFile() as ssh_key_file:
1171
+ metadata_file.write('metadata file content')
1172
+ metadata_file.flush()
1173
+ flag_values.metadata_from_file = ['bar_file:%s' % metadata_file.name]
1174
+
1175
+ flag_values.metadata = ['bar:baz']
1176
+
1177
+ if test_ssh_key_through_file:
1178
+ ssh_key_file.write(ssh_rsa_key)
1179
+ ssh_key_file.flush()
1180
+ flag_values.authorized_ssh_keys = ['user:%s' % ssh_key_file.name]
1181
+
1182
+ if test_ssh_key_through_flags:
1183
+ flag_values.metadata.append('sshKeys:user2:flags ssh key')
1184
+
1185
+ command.SetFlags(flag_values)
1186
+ metadata_flags_processor = command._metadata_flags_processor
1187
+ extended_metadata = command._AddSshKeysToMetadata(
1188
+ metadata_flags_processor.GatherMetadata())
1189
+
1190
+ self.assertTrue(len(extended_metadata) >= 2)
1191
+ self.assertEqual(extended_metadata[0]['key'], 'bar')
1192
+ self.assertEqual(extended_metadata[0]['value'], 'baz')
1193
+ self.assertEqual(extended_metadata[1]['key'], 'bar_file')
1194
+ self.assertEqual(extended_metadata[1]['value'], 'metadata file content')
1195
+
1196
+ ssh_keys = []
1197
+ if test_ssh_key_through_flags:
1198
+ ssh_keys.append('user2:flags ssh key')
1199
+ if test_ssh_key_through_file:
1200
+ ssh_keys.append('user:' + ssh_rsa_key)
1201
+
1202
+ if test_ssh_key_through_flags or test_ssh_key_through_file:
1203
+ self.assertEqual(len(extended_metadata), 3)
1204
+ self.assertEqual(extended_metadata[2]['key'], 'sshKeys')
1205
+ self.assertEqual(extended_metadata[2]['value'],
1206
+ '\n'.join(ssh_keys))
1207
+
1208
+ def testGatherMetadata(self):
1209
+ self._testAddSshKeysToMetadataHelper(False, False)
1210
+ self._testAddSshKeysToMetadataHelper(False, True)
1211
+ self._testAddSshKeysToMetadataHelper(True, False)
1212
+ self._testAddSshKeysToMetadataHelper(True, True)
1213
+
1214
+ def testBuildInstanceRequestWithMetadataAndDisk(self):
1215
+ flag_values = copy.deepcopy(FLAGS)
1216
+ command = instance_cmds.AddInstance('addinstance', flag_values)
1217
+
1218
+ expected_project = 'test_project'
1219
+ expected_instance = 'test_instance'
1220
+ expected_description = 'test instance'
1221
+ submitted_image = 'expected_image'
1222
+ submitted_zone = 'copernicus-moon-base'
1223
+ flag_values.service_version = 'v1beta13'
1224
+ flag_values.project = expected_project
1225
+ flag_values.zone = submitted_zone
1226
+ flag_values.description = expected_description
1227
+ flag_values.image = submitted_image
1228
+ flag_values.use_compute_key = False
1229
+ flag_values.authorized_ssh_keys = []
1230
+ flag_values.add_compute_key_to_project = False
1231
+ metadata = [{'key': 'foo', 'value': 'bar'}]
1232
+ disks = [{'source': ('http://www.googleapis.com/compute/v1beta13/projects/'
1233
+ 'google.com:test/disks/disk789'),
1234
+ 'deviceName': 'disk789', 'mode': 'READ_WRITE',
1235
+ 'type': 'PERSISTENT', 'boot': False}]
1236
+
1237
+ expected_metadata = {'kind': 'compute#metadata',
1238
+ 'items': metadata}
1239
+
1240
+ command.SetFlags(flag_values)
1241
+ command.SetApi(mock_api.MockApi())
1242
+
1243
+ result = command._BuildRequestWithMetadata(
1244
+ expected_instance, metadata, disks).execute()
1245
+
1246
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
1247
+ 'images',
1248
+ submitted_image)
1249
+
1250
+ self.assertEqual(result['project'], expected_project)
1251
+ self.assertEqual(result['body']['name'], expected_instance)
1252
+ self.assertEqual(result['body']['description'], expected_description)
1253
+ self.assertEqual(result['body']['image'], expected_image)
1254
+ self.assertEqual(result['body']['metadata'], expected_metadata)
1255
+ self.assertEqual(result['body']['disks'], disks)
1256
+
1257
+ def testBuildInstanceRequestWithTag(self):
1258
+ flag_values = copy.deepcopy(FLAGS)
1259
+ command = instance_cmds.AddInstance('addinstance', flag_values)
1260
+
1261
+ service_version = 'v1beta13'
1262
+ expected_project = 'test_project'
1263
+ expected_instance = 'test_instance'
1264
+ expected_description = 'test instance'
1265
+ submitted_image = 'expected_image'
1266
+ submitted_machine_type = 'goes_to_11'
1267
+ submitted_zone = 'copernicus-moon-base'
1268
+ expected_tags = ['tag0', 'tag1', 'tag2']
1269
+
1270
+ flag_values.service_version = service_version
1271
+ flag_values.project = expected_project
1272
+ flag_values.zone = submitted_zone
1273
+ flag_values.description = expected_description
1274
+ flag_values.image = submitted_image
1275
+ flag_values.machine_type = submitted_machine_type
1276
+ flag_values.use_compute_key = False
1277
+ flag_values.authorized_ssh_keys = []
1278
+ flag_values.tags = expected_tags * 2 # Create duplicates.
1279
+ flag_values.add_compute_key_to_project = False
1280
+
1281
+ self._instances.list = mock_api.CommandExecutor(self._instance_list)
1282
+
1283
+ command.SetFlags(flag_values)
1284
+ command._projects_api = self._projects
1285
+ command._instances_api = self._instances
1286
+ command._zones_api = self._zones
1287
+ command._credential = mock_api.MockCredential()
1288
+
1289
+ expected_metadata = {'kind': 'compute#metadata',
1290
+ 'items': []}
1291
+
1292
+ expected_image = command.NormalizeGlobalResourceName(expected_project,
1293
+ 'images',
1294
+ submitted_image)
1295
+
1296
+ expected_zone = command.NormalizeTopLevelResourceName(
1297
+ expected_project,
1298
+ 'zones',
1299
+ submitted_zone)
1300
+
1301
+ (results, exceptions) = command.Handle(expected_instance)
1302
+ result = results['items'][0]
1303
+
1304
+ self.assertEqual(result['project'], expected_project)
1305
+ self.assertEqual(result['body']['name'], expected_instance)
1306
+ self.assertEqual(result['body']['description'], expected_description)
1307
+ self.assertEqual(result['body']['image'], expected_image)
1308
+ self.assertFalse(
1309
+ 'natIP' in result['body']['networkInterfaces'][0]['accessConfigs'][0],
1310
+ result)
1311
+ self.assertEqual(result['body'].get('metadata'), expected_metadata)
1312
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
1313
+ instance_tags = result['body'].get('tags', {}).get('items', [])
1314
+ self.assertEqual(submitted_zone, result['zone'])
1315
+ self.assertFalse('zone' in result['body'])
1316
+ else:
1317
+ instance_tags = result['body'].get('tags', [])
1318
+ self.assertFalse('zone' in result)
1319
+ self.assertEqual(result['body']['zone'], expected_zone)
1320
+ self.assertEqual(instance_tags, expected_tags)
1321
+ self.assertEqual(exceptions, [])
1322
+
1323
+ def testGetInstanceGeneratesCorrectRequest(self):
1324
+ flag_values = copy.deepcopy(FLAGS)
1325
+ command = instance_cmds.GetInstance('getinstance', flag_values)
1326
+
1327
+ expected_project = 'test_project'
1328
+ expected_instance = 'test_instance'
1329
+ flag_values.project = expected_project
1330
+ flag_values.zone = 'zone-a'
1331
+
1332
+ command.SetFlags(flag_values)
1333
+ command.SetApi(mock_api.MockApi())
1334
+ command._credential = mock_api.MockCredential()
1335
+
1336
+ result = command.Handle(expected_instance)
1337
+
1338
+ self.assertEqual(result['project'], expected_project)
1339
+ self.assertEqual(result['instance'], expected_instance)
1340
+
1341
+ def _DoTestDeleteInstanceGeneratesCorrectRequest(self, service_version):
1342
+ flag_values = copy.deepcopy(FLAGS)
1343
+ command = instance_cmds.DeleteInstance('deleteinstance', flag_values)
1344
+
1345
+ expected_project = 'test_project'
1346
+ expected_instance = 'test_instance'
1347
+ submitted_zone = 'copernicus-moon-base'
1348
+ flag_values.project = expected_project
1349
+ flag_values.service_version = service_version
1350
+ flag_values.zone = submitted_zone
1351
+
1352
+ command.SetFlags(flag_values)
1353
+ command.SetApi(mock_api.MockApi())
1354
+ command._credential = mock_api.MockCredential()
1355
+
1356
+ (results, exceptions) = command.Handle(expected_instance)
1357
+ result = results['items'][0]
1358
+
1359
+ self.assertEqual(result['project'], expected_project)
1360
+ self.assertEqual(result['instance'], expected_instance)
1361
+ self.assertEqual(exceptions, [])
1362
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
1363
+ self.assertEqual(submitted_zone, result['zone'])
1364
+ else:
1365
+ self.assertFalse('zone' in result)
1366
+
1367
+ def testDeleteInstanceGeneratesCorrectRequest(self):
1368
+ for version in command_base.SUPPORTED_VERSIONS:
1369
+ self._DoTestDeleteInstanceGeneratesCorrectRequest(version)
1370
+
1371
+ def testDeleteMultipleInstances(self):
1372
+ flag_values = copy.deepcopy(FLAGS)
1373
+ command = instance_cmds.DeleteInstance('deleteinstance', flag_values)
1374
+
1375
+ expected_project = 'test_project'
1376
+ expected_instances = ['test-instance-%02d' % i for i in range(100)]
1377
+ flag_values.project = expected_project
1378
+ flag_values.zone = 'zone-a'
1379
+
1380
+ command.SetFlags(flag_values)
1381
+ command.SetApi(mock_api.MockApi())
1382
+ command._zones_api = self._zones
1383
+ command._credential = mock_api.MockCredential()
1384
+
1385
+ (results, exceptions) = command.Handle(*expected_instances)
1386
+ self.assertEqual(exceptions, [])
1387
+ results = results['items']
1388
+ self.assertEqual(len(results), len(expected_instances))
1389
+
1390
+ for (expected_instance, result) in zip(expected_instances, results):
1391
+ self.assertEqual(result['project'], expected_project)
1392
+ self.assertEqual(result['instance'], expected_instance)
1393
+
1394
+ def _DoTestAddAccessConfigGeneratesCorrectRequest(self, service_version):
1395
+ flag_values = copy.deepcopy(FLAGS)
1396
+ command = instance_cmds.AddAccessConfig('addaccessconfig', flag_values)
1397
+
1398
+ expected_project_name = 'test_project_name'
1399
+ expected_instance_name = 'test_instance_name'
1400
+ expected_network_interface_name = 'test_network_interface_name'
1401
+ expected_access_config_name = 'test_access_config_name'
1402
+ expected_access_config_type = 'test_access_config_type'
1403
+ expected_access_config_nat_ip = 'test_access_config_nat_ip'
1404
+
1405
+ flag_values.project = expected_project_name
1406
+ flag_values.network_interface_name = expected_network_interface_name
1407
+ flag_values.access_config_name = expected_access_config_name
1408
+ flag_values.access_config_type = expected_access_config_type
1409
+ flag_values.access_config_nat_ip = expected_access_config_nat_ip
1410
+ flag_values.service_version = service_version
1411
+ command.SetFlags(flag_values)
1412
+ command.SetApi(mock_api.MockApi())
1413
+ command._credential = mock_api.MockCredential()
1414
+ submitted_zone = 'copernicus-moon-base'
1415
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
1416
+ flag_values.zone = submitted_zone
1417
+
1418
+ result = command.Handle(expected_instance_name)
1419
+
1420
+ self.assertEqual(result['project'], expected_project_name)
1421
+ self.assertEqual(result['instance'], expected_instance_name)
1422
+ self.assertEqual(result['network_interface'],
1423
+ expected_network_interface_name)
1424
+ self.assertEqual(result['body']['name'], expected_access_config_name)
1425
+ self.assertEqual(result['body']['type'], expected_access_config_type)
1426
+ self.assertEqual(result['body']['natIP'], expected_access_config_nat_ip)
1427
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
1428
+ self.assertEqual(submitted_zone, result['zone'])
1429
+ else:
1430
+ self.assertFalse('zone' in result)
1431
+
1432
+ def testAddAccessConfigGeneratesCorrectRequest(self):
1433
+ for version in command_base.SUPPORTED_VERSIONS:
1434
+ self._DoTestAddAccessConfigGeneratesCorrectRequest(version)
1435
+
1436
+ def _DoTestDeleteAccessConfigGeneratesCorrectRequest(self, service_version):
1437
+ flag_values = copy.deepcopy(FLAGS)
1438
+ command = instance_cmds.DeleteAccessConfig('deleteaccessconfig',
1439
+ flag_values)
1440
+
1441
+ expected_project_name = 'test_project_name'
1442
+ expected_instance_name = 'test_instance_name'
1443
+ expected_network_interface_name = 'test_network_interface_name'
1444
+ expected_access_config_name = 'test_access_config_name'
1445
+
1446
+ flag_values.project = expected_project_name
1447
+ flag_values.network_interface_name = expected_network_interface_name
1448
+ flag_values.access_config_name = expected_access_config_name
1449
+ flag_values.service_version = service_version
1450
+ command.SetFlags(flag_values)
1451
+ command.SetApi(mock_api.MockApi())
1452
+ command._zones_api = self._zones
1453
+ command._credential = mock_api.MockCredential()
1454
+ submitted_zone = 'copernicus-moon-base'
1455
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
1456
+ flag_values.zone = submitted_zone
1457
+
1458
+ result = command.Handle(expected_instance_name)
1459
+
1460
+ self.assertEqual(result['project'], expected_project_name)
1461
+ self.assertEqual(result['instance'], expected_instance_name)
1462
+ self.assertEqual(result['network_interface'],
1463
+ expected_network_interface_name)
1464
+ self.assertEqual(result['access_config'],
1465
+ expected_access_config_name)
1466
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
1467
+ self.assertEqual(submitted_zone, result['zone'])
1468
+ else:
1469
+ self.assertFalse('zone' in result)
1470
+
1471
+ def testDeleteAccessConfigGeneratesCorrectRequest(self):
1472
+ for version in command_base.SUPPORTED_VERSIONS:
1473
+ self._DoTestDeleteAccessConfigGeneratesCorrectRequest(version)
1474
+
1475
+ def testSetInstanceMetadataGeneratesCorrectRequest(self):
1476
+ flag_values = copy.deepcopy(FLAGS)
1477
+ command = instance_cmds.SetMetadata('setinstancemetadata', flag_values)
1478
+
1479
+ expected_project = 'test_project'
1480
+ expected_instance = 'test_instance'
1481
+ expected_fingerprint = 'asdfg'
1482
+ submitted_zone = 'zone-a'
1483
+ flag_values.project = expected_project
1484
+ flag_values.fingerprint = expected_fingerprint
1485
+ flag_values.zone = submitted_zone
1486
+
1487
+ with tempfile.NamedTemporaryFile() as metadata_file:
1488
+ metadata_file.write('foo:bar')
1489
+ metadata_file.flush()
1490
+ flag_values.metadata_from_file = ['sshKeys:%s' % metadata_file.name]
1491
+
1492
+ command.SetFlags(flag_values)
1493
+ command.SetApi(mock_api.MockApi())
1494
+ command._instances_api.get = mock_api.CommandExecutor(
1495
+ {'metadata': {'kind': 'compute#metadata',
1496
+ 'items': [{'key': 'sshKeys', 'value': ''}]}})
1497
+ command._projects_api.get = mock_api.CommandExecutor(
1498
+ {'commonInstanceMetadata': {'kind': 'compute#metadata',
1499
+ 'items': [{'key': 'sshKeys',
1500
+ 'value': ''}]}})
1501
+ command._zones_api = self._zones
1502
+
1503
+ result = command.Handle(expected_instance)
1504
+ self.assertEquals(expected_project, result['project'])
1505
+ self.assertEquals(expected_instance, result['instance'])
1506
+ self.assertEquals(
1507
+ {'kind': 'compute#metadata',
1508
+ 'fingerprint': expected_fingerprint,
1509
+ 'items': [{'key': 'sshKeys', 'value': 'foo:bar'}]},
1510
+ result['body'])
1511
+
1512
+ def testSetMetadataChecksSshKeys(self):
1513
+ flag_values = copy.deepcopy(FLAGS)
1514
+ command = instance_cmds.SetMetadata(
1515
+ 'setinstancemetadata', flag_values)
1516
+
1517
+ expected_project = 'test_project'
1518
+ expected_instance = 'test_instance'
1519
+ expected_fingerprint = 'asdfg'
1520
+ flag_values.project = expected_project
1521
+ flag_values.fingerprint = expected_fingerprint
1522
+
1523
+ command.SetFlags(flag_values)
1524
+ command.SetApi(mock_api.MockApi())
1525
+ command._instances_api.get = mock_api.CommandExecutor(
1526
+ {'metadata': {'kind': 'compute#metadata',
1527
+ 'items': [{'key': 'sshKeys', 'value': 'xyz'}]}})
1528
+ command._projects_api.get = mock_api.CommandExecutor(
1529
+ {'commonInstanceMetadata': {'kind': 'compute#metadata',
1530
+ 'items': [{'key': 'noSshKey',
1531
+ 'value': 'none'}]}})
1532
+ command._zones_api = self._zones
1533
+
1534
+ self.assertRaises(command_base.CommandError,
1535
+ command.Handle, expected_instance)
1536
+
1537
+ def testSetMetadataFailsWithNofingerprint(self):
1538
+ flag_values = copy.deepcopy(FLAGS)
1539
+ command = instance_cmds.SetMetadata('setinstancemetadata', flag_values)
1540
+
1541
+ expected_project = 'test_project'
1542
+ expected_instance = 'test_instance'
1543
+ submitted_zone = 'zone-a'
1544
+ flag_values.project = expected_project
1545
+ flag_values.zone = submitted_zone
1546
+
1547
+ with tempfile.NamedTemporaryFile() as metadata_file:
1548
+ metadata_file.write('foo:bar')
1549
+ metadata_file.flush()
1550
+ flag_values.metadata_from_file = ['sshKeys:%s' % metadata_file.name]
1551
+
1552
+ command.SetFlags(flag_values)
1553
+ command.SetApi(mock_api.MockApi())
1554
+ command._instances_api.get = mock_api.CommandExecutor(
1555
+ {'metadata': {'kind': 'compute#metadata',
1556
+ 'items': [{'key': 'sshKeys', 'value': ''}]}})
1557
+ command._projects_api.get = mock_api.CommandExecutor(
1558
+ {'commonInstanceMetadata': {'kind': 'compute#metadata',
1559
+ 'items': [{'key': 'sshKeys',
1560
+ 'value': ''}]}})
1561
+ command._zones_api = self._zones
1562
+ self.assertRaises(app.UsageError, command.Handle, expected_instance)
1563
+
1564
+ def testSetTagsGeneratesCorrectRequest(self):
1565
+ flag_values = copy.deepcopy(FLAGS)
1566
+ command = instance_cmds.SetTags('settags', flag_values)
1567
+
1568
+ expected_project = 'test_project'
1569
+ expected_instance = 'test_instance'
1570
+ expected_fingerprint = 'test-hash'
1571
+ expected_tags = ['tag0', 'tag1', 'tag2']
1572
+ submitted_zone = 'zone-a'
1573
+ flag_values.project = expected_project
1574
+ flag_values.fingerprint = expected_fingerprint
1575
+ flag_values.tags = expected_tags
1576
+ flag_values.zone = submitted_zone
1577
+
1578
+ command.SetFlags(flag_values)
1579
+ command.SetApi(mock_api.MockApi())
1580
+ command._zones_api = self._zones
1581
+
1582
+ result = command.Handle(expected_instance)
1583
+
1584
+ self.assertEqual(result['instance'], expected_instance)
1585
+ self.assertEqual(result['project'], expected_project)
1586
+ self.assertEqual(result['body'].get('fingerprint'), expected_fingerprint)
1587
+ self.assertEqual(result['body'].get('items'), expected_tags)
1588
+
1589
+ def testSetTagsFailsWithNoFingerprint(self):
1590
+ flag_values = copy.deepcopy(FLAGS)
1591
+ command = instance_cmds.SetTags('settags', flag_values)
1592
+
1593
+ expected_project = 'test_project'
1594
+ expected_instance = 'test_instance'
1595
+ expected_tags = ['tag0', 'tag1', 'tag2']
1596
+ submitted_zone = 'zone-a'
1597
+ flag_values.project = expected_project
1598
+ flag_values.tags = expected_tags
1599
+ flag_values.zone = submitted_zone
1600
+
1601
+ command.SetFlags(flag_values)
1602
+ command.SetApi(mock_api.MockApi())
1603
+ command._zones_api = self._zones
1604
+
1605
+ self.assertRaises(app.UsageError, command.Handle, expected_instance)
1606
+
1607
+ def testGetSshAddressChecksForNetworkInterfaces(self):
1608
+ flag_values = copy.deepcopy(FLAGS)
1609
+ command = instance_cmds.SshInstanceBase('test', flag_values)
1610
+ command.SetFlags(flag_values)
1611
+ mock_instance = {'someFieldOtherThanNetworkInterfaces': [],
1612
+ 'status': 'RUNNING'}
1613
+
1614
+ self.assertRaises(command_base.CommandError,
1615
+ command._GetSshAddress,
1616
+ mock_instance)
1617
+
1618
+ def testGetSshAddressChecksForNonEmptyNetworkInterfaces(self):
1619
+ flag_values = copy.deepcopy(FLAGS)
1620
+ command = instance_cmds.SshInstanceBase('test', flag_values)
1621
+ command.SetFlags(flag_values)
1622
+ mock_instance = {'networkInterfaces': [], 'status': 'RUNNING'}
1623
+
1624
+ self.assertRaises(command_base.CommandError,
1625
+ command._GetSshAddress,
1626
+ mock_instance)
1627
+
1628
+ def testGetSshAddressChecksForAccessConfigs(self):
1629
+ flag_values = copy.deepcopy(FLAGS)
1630
+ command = instance_cmds.SshInstanceBase('test', flag_values)
1631
+ command.SetFlags(flag_values)
1632
+ mock_instance = {'networkInterfaces': [{}]}
1633
+
1634
+ self.assertRaises(command_base.CommandError,
1635
+ command._GetSshAddress,
1636
+ mock_instance)
1637
+
1638
+ def testGetSshAddressChecksForNonEmptyAccessConfigs(self):
1639
+ flag_values = copy.deepcopy(FLAGS)
1640
+ command = instance_cmds.SshInstanceBase('test', flag_values)
1641
+ command.SetFlags(flag_values)
1642
+ mock_instance = {'networkInterfaces': [{'accessConfigs': []}],
1643
+ 'status': 'RUNNING'}
1644
+
1645
+ self.assertRaises(command_base.CommandError,
1646
+ command._GetSshAddress,
1647
+ mock_instance)
1648
+
1649
+ def testGetSshAddressChecksForNatIp(self):
1650
+ flag_values = copy.deepcopy(FLAGS)
1651
+ command = instance_cmds.SshInstanceBase('test', flag_values)
1652
+ command.SetFlags(flag_values)
1653
+ mock_instance = {'networkInterfaces': [{'accessConfigs': [{}]}],
1654
+ 'status': 'RUNNING'}
1655
+
1656
+ self.assertRaises(command_base.CommandError,
1657
+ command._GetSshAddress,
1658
+ mock_instance)
1659
+
1660
+ def testEnsureSshableChecksForSshKeysInTheInstance(self):
1661
+ flag_values = copy.deepcopy(FLAGS)
1662
+ command = instance_cmds.SshInstanceBase('test', flag_values)
1663
+ command.SetFlags(flag_values)
1664
+ mock_instance = {'networkInterfaces': [{'accessConfigs': [{}]}],
1665
+ 'status': 'RUNNING',
1666
+ 'metadata': {u'kind': u'compute#metadata',
1667
+ u'items': [{u'key': u'sshKeys',
1668
+ u'value': ''}]}}
1669
+
1670
+ def MockAddComputeKeyToProject():
1671
+ self.fail('Unexpected call to _AddComputeKeyToProject')
1672
+
1673
+ command._AddComputeKeyToProject = MockAddComputeKeyToProject
1674
+ command._EnsureSshable(mock_instance)
1675
+
1676
+ def testEnsureSshableChecksForNonRunningInstance(self):
1677
+ flag_values = copy.deepcopy(FLAGS)
1678
+ command = instance_cmds.SshInstanceBase('test', flag_values)
1679
+ command.SetFlags(flag_values)
1680
+ mock_instance = {'networkInterfaces': [{'accessConfigs': [{}]}],
1681
+ 'status': 'STAGING'}
1682
+
1683
+ self.assertRaises(command_base.CommandError,
1684
+ command._EnsureSshable,
1685
+ mock_instance)
1686
+
1687
+ def testSshGeneratesCorrectArguments(self):
1688
+ flag_values = copy.deepcopy(FLAGS)
1689
+ command = instance_cmds.SshToInstance('ssh', flag_values)
1690
+
1691
+ argv = ['arg1', '%arg2', 'arg3']
1692
+ expected_arg_list = ['-A', '-p', '%(port)d', '%(user)s@%(host)s',
1693
+ '--', 'arg1', '%%arg2', 'arg3']
1694
+
1695
+ arg_list = command._GenerateSshArgs(*argv)
1696
+
1697
+ self.assertEqual(expected_arg_list, arg_list)
1698
+
1699
+ def testSshPassesThroughSshArg(self):
1700
+ flag_values = copy.deepcopy(FLAGS)
1701
+ command = instance_cmds.SshToInstance('ssh', flag_values)
1702
+ ssh_arg = '--passedSshArgKey=passedSshArgValue'
1703
+ flag_values.ssh_arg = [ssh_arg]
1704
+ command.SetFlags(flag_values)
1705
+ ssh_args = command._GenerateSshArgs(*[])
1706
+ mock_instance_resource = {
1707
+ 'networkInterfaces': [{'accessConfigs': [{'type': 'ONE_TO_ONE_NAT',
1708
+ 'natIP': '0.0.0.0'}]}],
1709
+ 'status': 'RUNNING'}
1710
+ command_line = command._BuildSshCmd(mock_instance_resource, 'ssh', ssh_args)
1711
+ self.assertTrue(ssh_arg in command_line)
1712
+
1713
+ def testSshPassesThroughTwoSshArgs(self):
1714
+ flag_values = copy.deepcopy(FLAGS)
1715
+ command = instance_cmds.SshToInstance('ssh', flag_values)
1716
+ ssh_arg1 = '--k1=v1'
1717
+ ssh_arg2 = '--k2=v2'
1718
+ flag_values.ssh_arg = [ssh_arg1, ssh_arg2]
1719
+ command.SetFlags(flag_values)
1720
+ ssh_args = command._GenerateSshArgs(*[])
1721
+ mock_instance_resource = {
1722
+ 'networkInterfaces': [{'accessConfigs': [{'type': 'ONE_TO_ONE_NAT',
1723
+ 'natIP': '0.0.0.0'}]}],
1724
+ 'status': 'RUNNING'}
1725
+ command_line = command._BuildSshCmd(mock_instance_resource, 'ssh', ssh_args)
1726
+
1727
+ self.assertTrue(ssh_arg1 in command_line)
1728
+ self.assertTrue(ssh_arg2 in command_line)
1729
+
1730
+ def testSshGeneratesCorrectCommand(self):
1731
+ flag_values = copy.deepcopy(FLAGS)
1732
+ command = instance_cmds.SshToInstance('ssh', flag_values)
1733
+
1734
+ expected_project = 'test_project'
1735
+ expected_ip = '1.1.1.1'
1736
+ expected_port = 22
1737
+ expected_user = 'test_user'
1738
+ expected_ssh_file = 'test_file'
1739
+ flag_values.project = expected_project
1740
+ flag_values.ssh_port = expected_port
1741
+ flag_values.ssh_user = expected_user
1742
+ flag_values.private_key_file = expected_ssh_file
1743
+
1744
+ ssh_args = ['-A', '-p', '%(port)d', '%(user)s@%(host)s', '--']
1745
+
1746
+ expected_command = [
1747
+ 'ssh', '-o', 'UserKnownHostsFile=/dev/null',
1748
+ '-o', 'CheckHostIP=no',
1749
+ '-o', 'StrictHostKeyChecking=no',
1750
+ '-i', expected_ssh_file,
1751
+ '-A', '-p', str(expected_port),
1752
+ '%s@%s' % (expected_user, expected_ip),
1753
+ '--']
1754
+
1755
+ if LOGGER.level <= logging.DEBUG:
1756
+ expected_command.insert(-5, '-v')
1757
+
1758
+ command.SetFlags(flag_values)
1759
+ mock_instance_resource = {
1760
+ 'networkInterfaces': [{'accessConfigs': [{'type': 'ONE_TO_ONE_NAT',
1761
+ 'natIP': expected_ip}]}],
1762
+ 'status': 'RUNNING'}
1763
+ command_line = command._BuildSshCmd(mock_instance_resource, 'ssh', ssh_args)
1764
+
1765
+ self.assertEqual(expected_command, command_line)
1766
+
1767
+ def testScpPushGeneratesCorrectArguments(self):
1768
+ flag_values = copy.deepcopy(FLAGS)
1769
+ command = instance_cmds.PushToInstance('push', flag_values)
1770
+
1771
+ argv = ['file1', '%file2', 'destination']
1772
+ expected_arg_list = ['-r', '-P', '%(port)d', '--',
1773
+ 'file1',
1774
+ '%%file2',
1775
+ '%(user)s@%(host)s:destination']
1776
+
1777
+ arg_list = command._GenerateScpArgs(*argv)
1778
+
1779
+ self.assertEqual(expected_arg_list, arg_list)
1780
+
1781
+ def testScpPushGeneratesCorrectCommand(self):
1782
+ flag_values = copy.deepcopy(FLAGS)
1783
+ command = instance_cmds.PushToInstance('push', flag_values)
1784
+
1785
+ expected_project = 'test_project'
1786
+ expected_ip = '1.1.1.1'
1787
+ expected_port = 22
1788
+ expected_user = 'test_user'
1789
+ expected_ssh_file = 'test_file'
1790
+ expected_local_file = 'test_source'
1791
+ expected_remote_file = 'test_remote'
1792
+ flag_values.project = expected_project
1793
+ flag_values.ssh_port = expected_port
1794
+ flag_values.ssh_user = expected_user
1795
+ flag_values.private_key_file = expected_ssh_file
1796
+
1797
+ scp_args = ['-P', '%(port)d', '--']
1798
+ unused_argv = ('', expected_local_file, expected_remote_file)
1799
+
1800
+ escaped_args = [a.replace('%', '%%') for a in unused_argv]
1801
+ scp_args.extend(escaped_args[1:-1])
1802
+ scp_args.append('%(user)s@%(host)s:' + escaped_args[-1])
1803
+
1804
+ expected_command = [
1805
+ 'scp',
1806
+ '-o', 'UserKnownHostsFile=/dev/null',
1807
+ '-o', 'CheckHostIP=no',
1808
+ '-o', 'StrictHostKeyChecking=no',
1809
+ '-i', expected_ssh_file,
1810
+ '-P', str(expected_port),
1811
+ '--', expected_local_file,
1812
+ '%s@%s:%s' % (expected_user, expected_ip, expected_remote_file)]
1813
+
1814
+ if LOGGER.level <= logging.DEBUG:
1815
+ expected_command.insert(-5, '-v')
1816
+
1817
+ command.SetFlags(flag_values)
1818
+ mock_instance_resource = {
1819
+ 'networkInterfaces': [{'accessConfigs': [{'type': 'ONE_TO_ONE_NAT',
1820
+ 'natIP': expected_ip}]}],
1821
+ 'status': 'RUNNING'}
1822
+
1823
+ command_line = command._BuildSshCmd(mock_instance_resource, 'scp', scp_args)
1824
+
1825
+ self.assertEqual(expected_command, command_line)
1826
+
1827
+ def testScpPullGeneratesCorrectArguments(self):
1828
+ class MockGetApi(object):
1829
+ def __init__(self, nat_ip='0.0.0.0'):
1830
+ self._nat_ip = nat_ip
1831
+
1832
+ def instances(self):
1833
+ return self
1834
+
1835
+ def get(self, *unused_args, **unused_kwargs):
1836
+ return self
1837
+
1838
+ def execute(self):
1839
+ return {'status': 'RUNNING'}
1840
+
1841
+ flag_values = copy.deepcopy(FLAGS)
1842
+ command = instance_cmds.PullFromInstance('pull', flag_values)
1843
+
1844
+ command._instances_api = MockGetApi()
1845
+
1846
+ argv = ['file1', '%file2', 'destination']
1847
+ expected_arg_list = ['-r', '-P', '%(port)d', '--',
1848
+ '%(user)s@%(host)s:file1',
1849
+ '%(user)s@%(host)s:%%file2',
1850
+ 'destination']
1851
+
1852
+ arg_list = command._GenerateScpArgs(*argv)
1853
+
1854
+ self.assertEqual(expected_arg_list, arg_list)
1855
+
1856
+ def testScpPullGeneratesCorrectCommand(self):
1857
+ flag_values = copy.deepcopy(FLAGS)
1858
+ command = instance_cmds.PushToInstance('push', flag_values)
1859
+
1860
+ expected_project = 'test_project'
1861
+ expected_ip = '1.1.1.1'
1862
+ expected_port = 22
1863
+ expected_user = 'test_user'
1864
+ expected_ssh_file = 'test_file'
1865
+ expected_local_file = 'test_source'
1866
+ expected_remote_file = 'test_remote'
1867
+ flag_values.project = expected_project
1868
+ flag_values.ssh_port = expected_port
1869
+ flag_values.ssh_user = expected_user
1870
+ flag_values.private_key_file = expected_ssh_file
1871
+
1872
+ scp_args = ['-P', '%(port)d', '--']
1873
+ unused_argv = ('', expected_remote_file, expected_local_file)
1874
+
1875
+ escaped_args = [a.replace('%', '%%') for a in unused_argv]
1876
+ for arg in escaped_args[1:-1]:
1877
+ scp_args.append('%(user)s@%(host)s:' + arg)
1878
+ scp_args.append(escaped_args[-1])
1879
+
1880
+ expected_command = [
1881
+ 'scp',
1882
+ '-o', 'UserKnownHostsFile=/dev/null',
1883
+ '-o', 'CheckHostIP=no',
1884
+ '-o', 'StrictHostKeyChecking=no',
1885
+ '-i', expected_ssh_file,
1886
+ '-P', str(expected_port),
1887
+ '--', '%s@%s:%s' % (expected_user, expected_ip, expected_remote_file),
1888
+ expected_local_file
1889
+ ]
1890
+ if LOGGER.level <= logging.DEBUG:
1891
+ expected_command.insert(-5, '-v')
1892
+
1893
+ command.SetFlags(flag_values)
1894
+ mock_instance_resource = {
1895
+ 'networkInterfaces': [{'accessConfigs': [{'type': 'ONE_TO_ONE_NAT',
1896
+ 'natIP': expected_ip}]}],
1897
+ 'status': 'RUNNING'}
1898
+
1899
+ command_line = command._BuildSshCmd(mock_instance_resource, 'scp', scp_args)
1900
+ self.assertEqual(expected_command, command_line)
1901
+
1902
+
1903
+ if __name__ == '__main__':
1904
+ unittest.main()