161
by Curtis Hovey
Windows and py3 compatability. |
1 |
from __future__ import print_function |
2 |
||
2
by Aaron Bentley
Added initial deploy_stack. |
3 |
__metaclass__ = type |
4 |
||
5 |
import yaml |
|
6 |
||
7 |
from collections import defaultdict |
|
8 |
from cStringIO import StringIO |
|
9 |
from datetime import datetime, timedelta |
|
15
by Aaron Bentley
Handle HTTPException. |
10 |
import httplib |
161
by Curtis Hovey
Windows and py3 compatability. |
11 |
import os |
16
by Aaron Bentley
Handle socket.error |
12 |
import socket |
2
by Aaron Bentley
Added initial deploy_stack. |
13 |
import subprocess |
14 |
import sys |
|
139.1.2
by Aaron Bentley
Write stderr to a temp file. |
15 |
import tempfile |
10
by Aaron Bentley
Give wordpress some time to get the welcome page together. |
16 |
from time import sleep |
7
by Aaron Bentley
Validate wordpress page contents. |
17 |
import urllib2 |
2
by Aaron Bentley
Added initial deploy_stack. |
18 |
|
112.1.4
by Aaron Bentley
Read config, use it to determine whether provider is local. |
19 |
from jujuconfig import get_selected_environment |
20 |
||
2
by Aaron Bentley
Added initial deploy_stack. |
21 |
|
163
by Curtis Hovey
Extracted the windows command incase it needs to be reused. |
22 |
WIN_JUJU_CMD = os.path.join('\\', 'Progra~2', 'Juju', 'juju.exe') |
23 |
||
24 |
||
2
by Aaron Bentley
Added initial deploy_stack. |
25 |
class ErroredUnit(Exception): |
26 |
||
301.1.3
by Aaron Bentley
Remove environment name from log messages and errors. |
27 |
def __init__(self, unit_name, state): |
28 |
msg = '%s is in state %s' % (unit_name, state) |
|
19.1.14
by Aaron Bentley
More error handling fixes. |
29 |
Exception.__init__(self, msg) |
2
by Aaron Bentley
Added initial deploy_stack. |
30 |
|
31 |
||
19.1.32
by Aaron Bentley
Test until_timeout, making it a class to enable patching. |
32 |
class until_timeout: |
33 |
||
372.1.3
by Aaron Bentley
until_timeout yields remaining seconds |
34 |
"""Yields remaining number of seconds. Stops when timeout is reached.
|
12
by Aaron Bentley
Clean up. |
35 |
|
19.1.32
by Aaron Bentley
Test until_timeout, making it a class to enable patching. |
36 |
:ivar timeout: Number of seconds to wait.
|
12
by Aaron Bentley
Clean up. |
37 |
"""
|
19.1.32
by Aaron Bentley
Test until_timeout, making it a class to enable patching. |
38 |
def __init__(self, timeout): |
39 |
self.timeout = timeout |
|
40 |
self.start = self.now() |
|
41 |
||
42 |
def __iter__(self): |
|
43 |
return self |
|
44 |
||
45 |
@staticmethod
|
|
46 |
def now(): |
|
47 |
return datetime.now() |
|
48 |
||
49 |
def next(self): |
|
372.1.3
by Aaron Bentley
until_timeout yields remaining seconds |
50 |
elapsed = self.now() - self.start |
51 |
remaining = self.timeout - elapsed.total_seconds() |
|
52 |
if remaining <= 0: |
|
19.1.32
by Aaron Bentley
Test until_timeout, making it a class to enable patching. |
53 |
raise StopIteration |
372.1.3
by Aaron Bentley
until_timeout yields remaining seconds |
54 |
return remaining |
10
by Aaron Bentley
Give wordpress some time to get the welcome page together. |
55 |
|
56 |
||
19.1.18
by Aaron Bentley
Provide destroy-environment script to simplify code. |
57 |
def yaml_loads(yaml_str): |
58 |
return yaml.safe_load(StringIO(yaml_str)) |
|
59 |
||
60 |
||
185.1.1
by Aaron Bentley
Fix cloud test handling of 'Unable to connect to environment.' |
61 |
class CannotConnectEnv(subprocess.CalledProcessError): |
62 |
||
63 |
def __init__(self, e): |
|
64 |
super(CannotConnectEnv, self).__init__(e.returncode, e.cmd, e.output) |
|
65 |
||
66 |
||
19.1.18
by Aaron Bentley
Provide destroy-environment script to simplify code. |
67 |
class JujuClientDevel: |
68 |
# This client is meant to work with the latest version of juju.
|
|
69 |
# Subclasses will retain support for older versions of juju, so that the
|
|
70 |
# latest version is easy to read, and older versions can be trivially
|
|
71 |
# deleted.
|
|
72 |
||
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
73 |
def __init__(self, version, full_path): |
84.1.5
by Aaron Bentley
JujuClient stores the detected revision. |
74 |
self.version = version |
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
75 |
self.full_path = full_path |
84.1.5
by Aaron Bentley
JujuClient stores the detected revision. |
76 |
|
19.1.18
by Aaron Bentley
Provide destroy-environment script to simplify code. |
77 |
@classmethod
|
78 |
def get_version(cls): |
|
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
79 |
return subprocess.check_output(('juju', '--version')).strip() |
80 |
||
81 |
@classmethod
|
|
82 |
def get_full_path(cls): |
|
161
by Curtis Hovey
Windows and py3 compatability. |
83 |
if sys.platform == 'win32': |
163
by Curtis Hovey
Extracted the windows command incase it needs to be reused. |
84 |
return WIN_JUJU_CMD |
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
85 |
return subprocess.check_output(('which', 'juju')).rstrip('\n') |
19.1.18
by Aaron Bentley
Provide destroy-environment script to simplify code. |
86 |
|
87 |
@classmethod
|
|
88 |
def by_version(cls): |
|
89 |
version = cls.get_version() |
|
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
90 |
full_path = cls.get_full_path() |
19.1.18
by Aaron Bentley
Provide destroy-environment script to simplify code. |
91 |
if version.startswith('1.16'): |
372.1.2
by Aaron Bentley
Support supplying timeout to calls. |
92 |
raise Exception('Unsupported juju: %s' % version) |
19.1.18
by Aaron Bentley
Provide destroy-environment script to simplify code. |
93 |
else: |
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
94 |
return JujuClientDevel(version, full_path) |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
95 |
|
372.1.2
by Aaron Bentley
Support supplying timeout to calls. |
96 |
def _full_args(self, environment, command, sudo, args, timeout=None): |
196
by Curtis Hovey
Reverted most of the hacks for the juju 1.17.1 tests. Kept some test fixes. |
97 |
# sudo is not needed for devel releases.
|
19.1.33
by Aaron Bentley
Add JujuClient tests. |
98 |
e_arg = () if environment is None else ('-e', environment.environment) |
372.1.2
by Aaron Bentley
Support supplying timeout to calls. |
99 |
if timeout is None: |
100 |
prefix = () |
|
101 |
else: |
|
102 |
prefix = ('timeout', '%.2fs' % timeout) |
|
103 |
return prefix + ('juju', '--show-log', command,) + e_arg + args |
|
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
104 |
|
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
105 |
def bootstrap(self, environment): |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
106 |
"""Bootstrap, using sudo if necessary."""
|
139
by Curtis Hovey
Added hpcloud attribute based on hp auth-url. hpcloud uses 4G to ensure mysql starts. |
107 |
if environment.hpcloud: |
108 |
constraints = 'mem=4G' |
|
109 |
else: |
|
110 |
constraints = 'mem=2G' |
|
111 |
self.juju(environment, 'bootstrap', ('--constraints', constraints), |
|
107.1.3
by Aaron Bentley
Remove unnecessary --upload-tools. |
112 |
environment.needs_sudo()) |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
113 |
|
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
114 |
def destroy_environment(self, environment): |
115 |
self.juju( |
|
197
by Curtis Hovey
Alwayd destroy-environment with --force. |
116 |
None, 'destroy-environment', |
117 |
(environment.environment, '--force', '-y'), |
|
19.1.22
by Aaron Bentley
Fix up destroy-environment. |
118 |
environment.needs_sudo(), check=False) |
19.1.18
by Aaron Bentley
Provide destroy-environment script to simplify code. |
119 |
|
372.1.2
by Aaron Bentley
Support supplying timeout to calls. |
120 |
def get_juju_output(self, environment, command, *args, **kwargs): |
121 |
args = self._full_args(environment, command, False, args, |
|
122 |
timeout=kwargs.get('timeout')) |
|
139.1.2
by Aaron Bentley
Write stderr to a temp file. |
123 |
with tempfile.TemporaryFile() as stderr: |
124 |
try: |
|
125 |
return subprocess.check_output(args, stderr=stderr) |
|
126 |
except subprocess.CalledProcessError as e: |
|
127 |
stderr.seek(0) |
|
128 |
e.stderr = stderr.read() |
|
218
by Curtis Hovey
Convert MissingOrIncorrectVersionHeader to CannotConnectEnv. |
129 |
if ('Unable to connect to environment' in e.stderr |
219
by Curtis Hovey
Convert 307 status to CannotConnectEnv. |
130 |
or 'MissingOrIncorrectVersionHeader' in e.stderr |
131 |
or '307: Temporary Redirect' in e.stderr): |
|
218
by Curtis Hovey
Convert MissingOrIncorrectVersionHeader to CannotConnectEnv. |
132 |
raise CannotConnectEnv(e) |
133 |
print('!!! ' + e.stderr) |
|
134 |
raise
|
|
19.1.18
by Aaron Bentley
Provide destroy-environment script to simplify code. |
135 |
|
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
136 |
def get_status(self, environment): |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
137 |
"""Get the current status as a dict."""
|
365.1.1
by Aaron Bentley
Restore timeouts to previous values. |
138 |
for ignored in until_timeout(60): |
331.1.1
by Aaron Bentley
juju status retries on error for 30 seconds. |
139 |
try: |
140 |
return Status(yaml_loads( |
|
141 |
self.get_juju_output(environment, 'status'))) |
|
142 |
except subprocess.CalledProcessError as e: |
|
143 |
pass
|
|
144 |
raise Exception( |
|
145 |
'Timed out waiting for juju status to succeed: %s' % e) |
|
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
146 |
|
353
by Curtis Hovey
Added get_env_option(). |
147 |
def get_env_option(self, environment, option): |
354
by Curtis Hovey
Added set_env_option(). |
148 |
"""Return the value of the environment's configured option."""
|
361
by Curtis Hovey
Use get_juju_output() to get the env option. |
149 |
return self.get_juju_output(environment, 'get-env', option) |
353
by Curtis Hovey
Added get_env_option(). |
150 |
|
357
by Curtis Hovey
Separate option from values. The callee doesn't need to |
151 |
def set_env_option(self, environment, option, value): |
152 |
"""Set the value of the option in the environment."""
|
|
153 |
option_value = "%s=%s" % (option, value) |
|
354
by Curtis Hovey
Added set_env_option(). |
154 |
return self.juju(environment, 'set-env', (option_value,)) |
353
by Curtis Hovey
Added get_env_option(). |
155 |
|
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
156 |
def juju(self, environment, command, args, sudo=False, check=True): |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
157 |
"""Run a command under juju for the current environment."""
|
107.1.2
by Aaron Bentley
Use full path when running under sudo. |
158 |
args = self._full_args(environment, command, sudo, args) |
161
by Curtis Hovey
Windows and py3 compatability. |
159 |
print(' '.join(args)) |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
160 |
sys.stdout.flush() |
19.1.19
by Aaron Bentley
Ignore status code for destroy_environment. |
161 |
if check: |
19.1.23
by Aaron Bentley
Return when running check_call. |
162 |
return subprocess.check_call(args) |
19.1.19
by Aaron Bentley
Ignore status code for destroy_environment. |
163 |
return subprocess.call(args) |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
164 |
|
165 |
||
34.1.3
by Aaron Bentley
Add status and environment tests. |
166 |
class Status: |
167 |
||
168 |
def __init__(self, status): |
|
169 |
self.status = status |
|
170 |
||
171 |
def agent_items(self): |
|
172 |
for machine_name, machine in sorted(self.status['machines'].items()): |
|
173 |
yield machine_name, machine |
|
174 |
for service in sorted(self.status['services'].values()): |
|
175 |
for unit_name, unit in service.get('units', {}).items(): |
|
176 |
yield unit_name, unit |
|
177 |
||
178 |
def agent_states(self): |
|
179 |
"""Map agent states to the units and machines in those states."""
|
|
180 |
states = defaultdict(list) |
|
181 |
for item_name, item in self.agent_items(): |
|
182 |
states[item.get('agent-state', 'no-agent')].append(item_name) |
|
183 |
return states |
|
184 |
||
185 |
def check_agents_started(self, environment_name): |
|
186 |
"""Check whether all agents are in the 'started' state.
|
|
187 |
||
188 |
If not, return agent_states output. If so, return None.
|
|
189 |
If an error is encountered for an agent, raise ErroredUnit
|
|
190 |
"""
|
|
191 |
# Look for errors preventing an agent from being installed
|
|
192 |
for item_name, item in self.agent_items(): |
|
193 |
state_info = item.get('agent-state-info', '') |
|
194 |
if 'error' in state_info: |
|
301.1.3
by Aaron Bentley
Remove environment name from log messages and errors. |
195 |
raise ErroredUnit(item_name, state_info) |
34.1.3
by Aaron Bentley
Add status and environment tests. |
196 |
states = self.agent_states() |
197 |
if states.keys() == ['started']: |
|
198 |
return None |
|
199 |
for state, entries in states.items(): |
|
200 |
if 'error' in state: |
|
301.1.3
by Aaron Bentley
Remove environment name from log messages and errors. |
201 |
raise ErroredUnit(entries[0], state) |
34.1.3
by Aaron Bentley
Add status and environment tests. |
202 |
return states |
203 |
||
84.1.4
by Aaron Bentley
Move version-dicting to jujupy. |
204 |
def get_agent_versions(self): |
205 |
versions = defaultdict(set) |
|
206 |
for item_name, item in self.agent_items(): |
|
207 |
versions[item.get('agent-version', 'unknown')].add(item_name) |
|
208 |
return versions |
|
209 |
||
34.1.3
by Aaron Bentley
Add status and environment tests. |
210 |
|
2
by Aaron Bentley
Added initial deploy_stack. |
211 |
class Environment: |
212 |
||
112.1.4
by Aaron Bentley
Read config, use it to determine whether provider is local. |
213 |
def __init__(self, environment, client=None, config=None): |
2
by Aaron Bentley
Added initial deploy_stack. |
214 |
self.environment = environment |
34.1.3
by Aaron Bentley
Add status and environment tests. |
215 |
self.client = client |
112.1.4
by Aaron Bentley
Read config, use it to determine whether provider is local. |
216 |
self.config = config |
217 |
if self.config is not None: |
|
218 |
self.local = bool(self.config.get('type') == 'local') |
|
139
by Curtis Hovey
Added hpcloud attribute based on hp auth-url. hpcloud uses 4G to ensure mysql starts. |
219 |
self.hpcloud = bool( |
220 |
'hpcloudsvc' in self.config.get('auth-url', '')) |
|
112.1.4
by Aaron Bentley
Read config, use it to determine whether provider is local. |
221 |
else: |
222 |
self.local = False |
|
139
by Curtis Hovey
Added hpcloud attribute based on hp auth-url. hpcloud uses 4G to ensure mysql starts. |
223 |
self.hpcloud = False |
112.1.4
by Aaron Bentley
Read config, use it to determine whether provider is local. |
224 |
|
225 |
@classmethod
|
|
226 |
def from_config(cls, name): |
|
227 |
client = JujuClientDevel.by_version() |
|
228 |
return cls(name, client, get_selected_environment(name)[0]) |
|
2
by Aaron Bentley
Added initial deploy_stack. |
229 |
|
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
230 |
def needs_sudo(self): |
84.1.7
by Aaron Bentley
Append .1 to local-provider version numbers. |
231 |
return self.local |
2
by Aaron Bentley
Added initial deploy_stack. |
232 |
|
19.1.11
by Aaron Bentley
Update bootstrap to sudo for local provider. |
233 |
def bootstrap(self): |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
234 |
return self.client.bootstrap(self) |
19.1.11
by Aaron Bentley
Update bootstrap to sudo for local provider. |
235 |
|
112.1.5
by Aaron Bentley
Use config to determine whether upgrades are local. |
236 |
def upgrade_juju(self): |
112.1.7
by Aaron Bentley
Fix upgrade command. |
237 |
args = ('--version', self.get_matching_agent_version(no_build=True)) |
112.1.5
by Aaron Bentley
Use config to determine whether upgrades are local. |
238 |
if self.local: |
239 |
args += ('--upload-tools',) |
|
240 |
self.client.juju(self, 'upgrade-juju', args) |
|
241 |
||
19.1.21
by Aaron Bentley
Provide destroy_environment on Environment itself. |
242 |
def destroy_environment(self): |
243 |
return self.client.destroy_environment(self) |
|
244 |
||
339.1.1
by Aaron Bentley
Use deploy method, tweak exception reporting. |
245 |
def deploy(self, charm): |
246 |
args = (charm,) |
|
247 |
return self.juju('deploy', *args) |
|
248 |
||
2
by Aaron Bentley
Added initial deploy_stack. |
249 |
def juju(self, command, *args): |
19.1.17
by Aaron Bentley
Isolate client to support incompatible command line changes. |
250 |
return self.client.juju(self, command, args) |
251 |
||
252 |
def get_status(self): |
|
253 |
return self.client.get_status(self) |
|
2
by Aaron Bentley
Added initial deploy_stack. |
254 |
|
349
by Curtis Hovey
Allow the caller to specify the timeout. |
255 |
def wait_for_started(self, timeout=1200): |
12
by Aaron Bentley
Clean up. |
256 |
"""Wait until all unit/machine agents are 'started'."""
|
349
by Curtis Hovey
Allow the caller to specify the timeout. |
257 |
for ignored in until_timeout(timeout): |
217
by Curtis Hovey
Continue when a CannotConnectEnv error is reaised from get_status. |
258 |
try: |
259 |
status = self.get_status() |
|
260 |
except CannotConnectEnv: |
|
261 |
print('Supressing "Unable to connect to environment"') |
|
262 |
continue
|
|
34.1.3
by Aaron Bentley
Add status and environment tests. |
263 |
states = status.check_agents_started(self.environment) |
264 |
if states is None: |
|
19.1.1
by Aaron Bentley
Add wait_for_agent_update.py |
265 |
break
|
301.1.3
by Aaron Bentley
Remove environment name from log messages and errors. |
266 |
print(format_listing(states, 'started')) |
4
by Aaron Bentley
Tweak output. |
267 |
sys.stdout.flush() |
10
by Aaron Bentley
Give wordpress some time to get the welcome page together. |
268 |
else: |
73.1.1
by Aaron Bentley
Make timeout exception more specific. |
269 |
raise Exception('Timed out waiting for agents to start in %s.' % |
270 |
self.environment) |
|
19.1.3
by Aaron Bentley
Fix wait_for_started logic. |
271 |
return status |
2
by Aaron Bentley
Added initial deploy_stack. |
272 |
|
84.1.6
by Aaron Bentley
Ensure agent-version match. |
273 |
def wait_for_version(self, version): |
365.1.1
by Aaron Bentley
Restore timeouts to previous values. |
274 |
for ignored in until_timeout(300): |
139.1.1
by Aaron Bentley
Try handling Unable to connect to environment gracefully. |
275 |
try: |
352
by Curtis Hovey
Fix test by not passing unknown values to get_status(). |
276 |
versions = self.get_status().get_agent_versions() |
196
by Curtis Hovey
Reverted most of the hacks for the juju 1.17.1 tests. Kept some test fixes. |
277 |
except CannotConnectEnv: |
185.1.1
by Aaron Bentley
Fix cloud test handling of 'Unable to connect to environment.' |
278 |
print('Supressing "Unable to connect to environment"') |
279 |
continue
|
|
84.1.6
by Aaron Bentley
Ensure agent-version match. |
280 |
if versions.keys() == [version]: |
281 |
break
|
|
301.1.3
by Aaron Bentley
Remove environment name from log messages and errors. |
282 |
print(format_listing(versions, version)) |
84.1.6
by Aaron Bentley
Ensure agent-version match. |
283 |
sys.stdout.flush() |
284 |
else: |
|
285 |
raise Exception('Some versions did not update.') |
|
286 |
||
112.1.7
by Aaron Bentley
Fix upgrade command. |
287 |
def get_matching_agent_version(self, no_build=False): |
84.1.7
by Aaron Bentley
Append .1 to local-provider version numbers. |
288 |
version_number = self.client.version.split('-')[0] |
233.1.18
by Aaron Bentley
Stop using --upload-tools for manual provider. |
289 |
if not no_build and self.local: |
84.1.7
by Aaron Bentley
Append .1 to local-provider version numbers. |
290 |
version_number += '.1' |
291 |
return version_number |
|
84.1.6
by Aaron Bentley
Ensure agent-version match. |
292 |
|
353
by Curtis Hovey
Added get_env_option(). |
293 |
def set_testing_tools_metadata_url(self): |
355
by Curtis Hovey
Added set_testing_tools_metadata_url(). |
294 |
url = self.client.get_env_option(self, 'tools-metadata-url') |
358
by Curtis Hovey
Do not change the tools-metadata-url if it already has 'testing' |
295 |
if 'testing' not in url: |
296 |
testing_url = url.replace('/tools', '/testing/tools') |
|
297 |
self.client.set_env_option(self, 'tools-metadata-url', testing_url) |
|
353
by Curtis Hovey
Added get_env_option(). |
298 |
|
2
by Aaron Bentley
Added initial deploy_stack. |
299 |
|
301.1.3
by Aaron Bentley
Remove environment name from log messages and errors. |
300 |
def format_listing(listing, expected): |
19.1.1
by Aaron Bentley
Add wait_for_agent_update.py |
301 |
value_listing = [] |
302 |
for value, entries in listing.items(): |
|
303 |
if value == expected: |
|
304 |
continue
|
|
305 |
value_listing.append('%s: %s' % (value, ', '.join(entries))) |
|
301.1.3
by Aaron Bentley
Remove environment name from log messages and errors. |
306 |
return ' | '.join(value_listing) |
307 |
||
308 |
||
309 |
def check_wordpress(host): |
|
12
by Aaron Bentley
Clean up. |
310 |
""""Check whether Wordpress has come up successfully.
|
311 |
||
312 |
Times out after 30 seconds.
|
|
313 |
"""
|
|
7
by Aaron Bentley
Validate wordpress page contents. |
314 |
welcome_text = ('Welcome to the famous five minute WordPress' |
315 |
' installation process!') |
|
11
by Aaron Bentley
Add url to error. |
316 |
url = 'http://%s/wp-admin/install.php' % host |
10
by Aaron Bentley
Give wordpress some time to get the welcome page together. |
317 |
for ignored in until_timeout(30): |
318 |
try: |
|
11
by Aaron Bentley
Add url to error. |
319 |
page = urllib2.urlopen(url) |
16
by Aaron Bentley
Handle socket.error |
320 |
except (urllib2.URLError, httplib.HTTPException, socket.error): |
10
by Aaron Bentley
Give wordpress some time to get the welcome page together. |
321 |
pass
|
322 |
else: |
|
323 |
if welcome_text in page.read(): |
|
324 |
break
|
|
12
by Aaron Bentley
Clean up. |
325 |
# Let's not DOS wordpress
|
10
by Aaron Bentley
Give wordpress some time to get the welcome page together. |
326 |
sleep(1) |
327 |
else: |
|
19.1.24
by Aaron Bentley
Mention environment in more places. |
328 |
raise Exception( |
301.1.3
by Aaron Bentley
Remove environment name from log messages and errors. |
329 |
'Cannot get welcome screen at %s' % (url)) |