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,342 @@
1
+ # Copyright 2012 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Commands for interacting with Google Compute Engine persistent disks."""
16
+
17
+
18
+
19
+ import time
20
+
21
+
22
+ from google.apputils import app
23
+ from google.apputils import appcommands
24
+ import gflags as flags
25
+
26
+ from gcutil import command_base
27
+ from gcutil import gcutil_logging
28
+
29
+
30
+ FLAGS = flags.FLAGS
31
+ LOGGER = gcutil_logging.LOGGER
32
+
33
+
34
+ class DiskCommand(command_base.GoogleComputeCommand):
35
+ """Base command for working with the disks collection."""
36
+
37
+ default_sort_field = 'name'
38
+ summary_fields = (('name', 'name'),
39
+ ('description', 'description'),
40
+ ('zone', 'zone'),
41
+ ('status', 'status'),
42
+ ('source-snapshot', 'sourceSnapshot'),
43
+ ('size-gb', 'sizeGb'))
44
+
45
+ detail_fields = (('name', 'name'),
46
+ ('description', 'description'),
47
+ ('creation-time', 'creationTimestamp'),
48
+ ('zone', 'zone'),
49
+ ('status', 'status'),
50
+ ('source-snapshot', 'sourceSnapshot'),
51
+ ('size-gb', 'sizeGb'))
52
+
53
+ resource_collection_name = 'disks'
54
+
55
+ def __init__(self, name, flag_values):
56
+ super(DiskCommand, self).__init__(name, flag_values)
57
+
58
+ flags.DEFINE_string('zone',
59
+ None,
60
+ 'The zone for this request.',
61
+ flag_values=flag_values)
62
+
63
+ def SetApi(self, api):
64
+ """Set the Google Compute Engine API for the command.
65
+
66
+ Args:
67
+ api: The Google Compute Engine API used by this command.
68
+
69
+ Returns:
70
+ None.
71
+
72
+ """
73
+ self._disks_api = api.disks()
74
+ self._zones_api = api.zones()
75
+
76
+ def _PrepareRequestArgs(self, disk_name, **other_args):
77
+ """Gets the dictionary of API method keyword arguments.
78
+
79
+ Args:
80
+ disk_name: The name of the disk.
81
+ **other_args: Keyword arguments that should be included in the request.
82
+
83
+ Returns:
84
+ Dictionary of keyword arguments that should be passed in the API call,
85
+ includes all keyword arguments passed in 'other_args' plus
86
+ common keys such as the name of the resource and the project.
87
+ """
88
+
89
+ kwargs = {
90
+ 'project': self._project,
91
+ 'disk': self.DenormalizeResourceName(disk_name)
92
+ }
93
+ if self._IsUsingAtLeastApiVersion('v1beta14') and self._flags.zone:
94
+ kwargs['zone'] = self._flags.zone
95
+ for key, value in other_args.items():
96
+ kwargs[key] = value
97
+ return kwargs
98
+
99
+
100
+ class AddDisk(DiskCommand):
101
+ """Create new machine disks.
102
+
103
+ More than one disk name can be specified. Multiple disks will be created in
104
+ parallel.
105
+ """
106
+
107
+ positional_args = '<disk-name-1> ... <disk-name-n>'
108
+ status_field = 'status'
109
+ _TERMINAL_STATUS = ['READY', 'FAILED']
110
+
111
+ def __init__(self, name, flag_values):
112
+ super(AddDisk, self).__init__(name, flag_values)
113
+ flags.DEFINE_string('description',
114
+ '',
115
+ 'Disk description.',
116
+ flag_values=flag_values)
117
+ flags.DEFINE_integer('size_gb',
118
+ None,
119
+ 'The size of the persistent disk in GB.',
120
+ flag_values=flag_values)
121
+ flags.DEFINE_string('source_snapshot',
122
+ None,
123
+ 'The source snapshot for this disk.',
124
+ flag_values=flag_values)
125
+ flags.DEFINE_string('source_image',
126
+ None,
127
+ 'The source image for this disk.',
128
+ flag_values=flag_values)
129
+ flags.DEFINE_boolean('wait_until_complete',
130
+ False,
131
+ 'Whether the program should wait until the disk'
132
+ ' is restored from snapshot.',
133
+ flag_values=flag_values)
134
+
135
+ def Handle(self, *disk_names):
136
+ """Add the specified disks.
137
+
138
+ Args:
139
+ *disk_names: The names of the disks to add.
140
+
141
+ Returns:
142
+ A tuple of (results, exceptions).
143
+
144
+ Raises:
145
+ CommandError: If the command is unsupported in this API version.
146
+ UsageError: If no disk names are specified.
147
+ """
148
+ if not disk_names:
149
+ raise app.UsageError('Please specify at lease one disk name.')
150
+
151
+ self._flags.zone = self._GetZone(self._flags.zone)
152
+ zone = self.NormalizeTopLevelResourceName(self._project, 'zones',
153
+ self._flags.zone)
154
+ kind = self._GetResourceApiKind('disk')
155
+
156
+ source_image = None
157
+ if self._flags.source_image:
158
+ source_image = self.NormalizeGlobalResourceName(
159
+ self._project,
160
+ 'images',
161
+ self._flags.source_image)
162
+ source_snapshot = None
163
+ if self._flags.source_snapshot:
164
+ source_snapshot = self.NormalizeGlobalResourceName(
165
+ self._project,
166
+ 'snapshots',
167
+ self._flags.source_snapshot)
168
+
169
+ kwargs = {}
170
+
171
+ if self._IsUsingAtLeastApiVersion('v1beta14'):
172
+ kwargs['zone'] = self.DenormalizeResourceName(self._flags.zone)
173
+
174
+ requests = []
175
+ for name in disk_names:
176
+ disk = {
177
+ 'kind': kind,
178
+ 'name': self.DenormalizeResourceName(name),
179
+ 'description': self._flags.description,
180
+ 'zone': zone,
181
+ }
182
+
183
+ if source_snapshot is not None:
184
+ disk['sourceSnapshot'] = source_snapshot
185
+ elif source_image is not None:
186
+ kwargs['sourceImage'] = source_image
187
+ if self._flags.size_gb:
188
+ disk['sizeGb'] = self._flags.size_gb
189
+ else:
190
+ disk['sizeGb'] = self._flags.size_gb or 10
191
+ if self._IsUsingAtLeastApiVersion('v1beta14'):
192
+ del disk['zone']
193
+
194
+ requests.append(self._disks_api.insert(project=self._project,
195
+ body=disk, **kwargs))
196
+
197
+ if self._flags.wait_until_complete and not self._flags.synchronous_mode:
198
+ LOGGER.warn('wait_until_complete specified. Implying synchronous_mode.')
199
+ self._flags.synchronous_mode = True
200
+
201
+ (results, exceptions) = self.ExecuteRequests(requests)
202
+
203
+ if self._flags.wait_until_complete:
204
+ awaiting = results
205
+ results = []
206
+ for result in awaiting:
207
+ if 'error' not in result:
208
+ result = self._WaitUntilDiskIsComplete(result)
209
+ results.append(result)
210
+
211
+ list_type = 'diskList' if self._flags.synchronous_mode else 'operationList'
212
+ return (self.MakeListResult(results, list_type), exceptions)
213
+
214
+ def _InternalGetDisk(self, disk_name):
215
+ """A simple implementation of getting current disk state.
216
+
217
+ Args:
218
+ disk_name: the name of the disk to get.
219
+
220
+ Returns:
221
+ Json containing full disk information.
222
+ """
223
+ disk_request = self._disks_api.get(**self._PrepareRequestArgs(disk_name))
224
+ return disk_request.execute()
225
+
226
+ def _WaitUntilDiskIsComplete(self, result):
227
+ """Waits for the disk to complete.
228
+
229
+ Periodically polls the server for current disk status. Exits if the
230
+ status of the disk is READY or FAILED or the maximum waiting timeout
231
+ has been reached. In both cases returns the last known disk details.
232
+
233
+ Args:
234
+ result: the current state of the disk.
235
+
236
+ Returns:
237
+ Json containing full disk information.
238
+ """
239
+ current_status = result[self.status_field]
240
+ disk_name = result['name']
241
+ start_time = time.time()
242
+ LOGGER.info('Will wait for restore for: %d seconds.',
243
+ self._flags.max_wait_time)
244
+ while (time.time() - start_time < self._flags.max_wait_time and
245
+ current_status not in self._TERMINAL_STATUS):
246
+ LOGGER.info(
247
+ 'Waiting for disk. Current status: %s. Sleeping for %ss.',
248
+ current_status, self._flags.sleep_between_polls)
249
+ time.sleep(self._flags.sleep_between_polls)
250
+ result = self._InternalGetDisk(disk_name)
251
+ current_status = result[self.status_field]
252
+ if current_status not in self._TERMINAL_STATUS:
253
+ LOGGER.warn('Timeout reached. Disk %s has not yet been restored.',
254
+ disk_name)
255
+ return result
256
+
257
+
258
+ class GetDisk(DiskCommand):
259
+ """Get a machine disk."""
260
+
261
+ positional_args = '<disk-name>'
262
+
263
+ def __init__(self, name, flag_values):
264
+ super(GetDisk, self).__init__(name, flag_values)
265
+
266
+ def Handle(self, disk_name):
267
+ """Get the specified disk.
268
+
269
+ Args:
270
+ disk_name: The name of the disk to get
271
+
272
+ Returns:
273
+ The result of getting the disk.
274
+ """
275
+ if self._IsUsingAtLeastApiVersion('v1beta14') and not self._flags.zone:
276
+ self._flags.zone = self.GetZoneForResource(self._disks_api,
277
+ disk_name)
278
+
279
+ disk_request = self._disks_api.get(**self._PrepareRequestArgs(disk_name))
280
+ return disk_request.execute()
281
+
282
+
283
+ class DeleteDisk(DiskCommand):
284
+ """Delete one or more machine disks.
285
+
286
+ If multiple disk names are specified, the disks will be deleted in parallel.
287
+ """
288
+
289
+ positional_args = '<disk-name-1> ... <disk-name-n>'
290
+ safety_prompt = 'Delete disk'
291
+
292
+ def __init__(self, name, flag_values):
293
+ super(DeleteDisk, self).__init__(name, flag_values)
294
+
295
+ def Handle(self, *disk_names):
296
+ """Delete the specified disks.
297
+
298
+ Args:
299
+ *disk_names: The names of the disks to delete
300
+
301
+ Returns:
302
+ Tuple (results, exceptions) - result of deleting the disks.
303
+ """
304
+ if self._IsUsingAtLeastApiVersion('v1beta14') and not self._flags.zone:
305
+ if len(disk_names) > 1:
306
+ self._flags.zone = self._GetZone()
307
+ else:
308
+ self._flags.zone = self.GetZoneForResource(self._disks_api,
309
+ disk_names[0])
310
+ requests = []
311
+ for disk_name in disk_names:
312
+ requests.append(self._disks_api.delete(
313
+ **self._PrepareRequestArgs(disk_name)))
314
+ results, exceptions = self.ExecuteRequests(requests)
315
+ return (self.MakeListResult(results, 'operationList'), exceptions)
316
+
317
+
318
+ class ListDisks(DiskCommand, command_base.GoogleComputeListCommand):
319
+ """List the disks for a project."""
320
+
321
+ is_global_level_collection = False
322
+ is_zone_level_collection = True
323
+
324
+ def __init__(self, name, flag_values):
325
+ super(ListDisks, self).__init__(name, flag_values)
326
+
327
+ def ListFunc(self):
328
+ """Returns the function for listing disks."""
329
+ if self._IsUsingAtLeastApiVersion('v1beta14'):
330
+ return None
331
+ return self._disks_api.list
332
+
333
+ def ListZoneFunc(self):
334
+ """Returns the function for listing disks in a zone."""
335
+ return self._disks_api.list
336
+
337
+
338
+ def AddCommands():
339
+ appcommands.AddCmd('adddisk', AddDisk)
340
+ appcommands.AddCmd('getdisk', GetDisk)
341
+ appcommands.AddCmd('deletedisk', DeleteDisk)
342
+ appcommands.AddCmd('listdisks', ListDisks)
@@ -0,0 +1,474 @@
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 persistent disk commands."""
18
+
19
+
20
+
21
+ import path_initializer
22
+ path_initializer.InitializeSysPath()
23
+
24
+ import copy
25
+ import sys
26
+
27
+ from google.apputils import app
28
+ import gflags as flags
29
+ import unittest
30
+
31
+ from gcutil import command_base
32
+ from gcutil import disk_cmds
33
+ from gcutil import mock_api
34
+
35
+
36
+ FLAGS = flags.FLAGS
37
+
38
+
39
+ class DiskCmdsTest(unittest.TestCase):
40
+
41
+ def _DoTestAddDiskGeneratesCorrectRequest(self, service_version):
42
+ flag_values = copy.deepcopy(FLAGS)
43
+
44
+ command = disk_cmds.AddDisk('adddisk', flag_values)
45
+
46
+ expected_project = 'test_project'
47
+ expected_disk = 'test_disk'
48
+ expected_description = 'test disk'
49
+ submitted_zone = 'copernicus-moon-base'
50
+ expected_size = 20
51
+ flag_values.service_version = service_version
52
+ flag_values.zone = submitted_zone
53
+ flag_values.project = expected_project
54
+ flag_values.size_gb = expected_size
55
+ flag_values.description = expected_description
56
+
57
+ command.SetFlags(flag_values)
58
+ command.SetApi(mock_api.MockApi())
59
+ command._credential = mock_api.MockCredential()
60
+
61
+ results, exceptions = command.Handle(expected_disk)
62
+ self.assertEqual(len(results['items']), 1)
63
+ self.assertEqual(exceptions, [])
64
+ result = results['items'][0]
65
+
66
+ expected_zone = command.NormalizeTopLevelResourceName(
67
+ expected_project,
68
+ 'zones',
69
+ submitted_zone)
70
+
71
+ self.assertEqual(result['project'], expected_project)
72
+ self.assertEqual(result['body']['name'], expected_disk)
73
+ self.assertEqual(result['body']['description'], expected_description)
74
+ self.assertEqual(result['body']['sizeGb'], expected_size)
75
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
76
+ self.assertEqual(submitted_zone, result['zone'])
77
+ self.assertFalse('zone' in result['body'])
78
+ else:
79
+ self.assertEqual(result['body']['zone'], expected_zone)
80
+ self.assertFalse('zone' in result)
81
+
82
+ def testAddDiskGeneratesCorrectRequest(self):
83
+ for version in command_base.SUPPORTED_VERSIONS:
84
+ self._DoTestAddDiskGeneratesCorrectRequest(version)
85
+
86
+ def _DoTestAddMultipleDisks(self, service_version):
87
+ flag_values = copy.deepcopy(FLAGS)
88
+ command = disk_cmds.AddDisk('adddisk', flag_values)
89
+
90
+ expected_kind = command._GetResourceApiKind('disk')
91
+ expected_project = 'test_project'
92
+ expected_disks = ['test-disk-%02d' % i for i in xrange(100)]
93
+ expected_description = 'test disk'
94
+ submitted_zone = 'copernicus-moon-base'
95
+ expected_size = 12
96
+
97
+ flag_values.service_version = service_version
98
+ flag_values.zone = submitted_zone
99
+ flag_values.project = expected_project
100
+ flag_values.size_gb = expected_size
101
+ flag_values.description = expected_description
102
+
103
+ command.SetFlags(flag_values)
104
+ command.SetApi(mock_api.MockApi())
105
+ command._credential = mock_api.MockCredential()
106
+
107
+ expected_zone = command.NormalizeTopLevelResourceName(
108
+ expected_project, 'zones', submitted_zone)
109
+
110
+ results, exceptions = command.Handle(*expected_disks)
111
+ self.assertEqual(exceptions, [])
112
+ results = results['items']
113
+ self.assertEqual(len(results), len(expected_disks))
114
+
115
+ for expected_disk, result in zip(expected_disks, results):
116
+ self.assertEqual(result['project'], expected_project)
117
+ self.assertEqual(result['body']['kind'], expected_kind)
118
+ self.assertEqual(result['body']['sizeGb'], expected_size)
119
+ self.assertEqual(result['body']['name'], expected_disk)
120
+ self.assertEqual(result['body']['description'], expected_description)
121
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
122
+ self.assertEqual(submitted_zone, result['zone'])
123
+ self.assertFalse('zone' in result['body'])
124
+ else:
125
+ self.assertFalse('zone' in result)
126
+ self.assertEqual(result['body']['zone'], expected_zone)
127
+
128
+ def testAddMultipleDisks(self):
129
+ for version in command_base.SUPPORTED_VERSIONS:
130
+ self._DoTestAddMultipleDisks(version)
131
+
132
+ def _DoTestAddDiskFromSnapshotGeneratesCorrectRequest(self, service_version):
133
+ flag_values = copy.deepcopy(FLAGS)
134
+
135
+ command = disk_cmds.AddDisk('adddisk', flag_values)
136
+
137
+ expected_project = 'test_project'
138
+ expected_disk = 'test_disk'
139
+ expected_description = 'test disk'
140
+ submitted_zone = 'copernicus-moon-base'
141
+ submitted_source_snapshot = 'snap1'
142
+ flag_values.service_version = service_version
143
+ flag_values.zone = submitted_zone
144
+ flag_values.project = expected_project
145
+ flag_values.description = expected_description
146
+ flag_values.source_snapshot = submitted_source_snapshot
147
+
148
+ command.SetFlags(flag_values)
149
+ command.SetApi(mock_api.MockApi())
150
+ command._credential = mock_api.MockCredential()
151
+
152
+ results, exceptions = command.Handle(expected_disk)
153
+ self.assertEqual(len(results['items']), 1)
154
+ self.assertEqual(exceptions, [])
155
+ result = results['items'][0]
156
+
157
+ expected_zone = command.NormalizeTopLevelResourceName(
158
+ expected_project,
159
+ 'zones',
160
+ submitted_zone)
161
+
162
+ expected_source_snapshot = command.NormalizeGlobalResourceName(
163
+ expected_project,
164
+ 'snapshots',
165
+ submitted_source_snapshot)
166
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
167
+ self.assertEqual(submitted_zone, result['zone'])
168
+ self.assertFalse('zone' in result['body'])
169
+ else:
170
+ self.assertFalse('zone' in result)
171
+ self.assertEqual(result['body']['zone'], expected_zone)
172
+
173
+ self.assertEqual(result['project'], expected_project)
174
+ self.assertEqual(result['body']['name'], expected_disk)
175
+ self.assertEqual(result['body']['description'], expected_description)
176
+ self.assertEqual(result['body']['sourceSnapshot'], expected_source_snapshot)
177
+
178
+ def testAddDiskFromSnapshotGeneratesCorrectRequest(self):
179
+ for version in command_base.SUPPORTED_VERSIONS:
180
+ self._DoTestAddDiskFromSnapshotGeneratesCorrectRequest(version)
181
+
182
+ def testAddDiskDefaultSizeGb(self):
183
+ flag_values = copy.deepcopy(FLAGS)
184
+
185
+ command = disk_cmds.AddDisk('adddisk', flag_values)
186
+
187
+ flag_values.zone = 'copernicus-moon-base'
188
+ flag_values.project = 'test_project'
189
+
190
+ command.SetFlags(flag_values)
191
+ command.SetApi(mock_api.MockApi())
192
+ command._credential = mock_api.MockCredential()
193
+
194
+ results, exceptions = command.Handle('disk1')
195
+ self.assertEqual(len(results['items']), 1)
196
+ self.assertEqual(exceptions, [])
197
+ result = results['items'][0]
198
+
199
+ # We did not set the size, make sure it defaults to 10GB.
200
+ self.assertEqual(10, result['body']['sizeGb'])
201
+
202
+ def testAddDiskFromImageDoesNotPassSizeGbUnlessExplicitlySet(self):
203
+ flag_values = copy.deepcopy(FLAGS)
204
+
205
+ command = disk_cmds.AddDisk('adddisk', flag_values)
206
+
207
+ flag_values.zone = 'copernicus-moon-base'
208
+ flag_values.project = 'test_project'
209
+ flag_values.source_image = 'image1'
210
+ flag_values.service_version = 'v1beta14'
211
+
212
+ command.SetFlags(flag_values)
213
+ command.SetApi(mock_api.MockApi())
214
+ command._credential = mock_api.MockCredential()
215
+
216
+ results, exceptions = command.Handle('disk1')
217
+ self.assertEqual(len(results['items']), 1)
218
+ self.assertEqual(exceptions, [])
219
+ result = results['items'][0]
220
+
221
+ # Make sure we did not pass 'sizeGb' in the body.
222
+ self.assertFalse('sizeGb' in result['body'])
223
+
224
+ def _DoTestAddDiskFromImageGeneratesCorrectRequest(self, service_version):
225
+ flag_values = copy.deepcopy(FLAGS)
226
+
227
+ command = disk_cmds.AddDisk('adddisk', flag_values)
228
+
229
+ expected_project = 'test_project'
230
+ expected_disk = 'test_disk'
231
+ expected_description = 'test disk'
232
+ expected_size_gb = 123
233
+ submitted_zone = 'copernicus-moon-base'
234
+ submitted_source_image = 'image1'
235
+ submitted_size_gb = 123
236
+ flag_values.zone = submitted_zone
237
+ flag_values.project = expected_project
238
+ flag_values.description = expected_description
239
+ flag_values.source_image = submitted_source_image
240
+ flag_values.size_gb = submitted_size_gb
241
+ flag_values.service_version = service_version
242
+
243
+ command.SetFlags(flag_values)
244
+ command.SetApi(mock_api.MockApi())
245
+ command._credential = mock_api.MockCredential()
246
+
247
+ results, exceptions = command.Handle(expected_disk)
248
+ self.assertEqual(len(results['items']), 1)
249
+ self.assertEqual(exceptions, [])
250
+ result = results['items'][0]
251
+
252
+ expected_zone = command.NormalizeTopLevelResourceName(
253
+ expected_project,
254
+ 'zones',
255
+ submitted_zone)
256
+
257
+ expected_source_image = command.NormalizeGlobalResourceName(
258
+ expected_project,
259
+ 'images',
260
+ submitted_source_image)
261
+
262
+ self.assertEqual(result['project'], expected_project)
263
+ self.assertEqual(result['body']['name'], expected_disk)
264
+ self.assertEqual(result['body']['description'], expected_description)
265
+ self.assertEqual(result['body']['sizeGb'], expected_size_gb)
266
+ self.assertEqual(result['sourceImage'], expected_source_image)
267
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
268
+ self.assertEqual(submitted_zone, result['zone'])
269
+ self.assertFalse('zone' in result['body'])
270
+ else:
271
+ self.assertEqual(result['body']['zone'], expected_zone)
272
+ self.assertFalse('zone' in result)
273
+
274
+ def testAddDiskFromImageGeneratesCorrectRequest(self):
275
+ for version in command_base.SUPPORTED_VERSIONS:
276
+ self._DoTestAddDiskFromImageGeneratesCorrectRequest(version)
277
+
278
+ def testAddDiskWithKernelGeneratesCorrectRequest(self):
279
+ flag_values = copy.deepcopy(FLAGS)
280
+
281
+ command = disk_cmds.AddDisk('adddisk', flag_values)
282
+
283
+ expected_project = 'test_project'
284
+ expected_disk = 'test_disk'
285
+ expected_description = 'test disk'
286
+ expected_size_gb = 123
287
+ submitted_zone = 'copernicus-moon-base'
288
+ submitted_size_gb = 123
289
+ flag_values.zone = submitted_zone
290
+ flag_values.project = expected_project
291
+ flag_values.description = expected_description
292
+ flag_values.size_gb = submitted_size_gb
293
+
294
+ command.SetFlags(flag_values)
295
+ command.SetApi(mock_api.MockApi())
296
+ command._credential = mock_api.MockCredential()
297
+
298
+ results, exceptions = command.Handle(expected_disk)
299
+ self.assertEqual(len(results['items']), 1)
300
+ self.assertEqual(exceptions, [])
301
+ result = results['items'][0]
302
+
303
+ expected_zone = command.NormalizeTopLevelResourceName(
304
+ expected_project,
305
+ 'zones',
306
+ submitted_zone)
307
+
308
+ self.assertEqual(result['project'], expected_project)
309
+ self.assertEqual(result['body']['name'], expected_disk)
310
+ self.assertEqual(result['body']['description'], expected_description)
311
+ self.assertEqual(result['body']['sizeGb'], expected_size_gb)
312
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
313
+ self.assertEqual(submitted_zone, result['zone'])
314
+ self.assertFalse('zone' in result['body'])
315
+ else:
316
+ self.assertFalse('zone' in result)
317
+ self.assertEqual(result['body']['zone'], expected_zone)
318
+
319
+ def testAddDiskRequiresZone(self):
320
+ flag_values = copy.deepcopy(FLAGS)
321
+
322
+ command = disk_cmds.AddDisk('adddisk', flag_values)
323
+
324
+ expected_project = 'test_project'
325
+ expected_disk = 'test_disk'
326
+ expected_description = 'test disk'
327
+ expected_size = 20
328
+ submitted_version = command_base.CURRENT_VERSION
329
+ submitted_zone = 'us-east-a'
330
+
331
+ flag_values.service_version = submitted_version
332
+ flag_values.project = expected_project
333
+ flag_values.size_gb = expected_size
334
+ flag_values.description = expected_description
335
+
336
+ command.SetFlags(flag_values)
337
+
338
+ zones = {'items': [{'name': 'us-east-a'},
339
+ {'name': 'us-east-b'},
340
+ {'name': 'us-east-c'},
341
+ {'name': 'us-west-a'}]}
342
+
343
+ class MockZonesApi(object):
344
+ def list(self, **unused_kwargs):
345
+ return mock_api.MockRequest(zones)
346
+
347
+ api = mock_api.MockApi()
348
+ api.zones = MockZonesApi
349
+ command.SetApi(api)
350
+ command._credential = mock_api.MockCredential()
351
+
352
+ expected_zone = command.NormalizeTopLevelResourceName(
353
+ expected_project,
354
+ 'zones',
355
+ submitted_zone)
356
+
357
+ mock_output = mock_api.MockOutput()
358
+ mock_input = mock_api.MockInput('1\n\r')
359
+ oldin = sys.stdin
360
+ sys.stdin = mock_input
361
+ oldout = sys.stdout
362
+ sys.stdout = mock_output
363
+
364
+ results, exceptions = command.Handle(expected_disk)
365
+ self.assertEqual(len(results['items']), 1)
366
+ self.assertEqual(exceptions, [])
367
+ result = results['items'][0]
368
+
369
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
370
+ self.assertEqual(submitted_zone, result['zone'])
371
+ self.assertFalse('zone' in result['body'])
372
+ else:
373
+ self.assertFalse('zone' in result)
374
+ self.assertEqual(result['body']['zone'], expected_zone)
375
+
376
+ sys.stdin = oldin
377
+ sys.stdout = oldout
378
+
379
+ def _DoTestGetDiskGeneratesCorrectRequest(self, service_version):
380
+ flag_values = copy.deepcopy(FLAGS)
381
+
382
+ command = disk_cmds.GetDisk('getdisk', flag_values)
383
+
384
+ expected_project = 'test_project'
385
+ expected_disk = 'test_disk'
386
+ flag_values.project = expected_project
387
+ flag_values.service_version = service_version
388
+ flag_values.zone = 'zone-a'
389
+
390
+ command.SetFlags(flag_values)
391
+ command.SetApi(mock_api.MockApi())
392
+ command._credential = mock_api.MockCredential()
393
+ submitted_zone = 'copernicus-moon-base'
394
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
395
+ flag_values.zone = submitted_zone
396
+
397
+ result = command.Handle(expected_disk)
398
+
399
+ self.assertEqual(result['project'], expected_project)
400
+ self.assertEqual(result['disk'], expected_disk)
401
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
402
+ self.assertEqual(submitted_zone, result['zone'])
403
+ else:
404
+ self.assertFalse('zone' in result)
405
+
406
+ def testGetDiskGeneratesCorrectRequest(self):
407
+ for version in command_base.SUPPORTED_VERSIONS:
408
+ self._DoTestGetDiskGeneratesCorrectRequest(version)
409
+
410
+ def _DoTestDeleteDiskGeneratesCorrectRequest(self, service_version):
411
+ flag_values = copy.deepcopy(FLAGS)
412
+
413
+ command = disk_cmds.DeleteDisk('deletedisk', flag_values)
414
+
415
+ expected_project = 'test_project'
416
+ expected_disk = 'test_disk'
417
+ flag_values.project = expected_project
418
+ flag_values.zone = 'zone-a'
419
+
420
+ command.SetFlags(flag_values)
421
+ command.SetApi(mock_api.MockApi())
422
+ flag_values.service_version = service_version
423
+ submitted_zone = 'copernicus-moon-base'
424
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
425
+ flag_values.zone = submitted_zone
426
+
427
+ command._credential = mock_api.MockCredential()
428
+
429
+ results, exceptions = command.Handle(expected_disk)
430
+ self.assertEqual(len(results['items']), 1)
431
+ self.assertEqual(exceptions, [])
432
+ result = results['items'][0]
433
+
434
+ self.assertEqual(result['project'], expected_project)
435
+ self.assertEqual(result['disk'], expected_disk)
436
+ if command._IsUsingAtLeastApiVersion('v1beta14'):
437
+ self.assertEqual(submitted_zone, result['zone'])
438
+ else:
439
+ self.assertFalse('zone' in result)
440
+
441
+ def testDeleteDiskGeneratesCorrectRequest(self):
442
+ for version in command_base.SUPPORTED_VERSIONS:
443
+ self._DoTestDeleteDiskGeneratesCorrectRequest(version)
444
+
445
+ def testDeleteMultipleDisks(self):
446
+ flag_values = copy.deepcopy(FLAGS)
447
+ command = disk_cmds.DeleteDisk('deletedisk', flag_values)
448
+
449
+ expected_project = 'test_project'
450
+ expected_disks = ['test-disk-%02d' % x for x in xrange(100)]
451
+ flag_values.project = expected_project
452
+ flag_values.zone = 'zone-a'
453
+
454
+ command.SetFlags(flag_values)
455
+ command.SetApi(mock_api.MockApi())
456
+ command._credential = mock_api.MockCredential()
457
+
458
+ results, exceptions = command.Handle(*expected_disks)
459
+ self.assertEqual(exceptions, [])
460
+ results = results['items']
461
+ self.assertEqual(len(results), len(expected_disks))
462
+
463
+ for expected_disk, result in zip(expected_disks, results):
464
+ self.assertEqual(result['project'], expected_project)
465
+ self.assertEqual(result['disk'], expected_disk)
466
+
467
+ def testAddWithNoDisk(self):
468
+ flag_values = copy.deepcopy(FLAGS)
469
+ command = disk_cmds.AddDisk('adddisk', flag_values)
470
+ self.assertRaises(app.UsageError, command.Handle)
471
+
472
+
473
+ if __name__ == '__main__':
474
+ unittest.main()