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.
- data.tar.gz.sig +2 -3
- data/CHANGELOG +4 -0
- data/LICENSE +674 -0
- data/Manifest +111 -0
- data/README.md +4 -3
- data/bin/gcutil +53 -0
- data/gcloud.gemspec +4 -3
- data/packages/gcutil-1.7.1/CHANGELOG +197 -0
- data/packages/gcutil-1.7.1/LICENSE +202 -0
- data/packages/gcutil-1.7.1/VERSION +1 -0
- data/packages/gcutil-1.7.1/gcutil +53 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/LICENSE +23 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/discovery.py +743 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/errors.py +123 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/ext/__init__.py +0 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/http.py +1443 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/mimeparse.py +172 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/model.py +385 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/schema.py +303 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/anyjson.py +32 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/appengine.py +528 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/client.py +1139 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/clientsecrets.py +105 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/crypt.py +244 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/django_orm.py +124 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/file.py +107 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/locked_file.py +343 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/multistore_file.py +379 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/tools.py +174 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/uritemplate/__init__.py +147 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/LICENSE +202 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/__init__.py +3 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/__init__.py +3 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/app.py +356 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/appcommands.py +783 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/basetest.py +1260 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/datelib.py +421 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/debug.py +60 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/file_util.py +181 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/resources.py +67 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/run_script_module.py +217 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/setup_command.py +159 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/shellutil.py +49 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/stopwatch.py +204 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/__init__.py +0 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper.py +140 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper_test.py +149 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth.py +130 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth_test.py +75 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds.py +128 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds_test.py +111 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base.py +1808 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base_test.py +1651 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta13.json +2851 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta14.json +3361 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds.py +342 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds_test.py +474 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds.py +344 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds_test.py +231 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/flags_cache.py +274 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil +89 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil_logging.py +69 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds.py +262 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds_test.py +172 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds.py +1506 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds_test.py +1904 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds.py +91 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds_test.py +56 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds.py +106 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds_test.py +59 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata.py +96 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_lib.py +357 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_test.py +84 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_api.py +420 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_metadata.py +58 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.py +824 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds_test.py +307 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds.py +178 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds_test.py +133 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds.py +181 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds_test.py +196 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/path_initializer.py +38 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds.py +173 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds_test.py +111 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes.py +61 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes_test.py +50 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds.py +276 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds_test.py +260 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys.py +266 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys_test.py +128 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/table_formatter.py +563 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool.py +188 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool_test.py +88 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils.py +208 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils_test.py +193 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version.py +17 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker.py +246 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker_test.py +271 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds.py +151 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds_test.py +60 -0
- data/packages/gcutil-1.7.1/lib/httplib2/LICENSE +21 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/__init__.py +1630 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/cacerts.txt +714 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/iri2uri.py +110 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/socks.py +438 -0
- data/packages/gcutil-1.7.1/lib/iso8601/LICENSE +20 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/iso8601.py +102 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/test_iso8601.py +111 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/AUTHORS +2 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/LICENSE +28 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags.py +2862 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags2man.py +544 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags_validators.py +187 -0
- metadata +118 -5
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,188 @@
|
|
|
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
|
+
"""A simple thread pool class for doing multiple concurrent API operations."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
import Queue
|
|
21
|
+
import sys
|
|
22
|
+
import threading
|
|
23
|
+
import time
|
|
24
|
+
import traceback
|
|
25
|
+
|
|
26
|
+
LOGGER = logging.getLogger('gcutil-logs')
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ThreadPoolError(Exception):
|
|
30
|
+
"""An error occurred in this module."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Operation(object):
|
|
35
|
+
"""An operation to be executed by the threadpool.
|
|
36
|
+
|
|
37
|
+
Override this and implement the Run() method.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self):
|
|
41
|
+
"""Initializer."""
|
|
42
|
+
self._result = None
|
|
43
|
+
self._raised_exception = False
|
|
44
|
+
|
|
45
|
+
def Run(self):
|
|
46
|
+
"""Override this method to execute this operation."""
|
|
47
|
+
raise NotImplementedError('pure virtual method called')
|
|
48
|
+
|
|
49
|
+
def _DoOperation(self):
|
|
50
|
+
"""Internal runner that captures result."""
|
|
51
|
+
try:
|
|
52
|
+
self._result = self.Run()
|
|
53
|
+
except: # pylint: disable-msg=W0702
|
|
54
|
+
self._raised_exception = True
|
|
55
|
+
a = sys.exc_info()
|
|
56
|
+
# If a string was thrown, a[1] is None. In Python 2.5, if an exception
|
|
57
|
+
# was thrown without a message, a is a 1-tuple. Otherwise, the exception
|
|
58
|
+
# object is in a[1].
|
|
59
|
+
if len(a) < 2 or a[1] is None:
|
|
60
|
+
self._result = a[0]
|
|
61
|
+
else:
|
|
62
|
+
self._result = a[1]
|
|
63
|
+
LOGGER.debug(traceback.format_exc())
|
|
64
|
+
|
|
65
|
+
def Result(self):
|
|
66
|
+
"""Get the operation's result.
|
|
67
|
+
|
|
68
|
+
If the operation is incomplete the return value will be None. If the
|
|
69
|
+
operation raised an exception, the return value will be the exception
|
|
70
|
+
object.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
The operation's result.
|
|
74
|
+
"""
|
|
75
|
+
return self._result
|
|
76
|
+
|
|
77
|
+
def RaisedException(self):
|
|
78
|
+
"""Did the operation raise an exception?
|
|
79
|
+
|
|
80
|
+
Will be False if the operation has not yet completed.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
True if an exception was raised by the operation.
|
|
84
|
+
"""
|
|
85
|
+
return self._raised_exception
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class Worker(threading.Thread):
|
|
89
|
+
"""Thread executing tasks from a given tasks queue."""
|
|
90
|
+
|
|
91
|
+
def __init__(self, queue):
|
|
92
|
+
threading.Thread.__init__(self)
|
|
93
|
+
self._queue = queue
|
|
94
|
+
self.daemon = True
|
|
95
|
+
self.start()
|
|
96
|
+
|
|
97
|
+
def run(self):
|
|
98
|
+
# pylint: disable-msg=W0212
|
|
99
|
+
while True:
|
|
100
|
+
op = self._queue.get()
|
|
101
|
+
if op is None:
|
|
102
|
+
self._queue.task_done()
|
|
103
|
+
break
|
|
104
|
+
op._DoOperation() # pylint: disable-msg=W0212
|
|
105
|
+
self._queue.task_done()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ThreadPool(object):
|
|
109
|
+
"""Pool of threads consuming tasks from a queue.
|
|
110
|
+
|
|
111
|
+
Note that operations on the thread pool itself (submitting, waiting,
|
|
112
|
+
shutdown) are not, themselves, multithread safe.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
# States
|
|
116
|
+
_NOT_RUNNING = 0
|
|
117
|
+
_RUNNING = 1
|
|
118
|
+
_TERMINATING = 3
|
|
119
|
+
_TERMINATED = 4
|
|
120
|
+
|
|
121
|
+
def __init__(self, num_threads):
|
|
122
|
+
self._queue = Queue.Queue()
|
|
123
|
+
self._num_threads = num_threads
|
|
124
|
+
self._state = self._NOT_RUNNING
|
|
125
|
+
|
|
126
|
+
self._workers = []
|
|
127
|
+
for _ in range(num_threads):
|
|
128
|
+
self._workers.append(Worker(self._queue))
|
|
129
|
+
self._state = self._RUNNING
|
|
130
|
+
|
|
131
|
+
def __del__(self):
|
|
132
|
+
# Shut down everything so that we don't leak memory.
|
|
133
|
+
if self._state == self._RUNNING:
|
|
134
|
+
self.WaitShutdown()
|
|
135
|
+
|
|
136
|
+
def Add(self, op):
|
|
137
|
+
"""Add an operation to the queue.
|
|
138
|
+
|
|
139
|
+
Note that this is not thread safe.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
op: An Operation object to add to the thread pool queue
|
|
143
|
+
|
|
144
|
+
Raises:
|
|
145
|
+
ThreadPoolError: if not in running state.
|
|
146
|
+
ValueError: if op isn't an Operation object
|
|
147
|
+
"""
|
|
148
|
+
if self._state != self._RUNNING:
|
|
149
|
+
raise ThreadPoolError('ThreadPool not running')
|
|
150
|
+
if not isinstance(op, Operation):
|
|
151
|
+
raise ValueError('Nonoperation argument to AddOperation')
|
|
152
|
+
self._queue.put(op)
|
|
153
|
+
|
|
154
|
+
def _InternalWait(self):
|
|
155
|
+
"""Wait for all items to clear.
|
|
156
|
+
|
|
157
|
+
This will come up for air once in a while so that we can capture
|
|
158
|
+
keyboard interrupt. Unfortunately Queue.join() isn't
|
|
159
|
+
interruptable.
|
|
160
|
+
"""
|
|
161
|
+
while not self._queue.empty():
|
|
162
|
+
time.sleep(0.2)
|
|
163
|
+
|
|
164
|
+
def WaitAll(self):
|
|
165
|
+
"""Wait for completion of all the tasks in the queue.
|
|
166
|
+
|
|
167
|
+
Note that this is not thread safe.
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
ThreadPoolError: if not in running state.
|
|
171
|
+
"""
|
|
172
|
+
if self._state != self._RUNNING:
|
|
173
|
+
raise ThreadPoolError('ThreadPool not running')
|
|
174
|
+
self._InternalWait()
|
|
175
|
+
|
|
176
|
+
def WaitShutdown(self):
|
|
177
|
+
"""Wait for completion of all tasks and shut down the ThreadPool.
|
|
178
|
+
|
|
179
|
+
Note that this is not thread safe.
|
|
180
|
+
"""
|
|
181
|
+
if self._state != self._RUNNING:
|
|
182
|
+
raise ThreadPoolError('ThreadPool not running')
|
|
183
|
+
self._state = self._TERMINATING
|
|
184
|
+
# Inject a set of sentinal values to have the workers exit.
|
|
185
|
+
for _ in range(self._num_threads):
|
|
186
|
+
self._queue.put(None)
|
|
187
|
+
self._InternalWait()
|
|
188
|
+
self._state = self._TERMINATED
|
|
@@ -0,0 +1,88 @@
|
|
|
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
|
+
"""Tests for thread_pool."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
import path_initializer
|
|
20
|
+
path_initializer.InitializeSysPath()
|
|
21
|
+
|
|
22
|
+
import time
|
|
23
|
+
|
|
24
|
+
import unittest
|
|
25
|
+
from gcutil import thread_pool
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestOperation(thread_pool.Operation):
|
|
29
|
+
def __init__(self, raise_exception=False, sleep_time=0):
|
|
30
|
+
thread_pool.Operation.__init__(self)
|
|
31
|
+
self.raise_exception = raise_exception
|
|
32
|
+
self.sleep_time = sleep_time
|
|
33
|
+
|
|
34
|
+
def Run(self):
|
|
35
|
+
if self.sleep_time:
|
|
36
|
+
time.sleep(self.sleep_time)
|
|
37
|
+
if self.raise_exception:
|
|
38
|
+
raise Exception('Exception!')
|
|
39
|
+
return 42
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ThreadPoolTest(unittest.TestCase):
|
|
43
|
+
def testBasic(self):
|
|
44
|
+
"""Test basic start up and shutdown."""
|
|
45
|
+
tp = thread_pool.ThreadPool(3)
|
|
46
|
+
tp.WaitShutdown()
|
|
47
|
+
|
|
48
|
+
def testSubmit(self):
|
|
49
|
+
tp = thread_pool.ThreadPool(3)
|
|
50
|
+
|
|
51
|
+
ops = []
|
|
52
|
+
for _ in xrange(20):
|
|
53
|
+
op = TestOperation()
|
|
54
|
+
ops.append(op)
|
|
55
|
+
tp.Add(op)
|
|
56
|
+
tp.WaitShutdown()
|
|
57
|
+
for op in ops:
|
|
58
|
+
self.assertEqual(op.Result(), 42)
|
|
59
|
+
self.assertFalse(op.RaisedException())
|
|
60
|
+
|
|
61
|
+
def testLongOps(self):
|
|
62
|
+
tp = thread_pool.ThreadPool(3)
|
|
63
|
+
|
|
64
|
+
ops = []
|
|
65
|
+
for _ in xrange(10):
|
|
66
|
+
op = TestOperation(sleep_time=0.1)
|
|
67
|
+
ops.append(op)
|
|
68
|
+
tp.Add(op)
|
|
69
|
+
tp.WaitShutdown()
|
|
70
|
+
for op in ops:
|
|
71
|
+
self.assertEqual(op.Result(), 42)
|
|
72
|
+
self.assertFalse(op.RaisedException())
|
|
73
|
+
|
|
74
|
+
def testExceptionOps(self):
|
|
75
|
+
tp = thread_pool.ThreadPool(3)
|
|
76
|
+
|
|
77
|
+
ops = []
|
|
78
|
+
for _ in xrange(20):
|
|
79
|
+
op = TestOperation(raise_exception=0.1)
|
|
80
|
+
ops.append(op)
|
|
81
|
+
tp.Add(op)
|
|
82
|
+
tp.WaitShutdown()
|
|
83
|
+
for op in ops:
|
|
84
|
+
self.assertEqual(str(op.Result()), 'Exception!')
|
|
85
|
+
self.assertTrue(op.RaisedException())
|
|
86
|
+
|
|
87
|
+
if __name__ == '__main__':
|
|
88
|
+
unittest.main()
|
|
@@ -0,0 +1,208 @@
|
|
|
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
|
+
"""A set of utility functions."""
|
|
16
|
+
|
|
17
|
+
import cStringIO
|
|
18
|
+
import numbers
|
|
19
|
+
import socket
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def SimpleName(entity):
|
|
26
|
+
if entity is None:
|
|
27
|
+
return ''
|
|
28
|
+
|
|
29
|
+
elif isinstance(entity, basestring):
|
|
30
|
+
if 'projects/google/' in entity:
|
|
31
|
+
return 'google/' + entity.split('/')[-1]
|
|
32
|
+
else:
|
|
33
|
+
return entity.split('/')[-1]
|
|
34
|
+
|
|
35
|
+
elif isinstance(entity, numbers.Number):
|
|
36
|
+
return str(entity)
|
|
37
|
+
|
|
38
|
+
raise ValueError('Expected number or string: ' + str(entity))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def FlattenList(list):
|
|
42
|
+
"""Flattens a list of lists."""
|
|
43
|
+
return [item for sublist in list for item in sublist]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def RegexesToFilterExpression(regexes, op='eq'):
|
|
47
|
+
"""Converts a list of regular expressions to a filter expression on name.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
regexes: A list of regular expressions to use for matching
|
|
51
|
+
resource names. Since resource names cannot contain whitespace
|
|
52
|
+
characters, regular expressions are split on whitespace (e.g.,
|
|
53
|
+
'[a-z]+ [0-9]+' will be treated as two separate regular expressions).
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The Google Compute Engine filter expression or None
|
|
57
|
+
if regexes evaluates to False.
|
|
58
|
+
"""
|
|
59
|
+
if not regexes:
|
|
60
|
+
return None
|
|
61
|
+
regexes = FlattenList(regex.split() for regex in regexes)
|
|
62
|
+
return 'name %s %s' % (op, '|'.join(regexes))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def SimplePrint(text, *args, **kwargs):
|
|
66
|
+
"""Prints the given text without a new-line character at the end."""
|
|
67
|
+
print text.format(*args, **kwargs),
|
|
68
|
+
sys.stdout.flush()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def ListStrings(strings, prefix=' '):
|
|
72
|
+
"""Returns a string containing each item in strings on its own line.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
strings: The list of strings to place in the result.
|
|
76
|
+
prefix: A string to place before each name.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
A string containing the names.
|
|
80
|
+
"""
|
|
81
|
+
strings = sorted(strings)
|
|
82
|
+
buf = cStringIO.StringIO()
|
|
83
|
+
for string in strings:
|
|
84
|
+
buf.write(prefix + str(string) + '\n')
|
|
85
|
+
return buf.getvalue().rstrip()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def Proceed(message=None):
|
|
89
|
+
"""Prompts the user to proceed.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
message: An optional message to include before
|
|
93
|
+
'Proceed? [y/N] ' is printed.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
True if the user answers yes.
|
|
97
|
+
"""
|
|
98
|
+
message = ((message or '') + ' Proceed? [y/N] ').lstrip()
|
|
99
|
+
return raw_input(message).strip().lower() == 'y'
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def ParseProtocol(protocol_string):
|
|
103
|
+
"""Attempt to parse a protocol number from a string.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
protocol_string: The string to parse.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
The corresponding protocol number.
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ValueError: If the protocol_string is not a valid protocol string.
|
|
113
|
+
"""
|
|
114
|
+
try:
|
|
115
|
+
protocol = socket.getprotobyname(protocol_string)
|
|
116
|
+
except (socket.error, TypeError):
|
|
117
|
+
try:
|
|
118
|
+
protocol = int(protocol_string)
|
|
119
|
+
except (ValueError, TypeError):
|
|
120
|
+
raise ValueError('Invalid protocol: %s' % protocol_string)
|
|
121
|
+
|
|
122
|
+
return protocol
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def ReplacePortNames(port_range_string):
|
|
126
|
+
"""Replace port names with port numbers in a port-range string.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
port_range_string: The string to parse.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
A port range string specifying ports only by number.
|
|
133
|
+
|
|
134
|
+
Raises:
|
|
135
|
+
ValueError: If the port_range_string is the wrong type or malformed.
|
|
136
|
+
"""
|
|
137
|
+
if not isinstance(port_range_string, basestring):
|
|
138
|
+
raise ValueError('Invalid port range: %s' % port_range_string)
|
|
139
|
+
|
|
140
|
+
ports = port_range_string.split('-')
|
|
141
|
+
if len(ports) not in [1, 2]:
|
|
142
|
+
raise ValueError('Invalid port range: %s' % port_range_string)
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
low_port = socket.getservbyname(ports[0])
|
|
146
|
+
except socket.error:
|
|
147
|
+
low_port = int(ports[0])
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
high_port = socket.getservbyname(ports[-1])
|
|
151
|
+
except socket.error:
|
|
152
|
+
high_port = int(ports[-1])
|
|
153
|
+
|
|
154
|
+
if low_port == high_port:
|
|
155
|
+
return '%d' % low_port
|
|
156
|
+
else:
|
|
157
|
+
return '%d-%d' % (low_port, high_port)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def Singularize(string):
|
|
161
|
+
"""A naive function for singularizing Compute Engine collection names."""
|
|
162
|
+
return string[:len(string) - 1] if string.endswith('s') else string
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def All(func, project, max_results=None, filter=None, zone=None):
|
|
166
|
+
"""Calls the given list function while taking care of paging logic.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
func: A Google Compute Engine list function.
|
|
170
|
+
project: The project to query.
|
|
171
|
+
max_results: The maximum number of items to return.
|
|
172
|
+
filter: The filter expression to plumb through.
|
|
173
|
+
zone: The zone for list functions that require a zone.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
A list of the resources.
|
|
177
|
+
"""
|
|
178
|
+
params = {
|
|
179
|
+
'project': project,
|
|
180
|
+
'maxResults': max_results,
|
|
181
|
+
'filter': filter}
|
|
182
|
+
|
|
183
|
+
if zone:
|
|
184
|
+
params['zone'] = zone
|
|
185
|
+
|
|
186
|
+
items = []
|
|
187
|
+
while True:
|
|
188
|
+
res = func(**params).execute()
|
|
189
|
+
kind = res.get('kind')
|
|
190
|
+
items.extend(res.get('items', []))
|
|
191
|
+
|
|
192
|
+
next_page_token = res.get('nextPageToken')
|
|
193
|
+
if not next_page_token:
|
|
194
|
+
break
|
|
195
|
+
|
|
196
|
+
params['pageToken'] = next_page_token
|
|
197
|
+
|
|
198
|
+
if max_results is not None:
|
|
199
|
+
items = items[:max_results]
|
|
200
|
+
return {'kind': kind,
|
|
201
|
+
'items': items}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def AllNames(func, project, max_results=None, filter=None, zone=None):
|
|
205
|
+
"""Like All, except returns a list of the names of the resources."""
|
|
206
|
+
list_res = All(
|
|
207
|
+
func, project, max_results=max_results, filter=filter, zone=zone)
|
|
208
|
+
return [resource.get('name') for resource in list_res.get('items', [])]
|