gcloud 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 +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()