googlecloud 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. data.tar.gz.sig +0 -0
  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/googlecloud.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()