Merge lp:~therve/pyjuju/rapi-uuid into lp:~hazmat/pyjuju/rapi-rollup
- rapi-uuid
- Merge into rapi-rollup
Proposed by
Kapil Thangavelu
Status: | Merged |
---|---|
Approved by: | Kapil Thangavelu |
Approved revision: | 624 |
Merged at revision: | 626 |
Proposed branch: | lp:~therve/pyjuju/rapi-uuid |
Merge into: | lp:~hazmat/pyjuju/rapi-rollup |
Diff against target: |
2304 lines (+511/-509) 65 files modified
examples/README (+0/-24) examples/precise/mysql/config.yaml (+0/-1) examples/precise/mysql/hooks/db-relation-joined (+0/-40) examples/precise/mysql/hooks/install (+0/-32) examples/precise/mysql/hooks/start (+0/-3) examples/precise/mysql/hooks/stop (+0/-3) examples/precise/mysql/metadata.yaml (+0/-17) examples/precise/mysql/revision (+0/-1) examples/precise/php/config.yaml (+0/-5) examples/precise/php/hooks/config-changed (+0/-14) examples/precise/php/hooks/install (+0/-49) examples/precise/php/hooks/start (+0/-1) examples/precise/php/hooks/stop (+0/-3) examples/precise/php/metadata.yaml (+0/-4) examples/precise/php/revision (+0/-1) examples/precise/recorder/hooks/install (+0/-3) examples/precise/recorder/hooks/juju-info-relation-changed (+0/-5) examples/precise/recorder/hooks/juju-info-relation-departed (+0/-3) examples/precise/recorder/hooks/juju-info-relation-joined (+0/-6) examples/precise/recorder/metadata.yaml (+0/-9) examples/precise/recorder/revision (+0/-1) examples/precise/wordpress/config.yaml (+0/-7) examples/precise/wordpress/hooks/config-changed (+0/-19) examples/precise/wordpress/hooks/db-relation-changed (+0/-100) examples/precise/wordpress/hooks/install (+0/-6) examples/precise/wordpress/hooks/start (+0/-1) examples/precise/wordpress/hooks/stop (+0/-3) examples/precise/wordpress/metadata.yaml (+0/-10) examples/precise/wordpress/revision (+0/-1) juju/agents/api.py (+3/-2) juju/agents/tests/test_unit.py (+1/-0) juju/charm/tests/test_directory.py (+7/-6) juju/environment/config.py (+3/-2) juju/environment/tests/test_config.py (+0/-1) juju/hooks/invoker.py (+5/-4) juju/hooks/protocol.py (+5/-5) juju/hooks/tests/test_executor.py (+3/-1) juju/hooks/tests/test_invoker.py (+24/-20) juju/machine/tests/data/test_get_container (+2/-0) juju/machine/tests/test_unit_deployment.py (+13/-8) juju/machine/unit.py (+12/-6) juju/providers/common/cloudinit.py (+13/-3) juju/providers/maas/maas.py (+13/-2) juju/providers/maas/tests/test_maas.py (+22/-1) juju/providers/openstack/client.py (+13/-5) juju/providers/openstack/launch.py (+6/-2) juju/providers/openstack/ports.py (+27/-10) juju/providers/openstack/provider.py (+17/-0) juju/providers/openstack/tests/__init__.py (+2/-2) juju/providers/openstack/tests/test_client.py (+30/-0) juju/providers/openstack/tests/test_launch.py (+48/-1) juju/providers/openstack/tests/test_ports.py (+29/-4) juju/providers/openstack/tests/test_provider.py (+29/-0) juju/rapi/transport/tests/test_ws.py (+2/-2) juju/rapi/transport/ws.py (+7/-3) juju/state/environment.py (+10/-2) juju/state/hook.py (+18/-7) juju/state/initialize.py (+2/-0) juju/state/tests/test_environment.py (+13/-0) juju/state/tests/test_hook.py (+80/-15) juju/state/tests/test_initialize.py (+2/-0) juju/unit/deploy.py (+5/-2) juju/unit/tests/test_address.py (+2/-7) juju/unit/tests/test_deploy.py (+25/-10) juju/unit/tests/test_lifecycle.py (+18/-4) |
To merge this branch: | bzr merge lp:~therve/pyjuju/rapi-uuid |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Kapil Thangavelu | Approve | ||
Review via email: mp+143663@code.launchpad.net |
This proposal supersedes a proposal from 2013-01-17.
Commit message
Description of the change
The branch merges the changes from trunk including the new environment UUID, and expose that UUID in the first API message.
[edit to point api rollup branch]
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed directory 'examples' |
2 | === removed file 'examples/README' |
3 | --- examples/README 2011-09-29 21:11:51 +0000 |
4 | +++ examples/README 1970-01-01 00:00:00 +0000 |
5 | @@ -1,24 +0,0 @@ |
6 | -Examples |
7 | -======== |
8 | - |
9 | - |
10 | -These are some example charms that can be deployed together to create some connected services. |
11 | - |
12 | -Many more charms of greater functionality and utility exist in the Principia project, which |
13 | -currently serves as a clearinghouse for juju charms. |
14 | - |
15 | -http://launchpad.net/principia |
16 | - |
17 | - |
18 | -Deploying |
19 | -========= |
20 | - |
21 | -As an example of deploying these sample charms as services and connectinng them. |
22 | - |
23 | - $ juju bootstrap |
24 | - $ juju deploy --repository=examples local:mysql |
25 | - $ juju deploy --repository=examples local:wordpress |
26 | - $ juju add-relation wordpress mysql |
27 | - $ juju status |
28 | - |
29 | -The status command will show the address of the newly deployed wordpress service. |
30 | |
31 | === removed directory 'examples/precise' |
32 | === removed directory 'examples/precise/mysql' |
33 | === removed file 'examples/precise/mysql/config.yaml' |
34 | --- examples/precise/mysql/config.yaml 2011-06-13 20:33:35 +0000 |
35 | +++ examples/precise/mysql/config.yaml 1970-01-01 00:00:00 +0000 |
36 | @@ -1,1 +0,0 @@ |
37 | -options: {} |
38 | |
39 | === removed directory 'examples/precise/mysql/hooks' |
40 | === removed file 'examples/precise/mysql/hooks/db-relation-joined' |
41 | --- examples/precise/mysql/hooks/db-relation-joined 2011-09-30 18:52:52 +0000 |
42 | +++ examples/precise/mysql/hooks/db-relation-joined 1970-01-01 00:00:00 +0000 |
43 | @@ -1,40 +0,0 @@ |
44 | -#!/bin/bash |
45 | - |
46 | -set -eu # -x for verbose logging to juju debug-log |
47 | - |
48 | -hostname=`unit-get private-address` |
49 | - |
50 | -# Get the mysql password that was generated by the install hook |
51 | -password=`cat /var/lib/juju/mysql.passwd` |
52 | - |
53 | -# Get the database name; this takes a service unit (ex: wordpress/0) |
54 | -# and extracts just 'wordpress' |
55 | -service=`echo $JUJU_REMOTE_UNIT | cut -d/ -f1` # split on / |
56 | - |
57 | -# Determine if a database needs to be created for this service |
58 | -existing_databases=`mysql --password="$password" --silent --execute 'show databases'` |
59 | -for db in $existing_databases; do |
60 | - if [ "$db" = "$service" ] ; then |
61 | - juju-log "Database already exists, publishing details and exiting" |
62 | - service_password=`cat /var/lib/juju/$service.passwd` |
63 | - # Save these settings on the relation; this will trigger the remote |
64 | - # service unit |
65 | - relation-set database="$service" user="$service" password="$service_password" |
66 | - exit 0 # database already exists |
67 | - fi |
68 | -done |
69 | - |
70 | -# Generate a strong password for the database, using /dev/urandom |
71 | -service_password=`pwgen 10 1` |
72 | -# Store service password, new service units of same service would need it |
73 | -echo $service_password >> /var/lib/juju/$service.passwd |
74 | - |
75 | -# Create new database and corresponding security settings |
76 | -juju-log "Creating new database and corresponding security settings" |
77 | -mysqladmin --password="$password" create "$service" |
78 | -echo "grant all on $service.* to $service identified by '$service_password'" | mysql --password="$password" --database="$service" |
79 | -mysqladmin --password="$password" flush-privileges |
80 | - |
81 | -# Save these settings on the relation; this will trigger the remote |
82 | -# service unit |
83 | -relation-set database="$service" user="$service" password="$service_password" |
84 | |
85 | === removed file 'examples/precise/mysql/hooks/install' |
86 | --- examples/precise/mysql/hooks/install 2012-08-22 23:20:44 +0000 |
87 | +++ examples/precise/mysql/hooks/install 1970-01-01 00:00:00 +0000 |
88 | @@ -1,32 +0,0 @@ |
89 | -#!/bin/bash |
90 | - |
91 | -set -eu # -x for verbose logging to juju debug-log |
92 | - |
93 | -apt-get install -qqy debconf-utils python-mysqldb pwgen |
94 | - |
95 | -# Generate a strong password for the mysql service, using /dev/urandom |
96 | -PASSWORD=`pwgen 10 1` |
97 | - |
98 | -# Store the password for later use by the db-relation-changed hook for |
99 | -# this service unit. As a general note, for data that service units do |
100 | -# not need to share, simply use the machine's local file store. |
101 | -PASSFILE=/var/lib/juju/mysql.passwd |
102 | -if ! [ -f $PASSFILE ] ; then |
103 | - touch $PASSFILE |
104 | -fi |
105 | -chmod 0600 $PASSFILE |
106 | -if ! [ -s $PASSFILE ] ; then |
107 | - echo $PASSWORD >> /var/lib/juju/mysql.passwd |
108 | -fi |
109 | - |
110 | -echo mysql-server-5.1 mysql-server/root_password password $PASSWORD | debconf-set-selections |
111 | -echo mysql-server-5.1 mysql-server/root_password_again password $PASSWORD | debconf-set-selections |
112 | - |
113 | -juju-log "mysql-server settings preseeded, now installing via apt-get" |
114 | -DEBIAN_FRONTEND=noninteractive apt-get -y install -qq mysql-server |
115 | - |
116 | -juju-log "Editing my.cnf to allow listening on all interfaces" |
117 | -sed --in-place=old 's/127\.0\.0\.1/0.0.0.0/' /etc/mysql/my.cnf |
118 | - |
119 | -juju-log "Stopping mysql service" |
120 | -service mysql stop |
121 | |
122 | === removed file 'examples/precise/mysql/hooks/start' |
123 | --- examples/precise/mysql/hooks/start 2011-11-28 16:29:37 +0000 |
124 | +++ examples/precise/mysql/hooks/start 1970-01-01 00:00:00 +0000 |
125 | @@ -1,3 +0,0 @@ |
126 | -#!/bin/bash |
127 | -juju-log "Starting mysql service" |
128 | -service mysql start || service mysql restart |
129 | |
130 | === removed file 'examples/precise/mysql/hooks/stop' |
131 | --- examples/precise/mysql/hooks/stop 2011-11-28 16:29:37 +0000 |
132 | +++ examples/precise/mysql/hooks/stop 1970-01-01 00:00:00 +0000 |
133 | @@ -1,3 +0,0 @@ |
134 | -#!/bin/bash |
135 | -juju-log "Stopping mysql service" |
136 | -service mysql stop || true |
137 | |
138 | === removed file 'examples/precise/mysql/metadata.yaml' |
139 | --- examples/precise/mysql/metadata.yaml 2011-10-04 19:35:07 +0000 |
140 | +++ examples/precise/mysql/metadata.yaml 1970-01-01 00:00:00 +0000 |
141 | @@ -1,17 +0,0 @@ |
142 | -name: mysql |
143 | -summary: "MySQL relational database provider" |
144 | -description: | |
145 | - Installs and configures the MySQL package (mysqldb), then runs it. |
146 | - |
147 | - Upon a consuming service establishing a relation, creates a new |
148 | - database for that service, if the database does not yet |
149 | - exist. Publishes the following relation settings for consuming |
150 | - services: |
151 | - |
152 | - database: database name |
153 | - user: user name to access database |
154 | - password: password to access the database |
155 | - host: local hostname |
156 | -provides: |
157 | - db: |
158 | - interface: mysql |
159 | |
160 | === removed file 'examples/precise/mysql/revision' |
161 | --- examples/precise/mysql/revision 2011-10-04 19:35:07 +0000 |
162 | +++ examples/precise/mysql/revision 1970-01-01 00:00:00 +0000 |
163 | @@ -1,1 +0,0 @@ |
164 | -11 |
165 | |
166 | === removed directory 'examples/precise/php' |
167 | === removed file 'examples/precise/php/config.yaml' |
168 | --- examples/precise/php/config.yaml 2011-08-30 21:38:19 +0000 |
169 | +++ examples/precise/php/config.yaml 1970-01-01 00:00:00 +0000 |
170 | @@ -1,5 +0,0 @@ |
171 | -options: |
172 | - application_file: |
173 | - description: An application file to push. |
174 | - type: string |
175 | - |
176 | |
177 | === removed directory 'examples/precise/php/hooks' |
178 | === removed file 'examples/precise/php/hooks/config-changed' |
179 | --- examples/precise/php/hooks/config-changed 2011-09-30 18:54:44 +0000 |
180 | +++ examples/precise/php/hooks/config-changed 1970-01-01 00:00:00 +0000 |
181 | @@ -1,14 +0,0 @@ |
182 | -#!/bin/bash |
183 | - |
184 | -hostname=`unit-get public-address` |
185 | - |
186 | -app_dir="/var/www/$hostname/" |
187 | -app_file=`config-get application_file` |
188 | - |
189 | -if [ -z $app_file ]; then |
190 | - exit 0 |
191 | -fi |
192 | - |
193 | -echo "$app_file" > $app_dir/index.php |
194 | -chmod a+r $app_dir/index.php |
195 | - |
196 | |
197 | === removed file 'examples/precise/php/hooks/install' |
198 | --- examples/precise/php/hooks/install 2011-09-30 18:54:44 +0000 |
199 | +++ examples/precise/php/hooks/install 1970-01-01 00:00:00 +0000 |
200 | @@ -1,49 +0,0 @@ |
201 | -#!/bin/bash |
202 | - |
203 | -juju-log "Installing php5 via apt-get" |
204 | -set -eu # -x for verbose logging to juju debug-log |
205 | - |
206 | -apt-get -y install php5 |
207 | - |
208 | -# Create an internal secret key for wordpress; this is unrelated to |
209 | -# the password generated for the admin user of wordpress |
210 | -hostname=`unit-get public-address` |
211 | - |
212 | -SITE_PATH="/var/www/$hostname" |
213 | - |
214 | - |
215 | -juju-log "Creating appropriate upload paths and directories" |
216 | -# Setup appropriate upload paths and directories |
217 | -mkdir -p $SITE_PATH |
218 | -chown -R root:www-data $SITE_PATH |
219 | -chmod -R a+rw $SITE_PATH |
220 | -chmod a+x $SITE_PATH |
221 | - |
222 | -# Write the apache config |
223 | -# XXX a future branch will change this to use augtool |
224 | -apache_config_file_path="/etc/apache2/sites-available/$hostname" |
225 | -juju-log "Writing apache config file $apache_config_file_path" |
226 | -cat > $apache_config_file_path <<EOF |
227 | -<VirtualHost *:80> |
228 | - ServerName $hostname |
229 | - DocumentRoot /var/www/$hostname |
230 | - Options All |
231 | - ErrorLog /var/log/apache2/$hostname-error.log |
232 | - TransferLog /var/log/apache2/$hostname-access.log |
233 | - <FilesMatch \.php$> |
234 | - SetHandler application/x-httpd-php |
235 | - </FilesMatch> |
236 | -</VirtualHost> |
237 | -EOF |
238 | -chmod 0644 $apache_config_file_path |
239 | - |
240 | -# Configure apache |
241 | -juju-log "Enabling apache modules: rewrite, vhost_alias" |
242 | -a2enmod rewrite |
243 | -a2enmod vhost_alias |
244 | -juju-log "Enabling apache site: $hostname" |
245 | -a2ensite $hostname |
246 | - |
247 | -# Restart apache |
248 | -juju-log "Restarting apache2 service" |
249 | -/etc/init.d/apache2 restart |
250 | |
251 | === removed file 'examples/precise/php/hooks/start' |
252 | --- examples/precise/php/hooks/start 2011-07-01 11:40:20 +0000 |
253 | +++ examples/precise/php/hooks/start 1970-01-01 00:00:00 +0000 |
254 | @@ -1,1 +0,0 @@ |
255 | -#!/bin/bash |
256 | |
257 | === removed file 'examples/precise/php/hooks/stop' |
258 | --- examples/precise/php/hooks/stop 2011-09-15 18:56:08 +0000 |
259 | +++ examples/precise/php/hooks/stop 1970-01-01 00:00:00 +0000 |
260 | @@ -1,3 +0,0 @@ |
261 | -#!/bin/bash |
262 | -juju-log "Stopping apache" |
263 | -/etc/init.d/apache2 stop |
264 | |
265 | === removed file 'examples/precise/php/metadata.yaml' |
266 | --- examples/precise/php/metadata.yaml 2011-10-04 19:35:07 +0000 |
267 | +++ examples/precise/php/metadata.yaml 1970-01-01 00:00:00 +0000 |
268 | @@ -1,4 +0,0 @@ |
269 | -name: php |
270 | -summary: "php container" |
271 | -description: | |
272 | - PHP environment for your code. |
273 | |
274 | === removed file 'examples/precise/php/revision' |
275 | --- examples/precise/php/revision 2011-10-04 19:35:07 +0000 |
276 | +++ examples/precise/php/revision 1970-01-01 00:00:00 +0000 |
277 | @@ -1,1 +0,0 @@ |
278 | -5 |
279 | |
280 | === removed directory 'examples/precise/recorder' |
281 | === removed directory 'examples/precise/recorder/hooks' |
282 | === removed file 'examples/precise/recorder/hooks/install' |
283 | --- examples/precise/recorder/hooks/install 2012-06-22 04:24:34 +0000 |
284 | +++ examples/precise/recorder/hooks/install 1970-01-01 00:00:00 +0000 |
285 | @@ -1,3 +0,0 @@ |
286 | -#!/bin/bash |
287 | -# for testing |
288 | -open-port 8080 |
289 | \ No newline at end of file |
290 | |
291 | === removed file 'examples/precise/recorder/hooks/juju-info-relation-changed' |
292 | --- examples/precise/recorder/hooks/juju-info-relation-changed 2012-03-21 12:54:28 +0000 |
293 | +++ examples/precise/recorder/hooks/juju-info-relation-changed 1970-01-01 00:00:00 +0000 |
294 | @@ -1,5 +0,0 @@ |
295 | -#!/bin/bash |
296 | -set -x |
297 | - |
298 | -juju-log "Changed relation with $JUJU_REMOTE_UNIT" |
299 | -juju-log `relation-list` |
300 | |
301 | === removed file 'examples/precise/recorder/hooks/juju-info-relation-departed' |
302 | --- examples/precise/recorder/hooks/juju-info-relation-departed 2012-03-21 12:54:28 +0000 |
303 | +++ examples/precise/recorder/hooks/juju-info-relation-departed 1970-01-01 00:00:00 +0000 |
304 | @@ -1,3 +0,0 @@ |
305 | -#!/bin/bash |
306 | - |
307 | -juju-log "Departed from $JUJU_REMOTE_UNIT" |
308 | |
309 | === removed file 'examples/precise/recorder/hooks/juju-info-relation-joined' |
310 | --- examples/precise/recorder/hooks/juju-info-relation-joined 2012-03-21 12:54:28 +0000 |
311 | +++ examples/precise/recorder/hooks/juju-info-relation-joined 1970-01-01 00:00:00 +0000 |
312 | @@ -1,6 +0,0 @@ |
313 | -#!/bin/bash |
314 | - |
315 | -set -x |
316 | - |
317 | -juju-log "Joined with $JUJU_REMOTE_UNIT" |
318 | -juju-log `relation-list` |
319 | |
320 | === removed file 'examples/precise/recorder/metadata.yaml' |
321 | --- examples/precise/recorder/metadata.yaml 2012-03-14 22:07:28 +0000 |
322 | +++ examples/precise/recorder/metadata.yaml 1970-01-01 00:00:00 +0000 |
323 | @@ -1,9 +0,0 @@ |
324 | -name: recorder |
325 | -summary: "Subordinate test charm" |
326 | -description: | |
327 | - Records which units can see each other to show how subordinates work. |
328 | -subordinate: true |
329 | -requires: |
330 | - juju-info: |
331 | - interface: juju-info |
332 | - scope: container |
333 | |
334 | === removed file 'examples/precise/recorder/revision' |
335 | --- examples/precise/recorder/revision 2012-03-14 22:07:28 +0000 |
336 | +++ examples/precise/recorder/revision 1970-01-01 00:00:00 +0000 |
337 | @@ -1,1 +0,0 @@ |
338 | -1 |
339 | \ No newline at end of file |
340 | |
341 | === removed directory 'examples/precise/wordpress' |
342 | === removed file 'examples/precise/wordpress/config.yaml' |
343 | --- examples/precise/wordpress/config.yaml 2011-08-30 21:38:19 +0000 |
344 | +++ examples/precise/wordpress/config.yaml 1970-01-01 00:00:00 +0000 |
345 | @@ -1,7 +0,0 @@ |
346 | -options: |
347 | - plugin: |
348 | - description: | |
349 | - The URL of a wordpress plugin which will be installed and made available in the Admin UI. |
350 | - http://downloads.wordpress.org/plugin/buddypress.1.2.8.zip is a valid example. |
351 | - type: string |
352 | - |
353 | |
354 | === removed directory 'examples/precise/wordpress/hooks' |
355 | === removed file 'examples/precise/wordpress/hooks/config-changed' |
356 | --- examples/precise/wordpress/hooks/config-changed 2011-09-30 18:52:52 +0000 |
357 | +++ examples/precise/wordpress/hooks/config-changed 1970-01-01 00:00:00 +0000 |
358 | @@ -1,19 +0,0 @@ |
359 | -#!/bin/bash |
360 | - |
361 | -hostname=`unit-get public-address` |
362 | -plugin_dir="/var/www/$hostname/wp-content/plugins" |
363 | -plugin_url=`config-get plugin` |
364 | - |
365 | -base_plugin=`basename ${plugin_url}` |
366 | - |
367 | -cd /tmp |
368 | - |
369 | -curl -O ${plugin_url} |
370 | - |
371 | -if [ $? = 0 ]; then |
372 | - cd ${plugin_dir} |
373 | - unzip /tmp/${base_plugin} |
374 | -else |
375 | - juju-log -l WARNING "Unable to fetch ${plugin_url}" |
376 | - |
377 | -fi |
378 | |
379 | === removed file 'examples/precise/wordpress/hooks/db-relation-changed' |
380 | --- examples/precise/wordpress/hooks/db-relation-changed 2011-09-30 18:52:52 +0000 |
381 | +++ examples/precise/wordpress/hooks/db-relation-changed 1970-01-01 00:00:00 +0000 |
382 | @@ -1,100 +0,0 @@ |
383 | -#!/bin/bash |
384 | - |
385 | -set -eu # -x for verbose logging to juju debug-log |
386 | - |
387 | -UPLOAD_PATH="/var/www/wp-uploads" |
388 | - |
389 | -hostname=`unit-get public-address` |
390 | -juju-log "Retrieved hostname: $hostname" |
391 | - |
392 | -# Check we haven't already been setup. |
393 | -config_file_path="/etc/wordpress/config-$hostname.php" |
394 | -if [ -f "$config_file_path" ] ; then |
395 | - juju-log "Wordpress for site $config_file_path already Configured, exiting" |
396 | - echo "Already Configured, Exiting" |
397 | - exit 0 # already setup |
398 | -fi |
399 | - |
400 | -# Get the database settings; if not set, wait for this hook to be |
401 | -# invoked again |
402 | -database=`relation-get database` |
403 | -if [ -z "$database" ] ; then |
404 | - exit 0 # wait for future handshake from database service unit |
405 | -fi |
406 | - |
407 | -# Our protocol on this interface ensures that all or none of the |
408 | -# settings are set. But we can verify the setting or the values if |
409 | -# more error checking if desired. |
410 | -user=`relation-get user` |
411 | -password=`relation-get password` |
412 | -host=`relation-get private-address` |
413 | - |
414 | -# Create an internal secret key for wordpress; this is unrelated to |
415 | -# the password generated for the admin user of wordpress |
416 | -secret_key=`pwgen 10 1` |
417 | - |
418 | -juju-log "Creating appropriate upload paths and directories" |
419 | -# Setup appropriate upload paths and directories |
420 | -ln -s /usr/share/wordpress "/var/www/$hostname" |
421 | -mkdir -p $UPLOAD_PATH |
422 | -mkdir -p "$UPLOAD_PATH/$hostname" |
423 | -chown -R root:www-data $UPLOAD_PATH |
424 | -chmod 0744 $UPLOAD_PATH |
425 | -chmod 0770 "$UPLOAD_PATH/$hostname" |
426 | -chown -R root:www-data "/var/www/$hostname/wp-content" |
427 | - |
428 | -juju-log "Writing wordpress config file $config_file_path" |
429 | -# Write the wordpress config |
430 | -cat > $config_file_path <<EOF |
431 | -<?php |
432 | -define('DB_NAME', '$database'); |
433 | -define('DB_USER', '$user'); |
434 | -define('DB_PASSWORD', '$password'); |
435 | -define('DB_HOST', '$host'); |
436 | -define('SECRET_KEY', '$secret_key'); |
437 | - |
438 | -#This will disable the update notification. |
439 | -define('WP_CORE_UPDATE', false); |
440 | - |
441 | -\$table_prefix = 'wp_'; |
442 | -\$server = '$host'; |
443 | -\$loginsql = '$user'; |
444 | -\$passsql = '$password'; |
445 | -\$base = '$database'; |
446 | -\$upload_path = '/var/www/wp-uploads/$hostname'; |
447 | -\$upload_url_path = 'http://$hostname/wp-uploads'; |
448 | -?> |
449 | -EOF |
450 | -chmod 0644 $config_file_path |
451 | - |
452 | -# Write the apache config |
453 | -# XXX a future branch will change this to use augtool |
454 | -apache_config_file_path="/etc/apache2/sites-available/$hostname" |
455 | -juju-log "Writing apache config file $apache_config_file_path" |
456 | -cat > $apache_config_file_path <<EOF |
457 | -<VirtualHost *:80> |
458 | - ServerName $hostname |
459 | - DocumentRoot /var/www/$hostname |
460 | - Options All |
461 | - ErrorLog /var/log/apache2/wp-error.log |
462 | - TransferLog /var/log/apache2/wp-access.log |
463 | - # Store uploads in /var/www/wp-uploads/$0 |
464 | - RewriteEngine On |
465 | - RewriteRule ^/wp-uploads/(.*)$ /var/www/wp-uploads/%%{HTTP_HOST}/\$1 |
466 | -</VirtualHost> |
467 | -EOF |
468 | -chmod 0644 $apache_config_file_path |
469 | - |
470 | -# Configure apache |
471 | -juju-log "Enabling apache modules: rewrite, vhost_alias" |
472 | -a2enmod rewrite |
473 | -a2enmod vhost_alias |
474 | -juju-log "Enabling apache site: $hostname" |
475 | -a2ensite $hostname |
476 | - |
477 | -# Restart apache |
478 | -juju-log "Restarting apache2 service" |
479 | -/etc/init.d/apache2 restart |
480 | - |
481 | -# Make it publicly visible, once the wordpress service is exposed |
482 | -open-port 80/tcp |
483 | |
484 | === removed file 'examples/precise/wordpress/hooks/install' |
485 | --- examples/precise/wordpress/hooks/install 2011-09-30 01:46:14 +0000 |
486 | +++ examples/precise/wordpress/hooks/install 1970-01-01 00:00:00 +0000 |
487 | @@ -1,6 +0,0 @@ |
488 | -#!/bin/bash |
489 | - |
490 | -juju-log "Installing wordpress, pwgen via apt-get" |
491 | -set -eu # -x for verbose logging to juju debug-log |
492 | - |
493 | -apt-get -y install wordpress pwgen unzip |
494 | |
495 | === removed file 'examples/precise/wordpress/hooks/start' |
496 | --- examples/precise/wordpress/hooks/start 2011-02-03 01:23:43 +0000 |
497 | +++ examples/precise/wordpress/hooks/start 1970-01-01 00:00:00 +0000 |
498 | @@ -1,1 +0,0 @@ |
499 | -#!/bin/bash |
500 | |
501 | === removed file 'examples/precise/wordpress/hooks/stop' |
502 | --- examples/precise/wordpress/hooks/stop 2011-09-15 18:56:08 +0000 |
503 | +++ examples/precise/wordpress/hooks/stop 1970-01-01 00:00:00 +0000 |
504 | @@ -1,3 +0,0 @@ |
505 | -#!/bin/bash |
506 | -juju-log "Stopping apache" |
507 | -/etc/init.d/apache2 stop |
508 | |
509 | === removed file 'examples/precise/wordpress/metadata.yaml' |
510 | --- examples/precise/wordpress/metadata.yaml 2011-10-04 19:35:07 +0000 |
511 | +++ examples/precise/wordpress/metadata.yaml 1970-01-01 00:00:00 +0000 |
512 | @@ -1,10 +0,0 @@ |
513 | -name: wordpress |
514 | -summary: "WordPress blog" |
515 | -description: | |
516 | - Installs WordPress package (wordpress). Upon the database provider |
517 | - providing the required database, and the relation settings |
518 | - necessary to access it, completes the configuration of WordPress |
519 | - and makes it available on the web. |
520 | -requires: |
521 | - db: |
522 | - interface: mysql |
523 | |
524 | === removed file 'examples/precise/wordpress/revision' |
525 | --- examples/precise/wordpress/revision 2011-10-04 19:35:07 +0000 |
526 | +++ examples/precise/wordpress/revision 1970-01-01 00:00:00 +0000 |
527 | @@ -1,1 +0,0 @@ |
528 | -31 |
529 | |
530 | === modified file 'juju/agents/api.py' |
531 | --- juju/agents/api.py 2012-12-18 01:15:02 +0000 |
532 | +++ juju/agents/api.py 2013-01-17 11:10:30 +0000 |
533 | @@ -50,10 +50,11 @@ |
534 | |
535 | self.environment = yield self.configure_environment() |
536 | self.provider = yield self._get_provider() |
537 | + env_uuid = yield self.global_settings_state.get_environment_id() |
538 | log.debug("Received environment data.") |
539 | root = Data("Juju API Server\n", "text/plain") |
540 | self.ws_factory = WebSocketAPIFactory( |
541 | - self.config['zookeeper_servers'], self.provider) |
542 | + self.config['zookeeper_servers'], self.provider, env_uuid) |
543 | yield self.ws_factory.startFactory() |
544 | |
545 | root.putChild('ws', WebSocketsResource(self.ws_factory)) |
546 | @@ -151,7 +152,7 @@ |
547 | "--port", default=default_port, type=int) |
548 | parser.add_argument("--secure", action='store_true') |
549 | parser.add_argument("--keys", default=os.getenv('JUJU_API_KEYS'), |
550 | - type=keys_directory, metavar='PATH') |
551 | + type=keys_directory, metavar='PATH') |
552 | return parser |
553 | |
554 | if __name__ == '__main__': |
555 | |
556 | === modified file 'juju/agents/tests/test_unit.py' |
557 | --- juju/agents/tests/test_unit.py 2012-09-10 03:20:20 +0000 |
558 | +++ juju/agents/tests/test_unit.py 2013-01-17 11:10:30 +0000 |
559 | @@ -35,6 +35,7 @@ |
560 | yield settings.set_provider_type("dummy") |
561 | self.change_environment( |
562 | PATH=get_cli_environ_path(), |
563 | + JUJU_ENV_UUID="snowflake", |
564 | JUJU_UNIT_NAME="mysql/0") |
565 | |
566 | @inlineCallbacks |
567 | |
568 | === modified file 'juju/charm/tests/test_directory.py' |
569 | --- juju/charm/tests/test_directory.py 2012-09-14 15:33:33 +0000 |
570 | +++ juju/charm/tests/test_directory.py 2013-01-17 11:10:30 +0000 |
571 | @@ -3,7 +3,6 @@ |
572 | import hashlib |
573 | import inspect |
574 | import shutil |
575 | -import tempfile |
576 | import zipfile |
577 | |
578 | from juju.errors import CharmError, FileNotFound |
579 | @@ -111,12 +110,12 @@ |
580 | def test_make_archive(self): |
581 | # make archive from sample directory |
582 | directory = CharmDirectory(sample_directory) |
583 | - f = tempfile.NamedTemporaryFile(suffix=".charm") |
584 | - directory.make_archive(f.name) |
585 | + f = self.makeFile(suffix=".charm") |
586 | + directory.make_archive(f) |
587 | |
588 | # open archive in .zip-format and assert integrity |
589 | from zipfile import ZipFile |
590 | - zf = ZipFile(f.name) |
591 | + zf = ZipFile(f) |
592 | self.assertEqual(zf.testzip(), None) |
593 | |
594 | # assert included |
595 | @@ -212,7 +211,8 @@ |
596 | |
597 | def test_internal_symlink(self): |
598 | charm_path = self.copy_charm() |
599 | - os.symlink("/etc/lsb-release", os.path.join(charm_path, "foobar")) |
600 | + external_file = self.makeFile(content='baz') |
601 | + os.symlink(external_file, os.path.join(charm_path, "foobar")) |
602 | |
603 | directory = CharmDirectory(charm_path) |
604 | e = self.assertRaises(InvalidCharmFile, directory.as_bundle) |
605 | @@ -220,7 +220,8 @@ |
606 | |
607 | def test_extract_symlink(self): |
608 | charm_path = self.copy_charm() |
609 | - os.symlink("/etc/lsb-release", os.path.join(charm_path, "foobar")) |
610 | + external_file = self.makeFile(content='lorem ipsum') |
611 | + os.symlink(external_file, os.path.join(charm_path, "foobar")) |
612 | |
613 | directory = CharmDirectory(charm_path) |
614 | e = self.assertRaises(InvalidCharmFile, directory.as_bundle) |
615 | |
616 | === modified file 'juju/environment/config.py' |
617 | --- juju/environment/config.py 2012-09-20 15:11:08 +0000 |
618 | +++ juju/environment/config.py 2013-01-17 11:10:30 +0000 |
619 | @@ -76,7 +76,7 @@ |
620 | optional=[ |
621 | "access-key", "secret-key", "auth-url", "project-name", |
622 | "auth-mode", "region", "use-floating-ip", |
623 | - "ssl-hostname-verification"]), |
624 | + "ssl-hostname-verification", "default-instance-type"]), |
625 | "openstack_s3": KeyDict({ |
626 | "control-bucket": String(), |
627 | "admin-secret": String(), |
628 | @@ -96,7 +96,8 @@ |
629 | optional=[ |
630 | "access-key", "secret-key", "combined-key", "auth-url", |
631 | "s3-uri", "project-name", "auth-mode", "region", |
632 | - "use-floating-ip", "ssl-hostname-verification"]), |
633 | + "use-floating-ip", "ssl-hostname-verification", |
634 | + "default-instance-type"]), |
635 | "orchestra": KeyDict({ |
636 | "orchestra-server": String(), |
637 | "orchestra-user": String(), |
638 | |
639 | === modified file 'juju/environment/tests/test_config.py' |
640 | --- juju/environment/tests/test_config.py 2012-09-27 04:36:51 +0000 |
641 | +++ juju/environment/tests/test_config.py 2013-01-17 11:10:30 +0000 |
642 | @@ -67,7 +67,6 @@ |
643 | admin-secret: sekret |
644 | control-bucket: container |
645 | default-image-id: 42 |
646 | - default-instance-type: m1-sample |
647 | default-series: precise |
648 | """ |
649 | |
650 | |
651 | === modified file 'juju/hooks/invoker.py' |
652 | --- juju/hooks/invoker.py 2012-09-28 16:22:27 +0000 |
653 | +++ juju/hooks/invoker.py 2013-01-17 11:10:30 +0000 |
654 | @@ -50,7 +50,7 @@ |
655 | exit_code = reason.value.exitCode |
656 | if exit_code == 0: |
657 | return deferred.callback(exit_code) |
658 | - elif exit_code == None and reason.value.signal: |
659 | + elif exit_code is None and reason.value.signal: |
660 | error = errors.CharmInvocationError( |
661 | self._hook_name, exit_code, signal=reason.value.signal) |
662 | else: |
663 | @@ -215,6 +215,7 @@ |
664 | JUJU_CLIENT_ID=self._client_id, |
665 | CHARM_DIR=os.path.join(self._unit_path, "charm"), |
666 | _JUJU_CHARM_FORMAT=str(self.charm_format), |
667 | + JUJU_ENV_UUID=os.environ["JUJU_ENV_UUID"], |
668 | JUJU_UNIT_NAME=os.environ["JUJU_UNIT_NAME"], |
669 | DEBIAN_FRONTEND="noninteractive", |
670 | APT_LISTCHANGES_FRONTEND="none", |
671 | @@ -234,8 +235,8 @@ |
672 | """Returns the hook context for the invocation.""" |
673 | return self._context |
674 | |
675 | - def get_relation_hook_context(self, relation_ident): |
676 | - """Returns a hook context corresponding to `relation_ident`""" |
677 | + def get_cached_relation_hook_context(self, relation_ident): |
678 | + """Returns cached hook context corresponding to `relation_ident`""" |
679 | try: |
680 | return self._relation_contexts[relation_ident] |
681 | except KeyError: |
682 | @@ -255,7 +256,7 @@ |
683 | |
684 | if not os.access(hook_filename, os.X_OK): |
685 | raise errors.CharmError(hook_filename, |
686 | - "hook is not executable") |
687 | + "hook is not executable") |
688 | |
689 | def send_signal(self, signal_id): |
690 | """Send a signal of the given signal_id. |
691 | |
692 | === modified file 'juju/hooks/protocol.py' |
693 | --- juju/hooks/protocol.py 2012-09-28 16:22:27 +0000 |
694 | +++ juju/hooks/protocol.py 2013-01-17 11:10:30 +0000 |
695 | @@ -206,7 +206,7 @@ |
696 | if relation_id: |
697 | yield self.factory.log( |
698 | logging.DEBUG, "Getting relation %s" % relation_id) |
699 | - context = yield invoker.get_relation_hook_context(relation_id) |
700 | + context = invoker.get_cached_relation_hook_context(relation_id) |
701 | require_relation_context(context) |
702 | |
703 | try: |
704 | @@ -238,7 +238,7 @@ |
705 | if relation_id: |
706 | yield self.factory.log( |
707 | logging.DEBUG, "Setting relation %s" % relation_id) |
708 | - context = yield invoker.get_relation_hook_context(relation_id) |
709 | + context = invoker.get_cached_relation_hook_context(relation_id) |
710 | require_relation_context(context) |
711 | |
712 | for k, v in data.items(): |
713 | @@ -256,8 +256,8 @@ |
714 | if relation_id: |
715 | yield self.factory.log( |
716 | logging.DEBUG, "Listing relation members for %s" % relation_id) |
717 | - context = yield self.factory.get_invoker(client_id).\ |
718 | - get_relation_hook_context(relation_id) |
719 | + invoker = yield self.factory.get_invoker(client_id) |
720 | + context = invoker.get_cached_relation_hook_context(relation_id) |
721 | require_relation_context(context) |
722 | members = yield context.get_members() |
723 | defer.returnValue(dict(members=" ".join(members))) |
724 | @@ -265,7 +265,7 @@ |
725 | @RelationIdsCommand.responder |
726 | @defer.inlineCallbacks |
727 | def relation_ids(self, client_id, relation_name): |
728 | - """Set values into state.hook.RelationHookContext. |
729 | + """Get relation idents for this hook context. |
730 | |
731 | :client_id: hooks client id that is used to define a context |
732 | for a consistent view of state. |
733 | |
734 | === modified file 'juju/hooks/tests/test_executor.py' |
735 | --- juju/hooks/tests/test_executor.py 2011-09-15 18:50:23 +0000 |
736 | +++ juju/hooks/tests/test_executor.py 2013-01-17 11:10:30 +0000 |
737 | @@ -207,7 +207,9 @@ |
738 | log = logging.getLogger("invoker") |
739 | # Populate environment variables for default invoker. |
740 | self.change_environment( |
741 | - JUJU_UNIT_NAME="dummy/1", PATH="/bin/:/usr/bin") |
742 | + JUJU_UNIT_NAME="dummy/1", |
743 | + JUJU_ENV_UUID="snowflake", |
744 | + PATH="/bin/:/usr/bin") |
745 | output = self.capture_logging("invoker", level=logging.DEBUG) |
746 | invoker = Invoker( |
747 | None, None, "constant", self.makeFile(), unit_dir, log) |
748 | |
749 | === modified file 'juju/hooks/tests/test_invoker.py' |
750 | --- juju/hooks/tests/test_invoker.py 2012-10-01 03:44:42 +0000 |
751 | +++ juju/hooks/tests/test_invoker.py 2013-01-17 11:10:30 +0000 |
752 | @@ -178,6 +178,7 @@ |
753 | "hooks") |
754 | self.change_environment( |
755 | PATH=get_cli_environ_path(test_hook_path, "/usr/bin", "/bin"), |
756 | + JUJU_ENV_UUID="snowflake", |
757 | JUJU_UNIT_NAME=local_unit, |
758 | JUJU_REMOTE_UNIT=remote_unit) |
759 | |
760 | @@ -268,8 +269,8 @@ |
761 | state["relations"]["mysql"][0]) |
762 | wpr = yield self.relation_state_manager.get_relations_for_service( |
763 | state["services"]["wordpress"]) |
764 | - wpr = [r for r in wpr if r.internal_relation_id == \ |
765 | - self.mysql_relation.internal_relation_id][0] |
766 | + wpr = [r for r in wpr if r.internal_relation_id == |
767 | + self.mysql_relation.internal_relation_id][0] |
768 | self.wordpress_relation = yield wpr.add_unit_state( |
769 | state["relations"]["wordpress"][0]) |
770 | |
771 | @@ -289,9 +290,10 @@ |
772 | yield self.wordpress_relation.set_data({"hello": "world"}) |
773 | |
774 | hook_log = self.capture_logging("hook") |
775 | - exe = yield self.ua.get_invoker("db:42", "add", "mysql/0", |
776 | - self.mysql_relation, |
777 | - client_id="client_id") |
778 | + exe = yield self.ua.get_invoker( |
779 | + "db:42", "add", "mysql/0", |
780 | + self.mysql_relation, |
781 | + client_id="client_id") |
782 | |
783 | yield exe(self.create_hook( |
784 | "relation-get", "--format=json - wordpress/0")) |
785 | @@ -542,6 +544,7 @@ |
786 | # dummy charm (this is the default charm used when the |
787 | # add_service method is use) |
788 | self.assertEqual(env["_JUJU_CHARM_FORMAT"], "1") |
789 | + self.assertEqual(env["JUJU_ENV_UUID"], "snowflake") |
790 | |
791 | @defer.inlineCallbacks |
792 | def test_missing_hook(self): |
793 | @@ -1016,7 +1019,7 @@ |
794 | self.assertEqual( |
795 | implied, |
796 | self.ua.server_factory.get_invoker("client_id").\ |
797 | - get_relation_hook_context("db:0")) |
798 | + get_cached_relation_hook_context("db:0")) |
799 | self.assertEqual( |
800 | set((yield implied.get_relation_idents("db"))), |
801 | set(["db:0", "db:1"])) |
802 | @@ -1031,32 +1034,32 @@ |
803 | # Add another relation, verify it's not yet visible |
804 | yield self.add_a_blog("wordpress3") |
805 | |
806 | - db0 = yield exe.get_relation_hook_context("db:0") |
807 | - db1 = yield exe.get_relation_hook_context("db:1") |
808 | + db0 = exe.get_cached_relation_hook_context("db:0") |
809 | + db1 = exe.get_cached_relation_hook_context("db:1") |
810 | self.assertEqual(db1.relation_ident, "db:1") |
811 | self.assertEqual( |
812 | set((yield db1.get_relation_idents("db"))), |
813 | set(["db:0", "db:1"])) |
814 | self.assertEqual( |
815 | db1, |
816 | - exe.get_relation_hook_context("db:1")) |
817 | + exe.get_cached_relation_hook_context("db:1")) |
818 | |
819 | # Not yet visible relation |
820 | self.assertRaises( |
821 | RelationStateNotFound, |
822 | - exe.get_relation_hook_context, "db:2") |
823 | + exe.get_cached_relation_hook_context, "db:2") |
824 | |
825 | # Nonexistent relation idents |
826 | self.assertRaises( |
827 | RelationStateNotFound, |
828 | - exe.get_relation_hook_context, "db:12345") |
829 | + exe.get_cached_relation_hook_context, "db:12345") |
830 | |
831 | # Reread parent and child contexts |
832 | exe = yield self.ua.get_invoker( |
833 | "db:0", "add", "mysql/0", self.relation, client_id="client_id") |
834 | db0 = yield exe.get_context() |
835 | - db1 = yield exe.get_relation_hook_context("db:1") |
836 | - db2 = yield exe.get_relation_hook_context("db:2") |
837 | + db1 = exe.get_cached_relation_hook_context("db:1") |
838 | + db2 = exe.get_cached_relation_hook_context("db:2") |
839 | |
840 | # Verify that any changes are written out; write directly here |
841 | # using the relation contexts |
842 | @@ -1107,9 +1110,9 @@ |
843 | set((yield exe.get_context().get_relation_idents("db"))), |
844 | set(["db:0", "db:1", "db:2"])) |
845 | |
846 | - db0 = yield exe.get_relation_hook_context("db:0") |
847 | - db1 = yield exe.get_relation_hook_context("db:1") |
848 | - db2 = yield exe.get_relation_hook_context("db:2") |
849 | + db0 = exe.get_cached_relation_hook_context("db:0") |
850 | + db1 = exe.get_cached_relation_hook_context("db:1") |
851 | + db2 = exe.get_cached_relation_hook_context("db:2") |
852 | |
853 | # Verify that any changes are written out; write directly here |
854 | # using the relation contexts |
855 | @@ -1152,8 +1155,9 @@ |
856 | self.assertEqual( |
857 | set((yield exe.get_context().get_relation_idents("db"))), |
858 | set(["db:0", "db:2"])) |
859 | - yield self.assertFailure((yield exe.get_relation_hook_context("db:1")), |
860 | - RelationStateNotFound) |
861 | + yield self.assertRaises( |
862 | + RelationStateNotFound, |
863 | + exe.get_cached_relation_hook_context, "db:1") |
864 | |
865 | @defer.inlineCallbacks |
866 | def test_relation_ids(self): |
867 | @@ -1288,7 +1292,7 @@ |
868 | self.assertEqual(result, 0) |
869 | yield exe.ended |
870 | |
871 | - db1 = exe.get_relation_hook_context("db:1") |
872 | + db1 = exe.get_cached_relation_hook_context("db:1") |
873 | yield self.assert_zk_data(db1, { |
874 | "a": "42", |
875 | "b": "xyz", |
876 | @@ -1363,7 +1367,7 @@ |
877 | client_id="client_id") |
878 | |
879 | # First set through the context |
880 | - db1 = exe.get_relation_hook_context("db:1") |
881 | + db1 = exe.get_cached_relation_hook_context("db:1") |
882 | yield db1.set({"name": "whiterabbit"}) |
883 | |
884 | # Then get from db:1 |
885 | |
886 | === modified file 'juju/machine/tests/data/test_get_container' |
887 | --- juju/machine/tests/data/test_get_container 2012-10-09 18:55:55 +0000 |
888 | +++ juju/machine/tests/data/test_get_container 2013-01-17 11:10:30 +0000 |
889 | @@ -25,6 +25,8 @@ |
890 | respawn |
891 | |
892 | |
893 | + env JUJU_ENV_UUID="snowflake" |
894 | + |
895 | env JUJU_HOME="/var/lib/juju" |
896 | |
897 | env JUJU_MACHINE_ID="None" |
898 | |
899 | === modified file 'juju/machine/tests/test_unit_deployment.py' |
900 | --- juju/machine/tests/test_unit_deployment.py 2012-10-05 13:55:09 +0000 |
901 | +++ juju/machine/tests/test_unit_deployment.py 2013-01-17 11:10:30 +0000 |
902 | @@ -23,6 +23,7 @@ |
903 | |
904 | DATA_DIR = os.path.join(os.path.dirname(inspect.getabsfile(tests)), "data") |
905 | |
906 | + |
907 | class UnitMachineDeploymentTest(RepositoryTestBase): |
908 | |
909 | def setUp(self): |
910 | @@ -110,7 +111,7 @@ |
911 | self.mocker.replay() |
912 | |
913 | d = self.deployment.start( |
914 | - "123", get_test_zookeeper_address(), self.bundle) |
915 | + "snowflake", "123", get_test_zookeeper_address(), self.bundle) |
916 | |
917 | def verify_upstart(_): |
918 | conf_path = os.path.join(self.init_dir, "juju-wordpress-0.conf") |
919 | @@ -130,6 +131,7 @@ |
920 | "JUJU_HOME": self.juju_directory, |
921 | "JUJU_UNIT_NAME": self.unit_name, |
922 | "JUJU_ZOOKEEPER": get_test_zookeeper_address(), |
923 | + "JUJU_ENV_UUID": "snowflake", |
924 | "JUJU_MACHINE_ID": "123"}) |
925 | |
926 | log_file = os.path.join( |
927 | @@ -158,7 +160,7 @@ |
928 | self.mocker.replay() |
929 | |
930 | yield self.deployment.start( |
931 | - "0", get_test_zookeeper_address(), self.bundle) |
932 | + "snowflake", "0", get_test_zookeeper_address(), self.bundle) |
933 | |
934 | yield self.deployment.destroy() |
935 | self.assertFalse(os.path.exists(self.deployment.directory)) |
936 | @@ -190,7 +192,7 @@ |
937 | self.mocker.replay() |
938 | |
939 | yield self.deployment.start( |
940 | - "0", get_test_zookeeper_address(), self.bundle) |
941 | + "snowflake", "0", get_test_zookeeper_address(), self.bundle) |
942 | yield self.deployment.destroy() |
943 | self.assertFalse(os.path.exists(self.deployment.directory)) |
944 | |
945 | @@ -263,7 +265,7 @@ |
946 | # "unpatch" to use real /etc/init |
947 | self.patch(UpstartService, "init_dir", self.real_init_dir) |
948 | yield self.deployment.start( |
949 | - "0", get_test_zookeeper_address(), self.bundle) |
950 | + "snowflake", "0", get_test_zookeeper_address(), self.bundle) |
951 | old_pid = yield self.deployment.get_pid() |
952 | self.assert_pid_running(old_pid, True) |
953 | |
954 | @@ -292,7 +294,7 @@ |
955 | self.patch(UpstartService, "init_dir", self.real_init_dir) |
956 | |
957 | d = self.deployment.start( |
958 | - "0", get_test_zookeeper_address(), self.bundle) |
959 | + "snowflake", "0", get_test_zookeeper_address(), self.bundle) |
960 | e = yield self.assertFailure(d, UnitDeploymentError) |
961 | self.assertTrue(str(e).startswith( |
962 | "Failed to start job juju-wordpress-0; got output:\n")) |
963 | @@ -366,8 +368,10 @@ |
964 | mock_deploy = self.mocker.patch(self.unit_deploy) |
965 | # this minimally validates that we are also called with the |
966 | # expect public key |
967 | + |
968 | def is_cloudinit(obj): |
969 | return isinstance(obj, CloudInit) |
970 | + |
971 | mock_deploy._get_container("0", MATCH(is_cloudinit)) |
972 | self.mocker.result((container, rootfs)) |
973 | |
974 | @@ -379,7 +383,8 @@ |
975 | self.unit_deploy.directory = rootfs |
976 | os.makedirs(os.path.join(rootfs, "etc", "init")) |
977 | |
978 | - yield self.unit_deploy.start("0", "127.0.1.1:2181", self.bundle) |
979 | + yield self.unit_deploy.start( |
980 | + "snowflake", "0", "127.0.1.1:2181", self.bundle) |
981 | |
982 | # Verify the symlinks exist |
983 | self.assertTrue(os.path.lexists(os.path.join( |
984 | @@ -410,9 +415,9 @@ |
985 | def test_get_container(self): |
986 | rootfs = self.makeDir() |
987 | cloud_init = self.unit_deploy._get_cloud_init(zookeepers='localhost') |
988 | - |
989 | + cloud_init.set_environment_id('snowflake') |
990 | expected = serializer.load( |
991 | - open(os.path.join(DATA_DIR, 'test_get_container'))) |
992 | + open(os.path.join(DATA_DIR, 'test_get_container'))) |
993 | rendered = serializer.load(cloud_init.render()) |
994 | self.assertEquals(rendered, expected) |
995 | |
996 | |
997 | === modified file 'juju/machine/unit.py' |
998 | --- juju/machine/unit.py 2012-09-27 00:42:32 +0000 |
999 | +++ juju/machine/unit.py 2013-01-17 11:10:30 +0000 |
1000 | @@ -8,7 +8,7 @@ |
1001 | |
1002 | from juju.charm.bundle import CharmBundle |
1003 | from juju.errors import ServiceError |
1004 | -from juju.lib.lxc import LXCContainer, get_containers, LXCError |
1005 | +from juju.lib.lxc import LXCContainer, get_containers |
1006 | from juju.lib.twistutils import get_module_directory |
1007 | from juju.lib.upstart import UpstartService |
1008 | from juju.providers.common.cloudinit import CloudInit |
1009 | @@ -27,12 +27,17 @@ |
1010 | return UnitMachineDeployment |
1011 | |
1012 | |
1013 | -def _get_environment(unit_name, juju_home, machine_id, zookeeper_hosts): |
1014 | +def _get_environment(unit_name, |
1015 | + juju_home, machine_id, zookeeper_hosts, env_id): |
1016 | + """ |
1017 | + Return environment dictionary for unit. |
1018 | + """ |
1019 | environ = dict() |
1020 | environ["JUJU_MACHINE_ID"] = str(machine_id) |
1021 | environ["JUJU_UNIT_NAME"] = unit_name |
1022 | environ["JUJU_HOME"] = juju_home |
1023 | environ["JUJU_ZOOKEEPER"] = zookeeper_hosts |
1024 | + environ["JUJU_ENV_UUID"] = env_id |
1025 | environ["PYTHONPATH"] = ":".join( |
1026 | filter(None, [ |
1027 | os.path.dirname(get_module_directory(juju)), |
1028 | @@ -66,13 +71,14 @@ |
1029 | "juju-%s" % self.unit_path_name, use_sudo=True) |
1030 | |
1031 | @inlineCallbacks |
1032 | - def start(self, machine_id, zookeeper_hosts, bundle): |
1033 | + def start(self, env_id, machine_id, zookeeper_hosts, bundle): |
1034 | """Start a service unit agent.""" |
1035 | self.unpack_charm(bundle) |
1036 | self.service.set_description( |
1037 | "Juju unit agent for %s" % self.unit_name) |
1038 | self.service.set_environ(_get_environment( |
1039 | - self.unit_name, self.juju_home, machine_id, zookeeper_hosts)) |
1040 | + self.unit_name, self.juju_home, machine_id, |
1041 | + zookeeper_hosts, env_id)) |
1042 | self.service.set_command(" ".join(( |
1043 | "/usr/bin/python", "-m", self.unit_agent_module, |
1044 | "--nodaemon", |
1045 | @@ -189,7 +195,7 @@ |
1046 | (zk, port) = zk.split(':') |
1047 | else: |
1048 | port = 2181 |
1049 | - zks.append((zk,port)) |
1050 | + zks.append((zk, port)) |
1051 | |
1052 | cloud_init.set_zookeeper_hosts(zks) |
1053 | # XXX Very hard to access the provider's notion of network |
1054 | @@ -228,7 +234,7 @@ |
1055 | returnValue((container, directory)) |
1056 | |
1057 | @inlineCallbacks |
1058 | - def start(self, machine_id, zookeeper_hosts, bundle): |
1059 | + def start(self, env_id, machine_id, zookeeper_hosts, bundle): |
1060 | """Start the unit. |
1061 | |
1062 | Creates and starts an lxc container for the unit. |
1063 | |
1064 | === modified file 'juju/providers/common/cloudinit.py' |
1065 | --- juju/providers/common/cloudinit.py 2012-10-20 19:23:19 +0000 |
1066 | +++ juju/providers/common/cloudinit.py 2013-01-17 11:10:30 +0000 |
1067 | @@ -56,7 +56,8 @@ |
1068 | "--session-file /var/run/juju/machine-agent.zksession") |
1069 | return service.get_cloud_init_commands() |
1070 | |
1071 | -def _unit_scripts(machine_id, unit_name, zookeeper_hosts, juju_home): |
1072 | + |
1073 | +def _unit_scripts(machine_id, unit_name, zookeeper_hosts, juju_home, env_id): |
1074 | unit_path_name = unit_name.replace('/', '-') |
1075 | service_name = "juju-%s" % unit_path_name |
1076 | service = UpstartService(service_name) |
1077 | @@ -66,6 +67,7 @@ |
1078 | {"JUJU_MACHINE_ID": str(machine_id), |
1079 | "JUJU_UNIT_NAME": unit_name, |
1080 | "JUJU_HOME": juju_home, |
1081 | + "JUJU_ENV_UUID": env_id, |
1082 | "JUJU_ZOOKEEPER": zookeeper_hosts}) |
1083 | service.set_output_path( |
1084 | "/var/log/juju/unit-%s-output.log" % unit_path_name) |
1085 | @@ -78,6 +80,7 @@ |
1086 | "/var/run/juju/unit-%s-agent.zksession" % unit_path_name])) |
1087 | return service.get_cloud_init_commands() |
1088 | |
1089 | + |
1090 | def _apiserver_scripts(zookeeper_hosts): |
1091 | service = UpstartService("juju-api-agent") |
1092 | service.set_description("Juju api agent") |
1093 | @@ -186,6 +189,7 @@ |
1094 | self._unit_name = None |
1095 | self._juju_home = None |
1096 | self._apt_proxy = None |
1097 | + self._env_id = None |
1098 | |
1099 | def add_ssh_key(self, key): |
1100 | """Add an SSH public key. |
1101 | @@ -239,6 +243,11 @@ |
1102 | self._origin = PROPOSED |
1103 | self._origin_url = None |
1104 | |
1105 | + def set_environment_id(self, id): |
1106 | + """Specify the environment id. |
1107 | + """ |
1108 | + self._env_id = id |
1109 | + |
1110 | def set_machine_id(self, id): |
1111 | """Specify the juju machine ID. |
1112 | |
1113 | @@ -314,7 +323,7 @@ |
1114 | |
1115 | def set_apt_proxy(self, proxy): |
1116 | """Specify an apt proxy to configure |
1117 | - |
1118 | + |
1119 | :param proxy: proxy to set for APT using Acquire:HTTP |
1120 | :type str |
1121 | """ |
1122 | @@ -409,7 +418,8 @@ |
1123 | self._machine_id, |
1124 | self._unit_name, |
1125 | self._join_zookeeper_hosts(), |
1126 | - self._juju_home)) |
1127 | + self._juju_home, |
1128 | + self._env_id)) |
1129 | if self._provision: |
1130 | scripts.extend(_provision_scripts(self._join_zookeeper_hosts())) |
1131 | scripts.extend(_apiserver_scripts(self._join_zookeeper_hosts())) |
1132 | |
1133 | === modified file 'juju/providers/maas/maas.py' |
1134 | --- juju/providers/maas/maas.py 2012-10-04 11:16:58 +0000 |
1135 | +++ juju/providers/maas/maas.py 2013-01-17 11:10:30 +0000 |
1136 | @@ -5,7 +5,9 @@ |
1137 | |
1138 | from base64 import b64encode |
1139 | import json |
1140 | +import logging |
1141 | import re |
1142 | +from twisted.internet.defer import inlineCallbacks, returnValue |
1143 | from twisted.python.failure import Failure |
1144 | from twisted.web.error import Error |
1145 | from urllib import urlencode |
1146 | @@ -17,6 +19,9 @@ |
1147 | from juju.providers.maas.files import encode_multipart_data |
1148 | |
1149 | |
1150 | +log = logging.getLogger("juju.maas") |
1151 | + |
1152 | + |
1153 | CONSUMER_SECRET = "" |
1154 | |
1155 | |
1156 | @@ -80,7 +85,7 @@ |
1157 | # error text that it comes with. |
1158 | if isinstance(error, Error): |
1159 | raise ProviderError(error.response) |
1160 | - |
1161 | + |
1162 | return convert_unknown_error(failure) |
1163 | |
1164 | def get(self, path, params): |
1165 | @@ -172,10 +177,16 @@ |
1166 | params = {"op": "release"} |
1167 | return self.post(resource_uri, params) |
1168 | |
1169 | + @inlineCallbacks |
1170 | def list_tags(self): |
1171 | """Ask MAAS to return a list of all the tags defined. |
1172 | |
1173 | :return: A Deferred whose value is the list of tags. |
1174 | """ |
1175 | params = {"op": "list"} |
1176 | - return self.get("api/1.0/tags/", params) |
1177 | + try: |
1178 | + value = yield self.get("api/1.0/tags/", params) |
1179 | + except ProviderError as e: |
1180 | + log.error("Listing valid maas-tags failed: %s", e) |
1181 | + value = [] |
1182 | + returnValue(value) |
1183 | |
1184 | === modified file 'juju/providers/maas/tests/test_maas.py' |
1185 | --- juju/providers/maas/tests/test_maas.py 2012-10-04 11:16:58 +0000 |
1186 | +++ juju/providers/maas/tests/test_maas.py 2013-01-17 11:10:30 +0000 |
1187 | @@ -5,9 +5,11 @@ |
1188 | |
1189 | import json |
1190 | from textwrap import dedent |
1191 | -from twisted.internet.defer import inlineCallbacks, succeed |
1192 | from urlparse import urlparse |
1193 | |
1194 | +from twisted.internet.defer import inlineCallbacks, fail, succeed |
1195 | +from twisted.web.error import Error |
1196 | + |
1197 | from juju.errors import ProviderError |
1198 | from juju.providers.maas.maas import extract_system_id, MAASClient |
1199 | from juju.providers.maas.tests.testing import ( |
1200 | @@ -15,6 +17,13 @@ |
1201 | FakeMAASHTTPConnectionWithNoAvailableNodes, NODE_JSON, TestCase) |
1202 | |
1203 | |
1204 | +class FakeMAASHTTPConnectionWithNoTags(FakeMAASHTTPConnection): |
1205 | + """Fake client that raises Not Found on tag listing""" |
1206 | + |
1207 | + def list_tags(self): |
1208 | + return fail(Error(404, "Not Found", "Tags? What tags?")) |
1209 | + |
1210 | + |
1211 | class TestFunctions(TestCase): |
1212 | |
1213 | def assertExtractSystemID(self, system_id, resource_uri): |
1214 | @@ -220,6 +229,18 @@ |
1215 | self.assertEqual("No matching node is available.", str(e)) |
1216 | |
1217 | @inlineCallbacks |
1218 | + def test_list_tags_unsupported(self): |
1219 | + """When tags are unspupported just report no valid tags""" |
1220 | + log = self.setup_connection( |
1221 | + MAASClient, FakeMAASHTTPConnectionWithNoTags) |
1222 | + client = MAASClient(CONFIG) |
1223 | + log = self.capture_logging() |
1224 | + result = yield client.list_tags() |
1225 | + self.assertEqual([], result) |
1226 | + self.assertRegexpMatches(log.getvalue(), |
1227 | + "(?m)^Listing valid maas-tags failed: ") |
1228 | + |
1229 | + @inlineCallbacks |
1230 | def test_start_node(self): |
1231 | resource_uri = NODE_JSON[0]["resource_uri"] |
1232 | series = "splendid" |
1233 | |
1234 | === modified file 'juju/providers/openstack/client.py' |
1235 | --- juju/providers/openstack/client.py 2012-10-03 15:16:42 +0000 |
1236 | +++ juju/providers/openstack/client.py 2013-01-17 11:10:30 +0000 |
1237 | @@ -391,7 +391,7 @@ |
1238 | return self.delete(["servers", server_id], code=204) |
1239 | |
1240 | def run_server(self, image_id, flavor_id, name, security_group_names=None, |
1241 | - user_data=None): |
1242 | + user_data=None, scheduler_hints=None): |
1243 | server = { |
1244 | 'name': name, |
1245 | 'flavorRef': flavor_id, |
1246 | @@ -402,6 +402,8 @@ |
1247 | if security_group_names is not None: |
1248 | server["security_groups"] = [{'name': n} |
1249 | for n in security_group_names] |
1250 | + if scheduler_hints is not None: |
1251 | + server["OS-SCH-HNT:scheduler_hints"] = scheduler_hints |
1252 | return self.post(["servers"], {'server': server}, |
1253 | root="server", code=202) |
1254 | |
1255 | @@ -409,12 +411,18 @@ |
1256 | d = self.get( |
1257 | ["servers", server_id, "os-security-groups"], |
1258 | root="security_groups") |
1259 | - # 2012-07-12: Workaround lack of this api in HP cloud |
1260 | - d.addErrback( |
1261 | - lambda f: self.get_server(server_id).addCallback( |
1262 | - operator.itemgetter("security_groups"))) |
1263 | + |
1264 | + # 2012-07-12: kt Workaround lack of this api in HP cloud |
1265 | + def _get_group_fallback(f): |
1266 | + log.debug("Falling back to older/diablo sec groups api") |
1267 | + return self.get_server(server_id).addCallback( |
1268 | + operator.itemgetter("security_groups")) |
1269 | + d.addErrback(_get_group_fallback) |
1270 | return d |
1271 | |
1272 | + def get_security_group_details(self, group_id): |
1273 | + return self.get(["os-security-groups", group_id], "security_group") |
1274 | + |
1275 | def list_security_groups(self): |
1276 | return self.get(["os-security-groups"], "security_groups") |
1277 | |
1278 | |
1279 | === modified file 'juju/providers/openstack/launch.py' |
1280 | --- juju/providers/openstack/launch.py 2012-08-21 16:30:17 +0000 |
1281 | +++ juju/providers/openstack/launch.py 2013-01-17 11:10:30 +0000 |
1282 | @@ -86,19 +86,23 @@ |
1283 | # Find appropriate instance type for the given constraints. Warn |
1284 | # if deprecated is instance-type is being used. |
1285 | flavor_name = self._provider.config.get("default-instance-type") |
1286 | - if flavor_name is None: |
1287 | + if flavor_name is not None: |
1288 | log.warning( |
1289 | "default-instance-type is deprecated, use cli --constraints") |
1290 | flavors = yield self._provider.nova.list_flavor_details() |
1291 | flavor_id = _solve_flavor(self._constraints, flavor_name, flavors) |
1292 | |
1293 | + hints = self._constraints["os-scheduler-hints"] |
1294 | + |
1295 | server = yield self._provider.nova.run_server( |
1296 | name="juju %s instance %s" % |
1297 | (self._provider.environment_name, machine_id,), |
1298 | image_id=image_id, |
1299 | flavor_id=flavor_id, |
1300 | security_group_names=security_groups, |
1301 | - user_data=user_data) |
1302 | + user_data=user_data, |
1303 | + scheduler_hints=hints, |
1304 | + ) |
1305 | |
1306 | if self._master: |
1307 | yield filestorage.put(id_name, StringIO(str(server['id']))) |
1308 | |
1309 | === modified file 'juju/providers/openstack/ports.py' |
1310 | --- juju/providers/openstack/ports.py 2012-09-19 05:34:00 +0000 |
1311 | +++ juju/providers/openstack/ports.py 2013-01-17 11:10:30 +0000 |
1312 | @@ -55,21 +55,34 @@ |
1313 | group_name = self._machine_group_name(machine_id) |
1314 | server_id = machine.instance_id |
1315 | groups = yield self.nova.get_server_security_groups(server_id) |
1316 | + |
1317 | + found = False |
1318 | for group in groups: |
1319 | if group['name'] == group_name: |
1320 | - returnValue(group) |
1321 | + found = group |
1322 | + break |
1323 | + |
1324 | + # 2012/12/19: kt diablo/hpcloud compatibility |
1325 | + if found and not 'rules' in group: |
1326 | + group = yield self.nova.get_security_group_details(group['id']) |
1327 | + found = True |
1328 | + |
1329 | + if found: |
1330 | + returnValue(group) |
1331 | + |
1332 | raise errors.ProviderInteractionError( |
1333 | "Missing security group %r for machine %r" % |
1334 | - (group_name, server_id)) |
1335 | + (group_name, server_id)) |
1336 | |
1337 | @inlineCallbacks |
1338 | def open_port(self, machine, machine_id, port, protocol="tcp"): |
1339 | """Allow access to a port for the given machine only""" |
1340 | group = yield self._get_machine_group(machine, machine_id) |
1341 | - yield self.nova.add_security_group_rule(group['id'], |
1342 | + yield self.nova.add_security_group_rule( |
1343 | + group['id'], |
1344 | ip_protocol=protocol, from_port=port, to_port=port) |
1345 | log.debug("Opened %s/%s on machine %r", |
1346 | - port, protocol, machine.instance_id) |
1347 | + port, protocol, machine.instance_id) |
1348 | |
1349 | @inlineCallbacks |
1350 | def close_port(self, machine, machine_id, port, protocol="tcp"): |
1351 | @@ -78,13 +91,14 @@ |
1352 | for rule in group["rules"]: |
1353 | if (port == rule["from_port"] == rule["to_port"] and |
1354 | rule["ip_protocol"] == protocol): |
1355 | + |
1356 | yield self.nova.delete_security_group_rule(rule["id"]) |
1357 | log.debug("Closed %s/%s on machine %r", |
1358 | port, protocol, machine.instance_id) |
1359 | return |
1360 | raise errors.ProviderInteractionError( |
1361 | "Couldn't close unopened %s/%s on machine %r", |
1362 | - port, protocol, machine.instance_id) |
1363 | + port, protocol, machine.instance_id) |
1364 | |
1365 | @inlineCallbacks |
1366 | def get_opened_ports(self, machine, machine_id): |
1367 | @@ -113,11 +127,12 @@ |
1368 | juju_group = self._juju_group_name() |
1369 | if not juju_group in groups_by_name: |
1370 | log.debug("Creating juju security group %s", juju_group) |
1371 | - sg = yield self.nova.create_security_group(juju_group, |
1372 | + sg = yield self.nova.create_security_group( |
1373 | + juju_group, |
1374 | "juju group for %s" % (self.tag,)) |
1375 | # Add external ssh access |
1376 | - yield self.nova.add_security_group_rule(sg['id'], |
1377 | - ip_protocol="tcp", from_port=22, to_port=22) |
1378 | + yield self.nova.add_security_group_rule( |
1379 | + sg['id'], ip_protocol="tcp", from_port=22, to_port=22) |
1380 | # Add internal group access |
1381 | yield self.nova.add_security_group_rule( |
1382 | parent_group_id=sg['id'], group_id=sg['id'], |
1383 | @@ -131,7 +146,8 @@ |
1384 | yield self.nova.delete_security_group( |
1385 | groups_by_name[machine_group]) |
1386 | log.debug("Creating machine security group %s", machine_group) |
1387 | - yield self.nova.create_security_group(machine_group, |
1388 | + yield self.nova.create_security_group( |
1389 | + machine_group, |
1390 | "juju group for %s machine %s" % (self.tag, machine_id)) |
1391 | |
1392 | returnValue([juju_group, machine_group]) |
1393 | @@ -157,7 +173,8 @@ |
1394 | server_id = machine.instance_id |
1395 | groups = yield self.nova.get_server_security_groups(server_id) |
1396 | juju_group = self._juju_group_name() |
1397 | - groups_by_name = dict((g['name'], g['id']) for g in groups |
1398 | + groups_by_name = dict( |
1399 | + (g['name'], g['id']) for g in groups |
1400 | if g['name'].startswith(juju_group)) |
1401 | if juju_group not in groups_by_name: |
1402 | # Not a juju machine, shouldn't touch |
1403 | |
1404 | === modified file 'juju/providers/openstack/provider.py' |
1405 | --- juju/providers/openstack/provider.py 2012-09-05 11:07:35 +0000 |
1406 | +++ juju/providers/openstack/provider.py 2013-01-17 11:10:30 +0000 |
1407 | @@ -11,6 +11,7 @@ |
1408 | """ |
1409 | |
1410 | import logging |
1411 | +import json |
1412 | |
1413 | from twisted.internet.defer import inlineCallbacks, returnValue |
1414 | |
1415 | @@ -33,6 +34,15 @@ |
1416 | log = logging.getLogger("juju.openstack") |
1417 | |
1418 | |
1419 | +def _convert_scheduler_hints(string): |
1420 | + """Check constraint value suitable for Nova SchedulerHints extension""" |
1421 | + obj = json.loads(string) |
1422 | + if not isinstance(obj, dict): |
1423 | + raise ValueError("Need json object of key/value strings") |
1424 | + # GZ 2012-10-26: Does nova have other restrictions on what it will accept? |
1425 | + return obj |
1426 | + |
1427 | + |
1428 | class MachineProvider(MachineProviderBase): |
1429 | """MachineProvider for use in an OpenStack environment""" |
1430 | |
1431 | @@ -83,6 +93,13 @@ |
1432 | returnValue(cs) |
1433 | cs = yield super(MachineProvider, self).get_constraint_set() |
1434 | |
1435 | + # Pseudo-constraint that does not affect flavor selected but is passed |
1436 | + # through to server creation for influencing the scheduler, for |
1437 | + # instance in the placement of the server. |
1438 | + # Perhaps only register this constraint if the deployment advertises |
1439 | + # the SchedulerHints extension as available? |
1440 | + cs.register("os-scheduler-hints", converter=_convert_scheduler_hints) |
1441 | + |
1442 | # Fetch provider defined instance types (just names) |
1443 | flavors = yield self.nova.list_flavors() |
1444 | flavor_names = [f['name'] for f in flavors] |
1445 | |
1446 | === modified file 'juju/providers/openstack/tests/__init__.py' |
1447 | --- juju/providers/openstack/tests/__init__.py 2012-08-24 19:22:13 +0000 |
1448 | +++ juju/providers/openstack/tests/__init__.py 2013-01-17 11:10:30 +0000 |
1449 | @@ -47,6 +47,8 @@ |
1450 | |
1451 | def setup_constraints(self): |
1452 | self.constraint_set = ConstraintSet(self.provider_type) |
1453 | + self.constraint_set.register("os-scheduler-hints", |
1454 | + converter=json.loads) |
1455 | self.constraint_set.register_generics( |
1456 | [f['name'] for f in self.default_flavors]) |
1457 | |
1458 | @@ -100,7 +102,6 @@ |
1459 | "auth-url": self.api_url, |
1460 | "project-name": "test_project", |
1461 | "control-bucket": self.environment_name, |
1462 | - "default-instance-type": "standard.xsmall", |
1463 | "default-image-id": 42, |
1464 | "use-floating-ip": True, |
1465 | "ssl-hostname-verification": True, |
1466 | @@ -189,7 +190,6 @@ |
1467 | "auth-url": api_url, |
1468 | "project-name": "aproject", |
1469 | "control-bucket": environment_name, |
1470 | - "default-instance-type": "standard.xsmall", |
1471 | "default-image-id": 42, |
1472 | "ssl-hostname-verification": True, |
1473 | } |
1474 | |
1475 | === modified file 'juju/providers/openstack/tests/test_client.py' |
1476 | --- juju/providers/openstack/tests/test_client.py 2012-09-28 15:53:06 +0000 |
1477 | +++ juju/providers/openstack/tests/test_client.py 2013-01-17 11:10:30 +0000 |
1478 | @@ -198,6 +198,36 @@ |
1479 | deferred = osc.authenticate() |
1480 | return self.assertFailure(deferred, errors.SSLVerificationError) |
1481 | |
1482 | + def is_server_with_hints(self, producer): |
1483 | + obj = json.loads(producer.content) |
1484 | + self.assertEqual({"server": { |
1485 | + "imageRef": "an-image", |
1486 | + "flavorRef": "a-flavor", |
1487 | + "name": "Test", |
1488 | + "OS-SCH-HNT:scheduler_hints": {"hint-key": "hint-val"}, |
1489 | + }}, obj) |
1490 | + return True |
1491 | + |
1492 | + @defer.inlineCallbacks |
1493 | + def test_run_server_passes_hints(self): |
1494 | + config, osc = self.make_client_legacy() |
1495 | + self.mock_agent.request("POST", |
1496 | + "https://testing.invalid/compute/servers", mocker.ANY, |
1497 | + mocker.MATCH(self.is_server_with_hints)) |
1498 | + response = FakeResponse(202, http_headers.Headers({ |
1499 | + "Content-Type": ["application/json"], |
1500 | + }), |
1501 | + json.dumps({'server': { |
1502 | + }})) |
1503 | + self.mocker.result(defer.succeed(response)) |
1504 | + self.mocker.replay() |
1505 | + # Fake having already authenticated by setting token and services |
1506 | + osc.token = "tok" |
1507 | + osc.services = {"compute": "https://testing.invalid/compute"} |
1508 | + novac = client._NovaClient(osc) |
1509 | + result = yield novac.run_server("an-image", "a-flavor", "Test", |
1510 | + scheduler_hints={"hint-key": "hint-val"}) |
1511 | + |
1512 | |
1513 | class TestReauthentication(testing.TestCase): |
1514 | |
1515 | |
1516 | === modified file 'juju/providers/openstack/tests/test_launch.py' |
1517 | --- juju/providers/openstack/tests/test_launch.py 2012-09-10 03:20:20 +0000 |
1518 | +++ juju/providers/openstack/tests/test_launch.py 2013-01-17 11:10:30 +0000 |
1519 | @@ -32,13 +32,15 @@ |
1520 | self.nova.list_flavor_details() |
1521 | self.mocker.result(succeed(self.default_flavors)) |
1522 | |
1523 | - def expect_run_server(self, machine_id, cc_match, response, flavor_id=1): |
1524 | + def expect_run_server(self, machine_id, cc_match, response, flavor_id=1, |
1525 | + hints=None): |
1526 | self.nova.run_server( |
1527 | name="juju testing instance " + machine_id, |
1528 | image_id=42, |
1529 | flavor_id=flavor_id, |
1530 | security_group_names=["juju-x", "juju-y"], |
1531 | user_data=MATCH(cc_match), |
1532 | + scheduler_hints=hints, |
1533 | ) |
1534 | self.mocker.result(succeed(response)) |
1535 | |
1536 | @@ -113,6 +115,13 @@ |
1537 | def get_cc_matcher(self, machine_id, provider, is_master=False): |
1538 | return _CloudConfigMatcher(self, machine_id, provider, is_master).match |
1539 | |
1540 | + def _check_log(self, log, pattern): |
1541 | + self.assertRegexpMatches(log.getvalue(), pattern) |
1542 | + |
1543 | + def capture_and_check_log(self, pattern="^$", logname="juju.openstack"): |
1544 | + log = self.capture_logging(logname) |
1545 | + self.addCleanup(self._check_log, log, pattern) |
1546 | + |
1547 | def test_start_machine_with_constraints(self): |
1548 | provider = MockedLaunchProvider(self.mocker) |
1549 | provider.expect_zookeeper_machines(1000, "master.invalid") |
1550 | @@ -126,8 +135,43 @@ |
1551 | }, |
1552 | flavor_id=2) |
1553 | self.mocker.replay() |
1554 | + self.capture_and_check_log() |
1555 | return provider.launch("1", constraints=["cpu=2", "mem=3G"]) |
1556 | |
1557 | + def test_start_machine_with_scheduler_hints(self): |
1558 | + provider = MockedLaunchProvider(self.mocker) |
1559 | + provider.expect_zookeeper_machines(1000, "master.invalid") |
1560 | + provider.expect_launch_setup("1") |
1561 | + provider.expect_run_server( |
1562 | + "1", |
1563 | + self.get_cc_matcher("1", provider), |
1564 | + response={ |
1565 | + 'id': 1001, |
1566 | + 'addresses': {'public': []}, |
1567 | + }, |
1568 | + hints={"hint-key": "hint-value"}) |
1569 | + self.mocker.replay() |
1570 | + self.capture_and_check_log() |
1571 | + return provider.launch("1", constraints=[ |
1572 | + "os-scheduler-hints={\"hint-key\": \"hint-value\"}"]) |
1573 | + |
1574 | + def test_start_machine_with_default_instance_type(self): |
1575 | + config = dict(MockedLaunchProvider.default_config) |
1576 | + config['default-instance-type'] = "m1.sample" |
1577 | + provider = MockedLaunchProvider(self.mocker, config) |
1578 | + provider.expect_zookeeper_machines(1000, "master.invalid") |
1579 | + provider.expect_launch_setup("1") |
1580 | + provider.expect_run_server("1", |
1581 | + self.get_cc_matcher("1", provider), |
1582 | + response={ |
1583 | + 'id': 1001, |
1584 | + 'addresses': {'public': []}, |
1585 | + }) |
1586 | + self.mocker.replay() |
1587 | + self.capture_and_check_log( |
1588 | + "^default-instance-type is deprecated.*constraints") |
1589 | + return provider.launch("1") |
1590 | + |
1591 | def test_start_machine(self): |
1592 | provider = MockedLaunchProvider(self.mocker) |
1593 | provider.expect_zookeeper_machines(1000, "master.invalid") |
1594 | @@ -139,6 +183,7 @@ |
1595 | 'addresses': {'public': []}, |
1596 | }) |
1597 | self.mocker.replay() |
1598 | + self.capture_and_check_log() |
1599 | return provider.launch("1") |
1600 | |
1601 | def test_start_machine_delay(self): |
1602 | @@ -159,6 +204,7 @@ |
1603 | provider.expect_available_floating_ip(1001) |
1604 | self.mocker.result(succeed(None)) |
1605 | self.mocker.replay() |
1606 | + self.capture_and_check_log() |
1607 | self.patch(NovaLaunchMachine, "_DELAY_FOR_ADDRESSES", 0) |
1608 | return provider.launch("1") |
1609 | |
1610 | @@ -175,6 +221,7 @@ |
1611 | provider.provider_actions.save_state({'zookeeper-instances': [1000]}) |
1612 | self.mocker.result(succeed(None)) |
1613 | self.mocker.replay() |
1614 | + self.capture_and_check_log() |
1615 | return provider.launch("0", master=True) |
1616 | |
1617 | def test_start_machine_master(self): |
1618 | |
1619 | === modified file 'juju/providers/openstack/tests/test_ports.py' |
1620 | --- juju/providers/openstack/tests/test_ports.py 2012-09-19 05:34:00 +0000 |
1621 | +++ juju/providers/openstack/tests/test_ports.py 2013-01-17 11:10:30 +0000 |
1622 | @@ -39,10 +39,10 @@ |
1623 | |
1624 | def test_open_port(self): |
1625 | """Opening a port adds the rule to the appropriate security group""" |
1626 | - self.expect_nova_get("servers/1000/os-security-groups", |
1627 | + self.expect_nova_get( |
1628 | + "servers/1000/os-security-groups", |
1629 | response={'security_groups': [ |
1630 | - {'name': "juju-testing-1", 'id': 1}, |
1631 | - ]}) |
1632 | + {'name': "juju-testing-1", 'id': 1, 'rules': []}]}) |
1633 | self.expect_create_rule(1, "tcp", 80) |
1634 | self.mocker.replay() |
1635 | |
1636 | @@ -52,9 +52,34 @@ |
1637 | |
1638 | def _check_log(_): |
1639 | self.assertIn("Opened 80/tcp on machine '1000'", |
1640 | - log.getvalue()) |
1641 | + log.getvalue()) |
1642 | return deferred.addCallback(_check_log) |
1643 | |
1644 | + def test_diablo_hpcloud_ccompatbility(self): |
1645 | + """Verify compatibility workarounds for hpcloud/diablo.""" |
1646 | + self.expect_nova_get( |
1647 | + "servers/1000/os-security-groups", |
1648 | + response={'security_groups': [ |
1649 | + {'name': "juju-testing-1", 'id': 1}]}) |
1650 | + |
1651 | + self.expect_nova_get( |
1652 | + "os-security-groups/1", |
1653 | + response={'security_group': { |
1654 | + 'name': "juju-testing-1", |
1655 | + 'id': 1, |
1656 | + 'rules': [{ |
1657 | + 'id': 1, |
1658 | + 'parent_group_id': 1, |
1659 | + 'ip_protocol': 'tcp', |
1660 | + 'from_port': 80, |
1661 | + 'to_port': 80}]}}) |
1662 | + |
1663 | + self.mocker.replay() |
1664 | + |
1665 | + machine = NovaProviderMachine('1000', "server1000.testing.invalid") |
1666 | + deferred = self.get_provider().get_opened_ports(machine, "1") |
1667 | + return deferred.addCallback(self.assertEqual, set([(80, "tcp")])) |
1668 | + |
1669 | def test_open_port_missing_group(self): |
1670 | """Missing security group raises an error on deleting port""" |
1671 | self.expect_nova_get("servers/1000/os-security-groups", |
1672 | |
1673 | === modified file 'juju/providers/openstack/tests/test_provider.py' |
1674 | --- juju/providers/openstack/tests/test_provider.py 2012-08-28 16:11:04 +0000 |
1675 | +++ juju/providers/openstack/tests/test_provider.py 2013-01-17 11:10:30 +0000 |
1676 | @@ -192,3 +192,32 @@ |
1677 | cs2 = yield provider.get_constraint_set() |
1678 | self.assertIsInstance(cs2, ConstraintSet) |
1679 | self.assertEqual(cs, cs2) |
1680 | + |
1681 | + def create_constraint_set(self): |
1682 | + self.expect_nova_get("flavors", |
1683 | + response={'flavors': self.default_flavors}) |
1684 | + self.mocker.replay() |
1685 | + provider = self.get_provider() |
1686 | + return provider.get_constraint_set() |
1687 | + |
1688 | + @inlineCallbacks |
1689 | + def test_parse_scheduler_hints_one(self): |
1690 | + cs = yield self.create_constraint_set() |
1691 | + c = cs.parse(["os-scheduler-hints={\"hint-key\": \"hint-val\"}"]) |
1692 | + self.assertEqual({"hint-key": "hint-val"}, c["os-scheduler-hints"]) |
1693 | + |
1694 | + @inlineCallbacks |
1695 | + def test_parse_scheduler_hints_bad_value(self): |
1696 | + cs = yield self.create_constraint_set() |
1697 | + err = self.assertRaises(errors.ConstraintError, |
1698 | + cs.parse, ["os-scheduler-hints=notjson"]) |
1699 | + self.assertRegexpMatches(str(err), |
1700 | + "Bad 'os-scheduler-hints' constraint 'notjson': .*") |
1701 | + |
1702 | + @inlineCallbacks |
1703 | + def test_parse_scheduler_hints_bad_array(self): |
1704 | + cs = yield self.create_constraint_set() |
1705 | + err = self.assertRaises(errors.ConstraintError, |
1706 | + cs.parse, ["os-scheduler-hints=[]"]) |
1707 | + self.assertRegexpMatches(str(err), |
1708 | + "Bad 'os-scheduler-hints' constraint '\\[\\]': .*") |
1709 | |
1710 | === modified file 'juju/rapi/transport/tests/test_ws.py' |
1711 | --- juju/rapi/transport/tests/test_ws.py 2012-10-04 15:58:43 +0000 |
1712 | +++ juju/rapi/transport/tests/test_ws.py 2013-01-17 11:10:30 +0000 |
1713 | @@ -74,7 +74,7 @@ |
1714 | self.provider = MachineProvider( |
1715 | "cloudy", {"default-series": "precise"}) |
1716 | self.ws_factory = WebSocketAPIFactory( |
1717 | - get_test_zookeeper_address(), self.provider) |
1718 | + get_test_zookeeper_address(), self.provider, "uuid1") |
1719 | self.ws = self.ws_factory.buildProtocol() |
1720 | self.ws.transport = self.transport = OWTransport(self.ws) |
1721 | self.ws._schedule = lambda: 1 |
1722 | @@ -92,7 +92,7 @@ |
1723 | def test_greeting(self): |
1724 | |
1725 | d = self.transport.watch_dict(dict( |
1726 | - version=0, ready=True, provider_type="dummy", |
1727 | + version=0, ready=True, provider_type="dummy", uuid="uuid1", |
1728 | default_series="precise")) |
1729 | self.ws.connectionMade() |
1730 | return d |
1731 | |
1732 | === modified file 'juju/rapi/transport/ws.py' |
1733 | --- juju/rapi/transport/ws.py 2012-10-04 15:58:43 +0000 |
1734 | +++ juju/rapi/transport/ws.py 2013-01-17 11:10:30 +0000 |
1735 | @@ -23,13 +23,15 @@ |
1736 | |
1737 | The client MUST wait for initial handshake from the server. |
1738 | """ |
1739 | - def __init__(self, zk_hosts, provider): |
1740 | + def __init__(self, zk_hosts, provider, env_uuid): |
1741 | # Are we currently accepting/processing messages. |
1742 | self.active = False |
1743 | # Zk servers to connect to. |
1744 | self.zk_hosts = zk_hosts |
1745 | # Env Provider (needed for status and constraint set retrieval). |
1746 | self.provider = provider |
1747 | + # Environment UUID |
1748 | + self.env_uuid = env_uuid |
1749 | # API Context/Endpoint |
1750 | self.context = None |
1751 | # Client to zk. |
1752 | @@ -47,6 +49,7 @@ |
1753 | """ |
1754 | self.transport.write(json.dumps( |
1755 | {"version": 0, "extensions": [], "ready": True, |
1756 | + "uuid": self.env_uuid, |
1757 | "provider_type": self.provider.provider_type, |
1758 | "default_series": self.provider.config.get("default-series")})) |
1759 | |
1760 | @@ -169,9 +172,10 @@ |
1761 | |
1762 | protocol = APIWebSocket |
1763 | |
1764 | - def __init__(self, zk_hosts, provider): |
1765 | + def __init__(self, zk_hosts, provider, env_uuid): |
1766 | self.zk_hosts = zk_hosts |
1767 | self.provider = provider |
1768 | + self.env_uuid = env_uuid |
1769 | self.numClients = 0 |
1770 | self.stream_manager = DeltaStreamManager( |
1771 | APIContext(ManagedClient(self.zk_hosts), self.provider)) |
1772 | @@ -191,7 +195,7 @@ |
1773 | |
1774 | # New connection. |
1775 | def buildProtocol(self, addr=None): |
1776 | - p = self.protocol(self.zk_hosts, self.provider) |
1777 | + p = self.protocol(self.zk_hosts, self.provider, self.env_uuid) |
1778 | p.factory = self |
1779 | self.stream_manager.add(p) |
1780 | return p |
1781 | |
1782 | === modified file 'juju/state/environment.py' |
1783 | --- juju/state/environment.py 2012-09-10 03:20:20 +0000 |
1784 | +++ juju/state/environment.py 2013-01-17 11:10:30 +0000 |
1785 | @@ -85,7 +85,7 @@ |
1786 | """ |
1787 | |
1788 | def set_provider_type(self, provider_type): |
1789 | - return self._set_value("provider-type", provider_type) |
1790 | + return self._set_value("provider-type", provider_type, once=True) |
1791 | |
1792 | def get_provider_type(self): |
1793 | return self._get_value("provider-type") |
1794 | @@ -102,6 +102,12 @@ |
1795 | """ |
1796 | return self._set_value("debug-log", bool(enabled)) |
1797 | |
1798 | + def set_environment_id(self, uid): |
1799 | + return self._set_value("env-id", uid, once=True) |
1800 | + |
1801 | + def get_environment_id(self): |
1802 | + return self._get_value("env-id") |
1803 | + |
1804 | @inlineCallbacks |
1805 | def _get_value(self, key, default=None): |
1806 | try: |
1807 | @@ -111,13 +117,15 @@ |
1808 | data = serializer.load(content) |
1809 | returnValue(data.get(key, default)) |
1810 | |
1811 | - def _set_value(self, key, value): |
1812 | + def _set_value(self, key, value, once=False): |
1813 | |
1814 | def set_value(old_content, stat): |
1815 | if not old_content: |
1816 | data = {} |
1817 | else: |
1818 | data = serializer.load(old_content) |
1819 | + if once and key in data: |
1820 | + raise ValueError("%s can only be set once" % key) |
1821 | data[key] = value |
1822 | return serializer.dump(data) |
1823 | |
1824 | |
1825 | === modified file 'juju/state/hook.py' |
1826 | --- juju/state/hook.py 2012-09-10 03:20:20 +0000 |
1827 | +++ juju/state/hook.py 2013-01-17 11:10:30 +0000 |
1828 | @@ -1,3 +1,4 @@ |
1829 | +import logging |
1830 | from collections import namedtuple |
1831 | |
1832 | from twisted.internet.defer import inlineCallbacks, returnValue, succeed, fail |
1833 | @@ -11,6 +12,9 @@ |
1834 | from juju.state.utils import YAMLState |
1835 | |
1836 | |
1837 | +log = logging.getLogger("juju.state.hook") |
1838 | + |
1839 | + |
1840 | class RelationChange( |
1841 | namedtuple( |
1842 | "RelationChange", |
1843 | @@ -103,16 +107,23 @@ |
1844 | self._topology = yield self._read_topology() |
1845 | service = yield self.get_local_service() |
1846 | internal_service_id = service.internal_id |
1847 | + service_unit_state = yield self.get_local_unit_state() |
1848 | for info in self._topology.get_relations_for_service( |
1849 | internal_service_id): |
1850 | service_info = info["service"] |
1851 | - relations.append( |
1852 | - ServiceRelationState( |
1853 | - self._client, |
1854 | - internal_service_id, |
1855 | - info["relation_id"], |
1856 | - info["scope"], |
1857 | - **service_info)) |
1858 | + relation = ServiceRelationState( |
1859 | + self._client, |
1860 | + internal_service_id, |
1861 | + info["relation_id"], |
1862 | + info["scope"], |
1863 | + **service_info) |
1864 | + # Verify that it has unit relation state defined in ZK |
1865 | + try: |
1866 | + yield relation.get_unit_state(service_unit_state) |
1867 | + relations.append(relation) |
1868 | + except UnitRelationStateNotFound: |
1869 | + log.debug("Ignoring partially constructed relation: %s", |
1870 | + relation.relation_ident) |
1871 | returnValue(relations) |
1872 | |
1873 | @inlineCallbacks |
1874 | |
1875 | === modified file 'juju/state/initialize.py' |
1876 | --- juju/state/initialize.py 2012-12-12 19:30:20 +0000 |
1877 | +++ juju/state/initialize.py 2013-01-17 11:10:30 +0000 |
1878 | @@ -1,4 +1,5 @@ |
1879 | import logging |
1880 | +import uuid |
1881 | |
1882 | from twisted.internet.defer import inlineCallbacks |
1883 | from txzookeeper.client import ZOO_OPEN_ACL_UNSAFE |
1884 | @@ -70,6 +71,7 @@ |
1885 | # Setup default global settings information. |
1886 | settings = GlobalSettingsStateManager(self.client) |
1887 | yield settings.set_provider_type(self.provider_type) |
1888 | + yield settings.set_environment_id(uuid.uuid4().get_hex()) |
1889 | |
1890 | # Create a node that only the admin can read. |
1891 | yield self.client.create("/login", acls=[ |
1892 | |
1893 | === modified file 'juju/state/tests/test_environment.py' |
1894 | --- juju/state/tests/test_environment.py 2012-09-10 03:20:20 +0000 |
1895 | +++ juju/state/tests/test_environment.py 2013-01-17 11:10:30 +0000 |
1896 | @@ -140,12 +140,25 @@ |
1897 | """Debug logging is off by default.""" |
1898 | self.assertEqual((yield self.manager.get_provider_type()), None) |
1899 | yield self.manager.set_provider_type("ec2") |
1900 | + yield self.assertFailure( |
1901 | + self.manager.set_provider_type("abc"), ValueError) |
1902 | self.assertEqual((yield self.manager.get_provider_type()), "ec2") |
1903 | content, stat = yield self.client.get("/settings") |
1904 | self.assertEqual(serializer.load(content), |
1905 | {"provider-type": "ec2"}) |
1906 | |
1907 | @inlineCallbacks |
1908 | + def test_set_get_environment(self): |
1909 | + self.assertEqual((yield self.manager.get_environment_id()), None) |
1910 | + yield self.manager.set_environment_id('snowflake') |
1911 | + yield self.assertFailure( |
1912 | + self.manager.set_environment_id('snowflake'), |
1913 | + ValueError) |
1914 | + self.assertEqual( |
1915 | + (yield self.manager.get_environment_id()), |
1916 | + "snowflake") |
1917 | + |
1918 | + @inlineCallbacks |
1919 | def test_get_debug_log_enabled_no_settings_default(self): |
1920 | """Debug logging is off by default.""" |
1921 | value = yield self.manager.is_debug_log_enabled() |
1922 | |
1923 | === modified file 'juju/state/tests/test_hook.py' |
1924 | --- juju/state/tests/test_hook.py 2012-09-10 03:20:20 +0000 |
1925 | +++ juju/state/tests/test_hook.py 2013-01-17 11:10:30 +0000 |
1926 | @@ -1,3 +1,5 @@ |
1927 | +import logging |
1928 | + |
1929 | from twisted.internet.defer import inlineCallbacks, returnValue |
1930 | from juju.lib.pick import pick_attr |
1931 | from juju.lib import serializer |
1932 | @@ -98,23 +100,61 @@ |
1933 | self.relation = self.mysql_states["relation"] |
1934 | |
1935 | @inlineCallbacks |
1936 | - def add_another_blog(self, service_name): |
1937 | - blog_ep = RelationEndpoint( |
1938 | - service_name, "client-server", "database", "client") |
1939 | - mysql_ep = RelationEndpoint( |
1940 | - "mysql", "client-server", "db", "server") |
1941 | - yield self.add_relation_service_unit_from_endpoints( |
1942 | - blog_ep, mysql_ep) |
1943 | + def add_another_blog(self, blog_name): |
1944 | + blog_ep = RelationEndpoint(blog_name, "client-server", "app", "client") |
1945 | + # Fully construct states for the relation connecting to this additional blog |
1946 | + other_mysql_states = yield self.add_relation_service_unit_to_another_endpoint( |
1947 | + self.mysql_states, blog_ep) |
1948 | + # Then complete in the opposite direction |
1949 | + blog_states = yield self.add_opposite_service_unit(other_mysql_states) |
1950 | + yield blog_states['service_relations'][-1].add_unit_state( |
1951 | + self.mysql_states['unit']) |
1952 | + returnValue(blog_states) |
1953 | |
1954 | @inlineCallbacks |
1955 | def add_db_admin_tool(self, admin_name): |
1956 | """Add another relation, using a different relation name""" |
1957 | admin_ep = RelationEndpoint( |
1958 | admin_name, "client-server", "admin-app", "client") |
1959 | - mysql_ep = RelationEndpoint( |
1960 | + mysql_admin_ep = RelationEndpoint( |
1961 | "mysql", "client-server", "db-admin", "server") |
1962 | - yield self.add_relation_service_unit_from_endpoints( |
1963 | - admin_ep, mysql_ep) |
1964 | + mysql_admin_states = yield self.reuse_service_unit_in_new_relation( |
1965 | + self.mysql_states, mysql_admin_ep, admin_ep) |
1966 | + admin_states = yield self.add_opposite_service_unit(mysql_admin_states) |
1967 | + returnValue(admin_states) |
1968 | + |
1969 | + @inlineCallbacks |
1970 | + def reuse_service_unit_in_new_relation(self, reused_states, *endpoints): |
1971 | + """Reuse an existing service unit as part of a new relation""" |
1972 | + service_state = reused_states["service"] |
1973 | + unit_state = reused_states["unit"] |
1974 | + |
1975 | + # 1. Setup all service states |
1976 | + service_states = [service_state] |
1977 | + for endpoint in endpoints[1:]: |
1978 | + service_state = yield self.add_service(endpoint.service_name) |
1979 | + service_states.append(service_state) |
1980 | + |
1981 | + # 2. And join together in a relation |
1982 | + relation_state, service_relation_states = \ |
1983 | + yield self.relation_manager.add_relation_state( |
1984 | + *endpoints) |
1985 | + # 3. Add a service unit to only the first endpoint - we need |
1986 | + # to test what happens when service units are added to the |
1987 | + # other service state (if any), so do so separately |
1988 | + relation_unit_state = yield service_relation_states[0].add_unit_state( |
1989 | + unit_state) |
1990 | + |
1991 | + returnValue({ |
1992 | + "endpoints": list(endpoints), |
1993 | + "service": service_states[0], |
1994 | + "services": service_states, |
1995 | + "unit": unit_state, |
1996 | + "relation": relation_state, |
1997 | + "service_relation": service_relation_states[0], |
1998 | + "unit_relation": relation_unit_state, |
1999 | + "service_relations": service_relation_states}) |
2000 | + |
2001 | |
2002 | |
2003 | class HookContextTest(HookContextTestBase, CommonHookContextTestsMixin): |
2004 | @@ -162,6 +202,35 @@ |
2005 | set((yield new_context.get_relation_idents(None))), |
2006 | set(["db:0", "db:1", "db:2", "db-admin:3"])) |
2007 | |
2008 | + @inlineCallbacks |
2009 | + def test_get_relation_idents_partial_updates_to_zk(self): |
2010 | + """Verify relation idents do not reflect partial updates to ZK.""" |
2011 | + log = self.capture_logging(level=logging.DEBUG) |
2012 | + |
2013 | + # 1. Partial update - no corresponding service relation unit |
2014 | + yield self.add_relation_service_unit_to_another_endpoint( |
2015 | + self.mysql_states, |
2016 | + RelationEndpoint( |
2017 | + "wordpress2", "client-server", "app", "client")) |
2018 | + |
2019 | + # 2. Do a complete update of adding another relation and |
2020 | + # corresponding units |
2021 | + yield self.add_another_blog("wordpress3") |
2022 | + context = self.get_context("mysql/0") |
2023 | + |
2024 | + # 3. Observe only the relation ids for wordpress, wordpress3 |
2025 | + self.assertEqual( |
2026 | + set((yield context.get_relation_idents("db"))), |
2027 | + set(["db:0", "db:2"])) |
2028 | + self.assertIn("Ignoring partially constructed relation: db:1", |
2029 | + log.getvalue()) |
2030 | + |
2031 | + # 4. Finally, relation ids for a nonexistent relation are |
2032 | + # still not seen, or cause an error. |
2033 | + self.assertEqual( |
2034 | + set((yield context.get_relation_idents("not-a-relation"))), |
2035 | + set()) |
2036 | + |
2037 | |
2038 | class RelationHookContextTest(HookContextTestBase, |
2039 | CommonHookContextTestsMixin): |
2040 | @@ -178,10 +247,6 @@ |
2041 | self.wordpress_states, "modified", "mysql/0") |
2042 | |
2043 | def get_context(self, states, change_type, unit_name): |
2044 | - change = RelationChange( |
2045 | - states["service_relation"].relation_ident, |
2046 | - change_type, |
2047 | - unit_name) |
2048 | return RelationHookContext( |
2049 | self.client, states["unit_relation"], |
2050 | states["service_relation"].relation_ident, |
2051 | @@ -605,7 +670,7 @@ |
2052 | self.assertEqual( |
2053 | set((yield new_context.get_relation_idents("db"))), |
2054 | set(["db:1"])) |
2055 | - yield self.assertFailure( |
2056 | + yield self.assertFailure( |
2057 | new_context.get_relation_hook_context("db:0"), |
2058 | RelationStateNotFound) |
2059 | db1 = yield new_context.get_relation_hook_context("db:1") |
2060 | |
2061 | === modified file 'juju/state/tests/test_initialize.py' |
2062 | --- juju/state/tests/test_initialize.py 2012-12-12 19:30:20 +0000 |
2063 | +++ juju/state/tests/test_initialize.py 2013-01-17 11:10:30 +0000 |
2064 | @@ -91,6 +91,8 @@ |
2065 | self.assertEqual(instance_id, "i-abcdef") |
2066 | |
2067 | settings_manager = GlobalSettingsStateManager(self.client) |
2068 | + env_id = yield settings_manager.get_environment_id() |
2069 | + self.assertEqual(len(env_id), 32) |
2070 | self.assertEqual((yield settings_manager.get_provider_type()), "dummy") |
2071 | self.assertEqual( |
2072 | self.log.getvalue().strip(), |
2073 | |
2074 | === modified file 'juju/unit/deploy.py' |
2075 | --- juju/unit/deploy.py 2012-04-04 20:21:44 +0000 |
2076 | +++ juju/unit/deploy.py 2013-01-17 11:10:30 +0000 |
2077 | @@ -29,6 +29,7 @@ |
2078 | self.juju_directory = juju_directory |
2079 | self.service_state_manager = ServiceStateManager(self.client) |
2080 | self.charm_state_manager = CharmStateManager(self.client) |
2081 | + self.env_id = None |
2082 | |
2083 | @property |
2084 | def charms_directory(self): |
2085 | @@ -38,10 +39,12 @@ |
2086 | def start(self, provider_type=None): |
2087 | """Starts the unit deployer.""" |
2088 | # Find out what provided the machine, and how to deploy units. |
2089 | + settings = GlobalSettingsStateManager(self.client) |
2090 | if provider_type is None: |
2091 | - settings = GlobalSettingsStateManager(self.client) |
2092 | provider_type = yield settings.get_provider_type() |
2093 | + |
2094 | self.deploy_factory = get_deploy_factory(provider_type) |
2095 | + self.env_id = yield settings.get_environment_id() |
2096 | |
2097 | if not os.path.exists(self.charms_directory): |
2098 | os.makedirs(self.charms_directory) |
2099 | @@ -89,7 +92,7 @@ |
2100 | if not running: |
2101 | log.debug("Starting service unit %s...", service_unit_name) |
2102 | yield deployment.start( |
2103 | - self.machine_id, self.client.servers, bundle) |
2104 | + self.env_id, self.machine_id, self.client.servers, bundle) |
2105 | log.info("Started service unit %s", service_unit_name) |
2106 | |
2107 | @inlineCallbacks |
2108 | |
2109 | === modified file 'juju/unit/tests/test_address.py' |
2110 | --- juju/unit/tests/test_address.py 2012-10-05 17:49:27 +0000 |
2111 | +++ juju/unit/tests/test_address.py 2013-01-17 11:10:30 +0000 |
2112 | @@ -1,23 +1,18 @@ |
2113 | import subprocess |
2114 | -import zookeeper |
2115 | |
2116 | from twisted.internet.defer import inlineCallbacks, succeed, returnValue |
2117 | from twisted.web import client |
2118 | |
2119 | from juju.errors import JujuError |
2120 | from juju.lib.testing import TestCase |
2121 | +from juju.state.tests.common import StateTestBase |
2122 | from juju.unit.address import ( |
2123 | EC2UnitAddress, LocalUnitAddress, OrchestraUnitAddress, DummyUnitAddress, |
2124 | MAASUnitAddress, OpenStackUnitAddress, UnitAddress, get_unit_address) |
2125 | from juju.state.environment import GlobalSettingsStateManager |
2126 | |
2127 | |
2128 | -class AddressTest(TestCase): |
2129 | - |
2130 | - def setUp(self): |
2131 | - zookeeper.set_debug_level(0) |
2132 | - self.client = self.get_zookeeper_client() |
2133 | - return self.client.connect() |
2134 | +class AddressTest(StateTestBase): |
2135 | |
2136 | @inlineCallbacks |
2137 | def get_address_for(self, provider_type): |
2138 | |
2139 | === modified file 'juju/unit/tests/test_deploy.py' |
2140 | --- juju/unit/tests/test_deploy.py 2012-03-28 00:38:16 +0000 |
2141 | +++ juju/unit/tests/test_deploy.py 2013-01-17 11:10:30 +0000 |
2142 | @@ -12,6 +12,7 @@ |
2143 | from juju.machine.tests.test_constraints import ( |
2144 | dummy_constraints, series_constraints) |
2145 | from juju.machine.unit import UnitMachineDeployment |
2146 | +from juju.state.environment import GlobalSettingsStateManager |
2147 | from juju.state.machine import MachineStateManager |
2148 | from juju.state.service import ServiceStateManager |
2149 | from juju.state.tests.common import StateTestBase |
2150 | @@ -48,6 +49,9 @@ |
2151 | add_machine_state(series_constraints) |
2152 | yield self.unit_state.assign_to_machine(self.machine_state) |
2153 | |
2154 | + self.env_settings = GlobalSettingsStateManager(self.client) |
2155 | + yield self.env_settings.set_environment_id("snowflake") |
2156 | + |
2157 | # NOTE machine_id must be a str to use with one of the |
2158 | # deployment classes |
2159 | self.juju_dir = self.makeDir() |
2160 | @@ -62,13 +66,22 @@ |
2161 | UnitMachineDeployment) |
2162 | |
2163 | @inlineCallbacks |
2164 | + def test_start_with_provider_type(self): |
2165 | + # bug test against 1100245 |
2166 | + self.unit_manager = UnitDeployer( |
2167 | + self.client, str(self.machine_state.id), self.juju_dir) |
2168 | + yield self.unit_manager.start("subordinate") |
2169 | + self.assertEqual(self.unit_manager.env_id, "snowflake") |
2170 | + |
2171 | + @inlineCallbacks |
2172 | def test_charm_download(self): |
2173 | """Downloading a charm should store the charm locally.""" |
2174 | yield self.unit_manager.download_charm(self.charm_state) |
2175 | checksum = self.charm.get_sha256() |
2176 | charm_id = local_charm_id(self.charm) |
2177 | charm_key = under.quote("%s:%s" % (charm_id, checksum)) |
2178 | - charm_path = os.path.join(self.unit_manager.charms_directory, charm_key) |
2179 | + charm_path = os.path.join( |
2180 | + self.unit_manager.charms_directory, charm_key) |
2181 | |
2182 | self.assertTrue(os.path.exists(charm_path)) |
2183 | bundle = CharmBundle(charm_path) |
2184 | @@ -82,10 +95,11 @@ |
2185 | def test_start_service_unit(self): |
2186 | """Verify starting a service unit kicks off the desired deployment.""" |
2187 | mock_deployment = self.mocker.patch(self.unit_manager.deploy_factory) |
2188 | - mock_deployment.start("0", get_test_zookeeper_address(), MATCH_BUNDLE) |
2189 | + mock_deployment.start( |
2190 | + "snowflake", "0", get_test_zookeeper_address(), MATCH_BUNDLE) |
2191 | test_deferred = Deferred() |
2192 | |
2193 | - def test_complete(machine_id, servers, bundle): |
2194 | + def test_complete(env_id, machine_id, servers, bundle): |
2195 | test_deferred.callback(True) |
2196 | |
2197 | self.mocker.call(test_complete) |
2198 | @@ -95,16 +109,17 @@ |
2199 | yield test_deferred |
2200 | self.assertLogLines( |
2201 | self.output.getvalue(), |
2202 | - ["Downloading charm local:series/dummy-1 to %s" % \ |
2203 | - os.path.join(self.juju_dir, "charms"), |
2204 | - "Starting service unit myblog/0...", |
2205 | - "Started service unit myblog/0"]) |
2206 | + ["Downloading charm local:series/dummy-1 to %s" % |
2207 | + os.path.join(self.juju_dir, "charms"), |
2208 | + "Starting service unit myblog/0...", |
2209 | + "Started service unit myblog/0"]) |
2210 | |
2211 | @inlineCallbacks |
2212 | def test_kill_service_unit(self): |
2213 | """Verify killing a service unit destroys the deployment.""" |
2214 | mock_deployment = self.mocker.patch(self.unit_manager.deploy_factory) |
2215 | - mock_deployment.start("0", get_test_zookeeper_address(), MATCH_BUNDLE) |
2216 | + mock_deployment.start( |
2217 | + "snowflake", "0", get_test_zookeeper_address(), MATCH_BUNDLE) |
2218 | self.mocker.result(succeed(True)) |
2219 | mock_deployment.destroy() |
2220 | self.mocker.result(succeed(True)) |
2221 | @@ -126,8 +141,8 @@ |
2222 | yield test_deferred |
2223 | self.assertLogLines( |
2224 | self.output.getvalue(), |
2225 | - ["Downloading charm local:series/dummy-1 to %s" % \ |
2226 | - os.path.join(self.juju_dir, "charms"), |
2227 | + ["Downloading charm local:series/dummy-1 to %s" % |
2228 | + os.path.join(self.juju_dir, "charms"), |
2229 | "Starting service unit myblog/0...", |
2230 | "Started service unit myblog/0", |
2231 | "Stopping service unit myblog/0...", |
2232 | |
2233 | === modified file 'juju/unit/tests/test_lifecycle.py' |
2234 | --- juju/unit/tests/test_lifecycle.py 2012-09-10 03:20:20 +0000 |
2235 | +++ juju/unit/tests/test_lifecycle.py 2013-01-17 11:10:30 +0000 |
2236 | @@ -68,6 +68,7 @@ |
2237 | self.executor.start() |
2238 | self.change_environment( |
2239 | PATH=os.environ["PATH"], |
2240 | + JUJU_ENV_UUID="snowflake", |
2241 | JUJU_UNIT_NAME="service-unit/0") |
2242 | |
2243 | @inlineCallbacks |
2244 | @@ -897,14 +898,19 @@ |
2245 | self.write_hook( |
2246 | "start", |
2247 | '#!/bin/sh\n echo "hello world"\n') |
2248 | - yield self.add_opposite_service_unit(self.states) |
2249 | + blog_states = yield self.add_opposite_service_unit(self.states) |
2250 | + yield blog_states['service_relations'][-1].add_unit_state( |
2251 | + self.states['unit']) |
2252 | + |
2253 | for i in range(1, 3): |
2254 | - yield self.add_opposite_service_unit( |
2255 | + blog_states = yield self.add_opposite_service_unit( |
2256 | (yield self.add_relation_service_unit_to_another_endpoint( |
2257 | self.states, |
2258 | RelationEndpoint( |
2259 | "wordpress-%d" % i, |
2260 | "client-server", "db", "client")))) |
2261 | + yield blog_states['service_relations'][-1].add_unit_state( |
2262 | + self.states['unit']) |
2263 | |
2264 | finished = self.wait_on_hook("app-relation-changed", 3) |
2265 | yield self.lifecycle.start() |
2266 | @@ -1006,6 +1012,7 @@ |
2267 | charm specification of hook invocation.""" |
2268 | self.change_environment( |
2269 | PATH=os.environ["PATH"], |
2270 | + JUJU_ENV_UUID="snowflake", |
2271 | JUJU_UNIT_NAME="service-unit/0") |
2272 | change = RelationChange("clients:42", "joined", "s/2") |
2273 | unit_hook_path = self.makeDir() |
2274 | @@ -1014,6 +1021,7 @@ |
2275 | self.assertEqual(environ["JUJU_RELATION"], "clients") |
2276 | self.assertEqual(environ["JUJU_RELATION_ID"], "clients:42") |
2277 | self.assertEqual(environ["JUJU_REMOTE_UNIT"], "s/2") |
2278 | + self.assertEqual(environ["JUJU_ENV_UUID"], "snowflake") |
2279 | self.assertEqual(environ["CHARM_DIR"], |
2280 | os.path.join(unit_hook_path, "charm")) |
2281 | |
2282 | @@ -1328,14 +1336,20 @@ |
2283 | # Setup 5 different wordpress services, wordpress, wordpress-1 |
2284 | # through wordpress-4 with one service unit each. Each of these |
2285 | # will be on the relation app:0 ... app:4 |
2286 | - yield self.add_opposite_service_unit(self.states) |
2287 | + blog_states = yield self.add_opposite_service_unit(self.states) |
2288 | + yield blog_states['service_relations'][-1].add_unit_state( |
2289 | + self.states['unit']) |
2290 | + |
2291 | for i in range(1, 5): |
2292 | - yield self.add_opposite_service_unit( |
2293 | + blog_states = yield self.add_opposite_service_unit( |
2294 | (yield self.add_relation_service_unit_to_another_endpoint( |
2295 | self.states, |
2296 | RelationEndpoint( |
2297 | "wordpress-%d" % i, |
2298 | "client-server", "db", "client")))) |
2299 | + yield blog_states['service_relations'][-1].add_unit_state( |
2300 | + self.states['unit']) |
2301 | + |
2302 | yield self.lifecycle.start() |
2303 | yield self.wait_on_hook( |
2304 | sequence=["app-relation-joined", "app-relation-changed"]) |
looks good thanks.