Merge lp:~gary/charms/precise/juju-gui/update-for-jujucharms into lp:~juju-gui/charms/precise/juju-gui/trunk

Proposed by Gary Poster
Status: Merged
Merged at revision: 48
Proposed branch: lp:~gary/charms/precise/juju-gui/update-for-jujucharms
Merge into: lp:~juju-gui/charms/precise/juju-gui/trunk
Diff against target: 313 lines (+105/-20)
10 files modified
.bzrignore (+1/-0)
config.yaml (+6/-0)
config/config.js.template (+1/-0)
hooks/backend.py (+2/-2)
hooks/install (+23/-5)
hooks/utils.py (+13/-4)
hooks/web-relation-joined (+23/-0)
revision (+1/-1)
tests/deploy.test (+4/-4)
tests/test_utils.py (+31/-4)
To merge this branch: bzr merge lp:~gary/charms/precise/juju-gui/update-for-jujucharms
Reviewer Review Type Date Requested Status
charmers Pending
Review via email: mp+161298@code.launchpad.net

Description of the change

Fix charm for jujucharms.com use

- Merge work from mews to support exec.d directory and relative file paths. Add tests.
- Merge work from benji to support charmworld option needed by upcoming gui changes. Make a small fix.
- Fix deploy tests.

Tests are still fragile, but I got them all to pass with the current branch at one time, and verified manually that the various steps still work.

https://codereview.appspot.com/8999043/

To post a comment you must log in.
Revision history for this message
Gary Poster (gary) wrote :

Please take a look.

Revision history for this message
Gary Poster (gary) wrote :

Reviewers: mp+161298_code.launchpad.net,

Message:
Please take a look.

Description:
Fix charm for jujucharms.com use

- Merge work from mews to support exec.d directory and relative file
paths. Add tests.
- Merge work from benji to support charmworld option needed by upcoming
gui changes. Make a small fix.
- Fix deploy tests.

Tests are still fragile, but I got them all to pass with the current
branch at one time, and verified manually that the various steps still
work.

https://code.launchpad.net/~gary/charms/precise/juju-gui/update-for-jujucharms/+merge/161298

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/8999043/

Affected files:
   M .bzrignore
   A [revision details]
   M config.yaml
   M config/config.js.template
   M hooks/backend.py
   M hooks/install
   M hooks/utils.py
   A hooks/web-relation-joined
   M revision
   M tests/deploy.test
   M tests/test_utils.py

Revision history for this message
Richard Harding (rharding) wrote :

LGTM, thanks for working through it.

https://codereview.appspot.com/8999043/

51. By Gary Poster

respond to review

Revision history for this message
Gary Poster (gary) wrote :
Download full text (4.3 KiB)

*** Submitted:

Fix charm for jujucharms.com use

- Merge work from mews to support exec.d directory and relative file
paths. Add tests.
- Merge work from benji to support charmworld option needed by upcoming
gui changes. Make a small fix.
- Fix deploy tests.

Tests are still fragile, but I got them all to pass with the current
branch at one time, and verified manually that the various steps still
work.

R=rharding, benji
CC=
https://codereview.appspot.com/8999043

https://codereview.appspot.com/8999043/diff/1/hooks/install
File hooks/install (right):

https://codereview.appspot.com/8999043/diff/1/hooks/install#newcode46
hooks/install:46: for module in os.listdir('exec.d'):
On 2013/04/27 20:29:30, benji wrote:
> Usually ".d" files are to be run in lexicographic order, so throwing a
sort()
> around the listdir would be good.

Good idea in the abstract, and I changed it.

FWIW, this code is provided by IS for their use, and I don't like the
pattern and at least mew has agreed with me, so I'm not super excited
about improving it. Your ideas were good, though, so I grudgingly did
them anyway. :-)

https://codereview.appspot.com/8999043/diff/1/hooks/install#newcode49
hooks/install:49: except OSError:
On 2013/04/27 20:29:30, benji wrote:
> It would be safer if we knew which OSErrors in particular we should
ignore. It
> would also be nice to know why we are ignoring them (i.e., a comment).

OK, good point...I did it, because I agree with you, though I had to
guess at their intent. Hopefully I got it right. :-/

https://codereview.appspot.com/8999043/diff/1/hooks/utils.py
File hooks/utils.py (right):

https://codereview.appspot.com/8999043/diff/1/hooks/utils.py#newcode195
hooks/utils.py:195: """Log when a hook starts and stops its execution.
On 2013/04/27 20:29:30, benji wrote:
> Yay! I hate the "an" before non-silent "h" thing.

> I know, I know; I'm weird.

heh

https://codereview.appspot.com/8999043/diff/1/hooks/utils.py#newcode228
hooks/utils.py:228: if source[0] != '/':
On 2013/04/27 20:29:30, benji wrote:
> I don't really prefer it, but just in case you do:

> if not source.startswith('/'):

Yeah, I do, thanks. Changed.

https://codereview.appspot.com/8999043/diff/1/hooks/web-relation-joined
File hooks/web-relation-joined (right):

https://codereview.appspot.com/8999043/diff/1/hooks/web-relation-joined#newcode9
hooks/web-relation-joined:9:
On 2013/04/27 20:29:30, benji wrote:
> Unnecessary newline.

I was doing as the Romans do, but eh, I don't think the Romans will
notice. Deleted.

https://codereview.appspot.com/8999043/diff/1/hooks/web-relation-joined#newcode11
hooks/web-relation-joined:11: log_hook,
On 2013/04/27 20:29:30, benji wrote:
> You can use a one-liner here.

Again, I was following the local patterns in the charm, but eh, I agree.
  Changed.

https://codereview.appspot.com/8999043/diff/1/hooks/web-relation-joined#newcode18
hooks/web-relation-joined:18: hostname = socket.gethostname()
On 2013/04/27 20:29:30, benji wrote:
> I'm pretty sure lines 16-18 are equivalent to

> hostname = socket.getfqdn()

I stared at this for a bit. I think you are probably right. What I had
here is what the haproxy or apache2 charms are...

Read more...

Revision history for this message
Gary Poster (gary) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2013-04-15 17:47:54 +0000
+++ .bzrignore 2013-04-28 01:09:28 +0000
@@ -1,2 +1,3 @@
1.emacs*1.emacs*
2tags2tags
3exec.d/*
34
=== modified file 'config.yaml'
--- config.yaml 2013-04-17 19:31:56 +0000
+++ config.yaml 2013-04-28 01:09:28 +0000
@@ -112,3 +112,9 @@
112 the source: hooks/install and hooks/backend.py in particular.112 the source: hooks/install and hooks/backend.py in particular.
113 type: boolean113 type: boolean
114 default: true114 default: true
115 charmworld-url:
116 description: |
117 The URL of the charm catalog site ("charmworld") from which charm catalog
118 data will be drawn.
119 type: string
120 default: http://staging.jujucharms.com
115121
=== modified file 'config/config.js.template'
--- config/config.js.template 2013-04-12 10:09:32 +0000
+++ config/config.js.template 2013-04-28 01:09:28 +0000
@@ -11,6 +11,7 @@
11 // SubApps.11 // SubApps.
12 consoleEnabled: {{console_enabled}},12 consoleEnabled: {{console_enabled}},
13 charm_store_url: 'https://jujucharms.com/',13 charm_store_url: 'https://jujucharms.com/',
14 charmworldURL: {{charmworld_url}},
14 // socket_url is only honored in older versions of the GUI.15 // socket_url is only honored in older versions of the GUI.
15 socket_url: '{{raw_protocol}}://{{address}}/ws',16 socket_url: '{{raw_protocol}}://{{address}}/ws',
16 // socket_protocol is used instead by newer versions of the GUI to17 // socket_protocol is used instead by newer versions of the GUI to
1718
=== added directory 'exec.d'
=== modified file 'hooks/backend.py'
--- hooks/backend.py 2013-04-24 13:18:22 +0000
+++ hooks/backend.py 2013-04-28 01:09:28 +0000
@@ -107,8 +107,8 @@
107 start_gui(107 start_gui(
108 config['juju-gui-console-enabled'], config['login-help'],108 config['juju-gui-console-enabled'], config['login-help'],
109 config['read-only'], config['staging'], config['ssl-cert-path'],109 config['read-only'], config['staging'], config['ssl-cert-path'],
110 config['serve-tests'], secure=config['secure'],110 config['charmworld-url'], config['serve-tests'],
111 sandbox=config['sandbox'])111 secure=config['secure'], sandbox=config['sandbox'])
112 open_port(80)112 open_port(80)
113 open_port(443)113 open_port(443)
114114
115115
=== modified file 'hooks/install'
--- hooks/install 2013-04-24 10:46:20 +0000
+++ hooks/install 2013-04-28 01:09:28 +0000
@@ -1,8 +1,9 @@
1#!/usr/bin/env python21#!/usr/bin/env python2
2# -*- python -*-2# -*- python -*-
33
4import errno
4import json5import json
5from subprocess import check_call6import os
67
7# If the user's environment has "juju-origin: ppa" set, they will8# If the user's environment has "juju-origin: ppa" set, they will
8# automatically have access to python-charmhelpers and python-shelltoolbox.9# automatically have access to python-charmhelpers and python-shelltoolbox.
@@ -27,18 +28,35 @@
27 'python-apt', 'python-charmhelpers', 'python-launchpadlib',28 'python-apt', 'python-charmhelpers', 'python-launchpadlib',
28 'python-shelltoolbox', 'python-tempita',29 'python-shelltoolbox', 'python-tempita',
29)30)
30check_call(('apt-get', 'install', '-y') + PYTHON_DEPENDENCIES)31bootstrap_utils.run(*(('apt-get', 'install', '-y') + PYTHON_DEPENDENCIES))
3132
3233
34from charmhelpers import log
33from utils import (35from utils import (
34 config_json,36 config_json,
35 log_hook,37 log_hook,
36)38)
37
38from backend import Backend39from backend import Backend
3940
4041
41def main():42def main():
43 # Run pre-install tasks, if available. Please do not rely on the
44 # exec.d interface without conferring with the Juju GUI team: it may
45 # change after upcoming discussion with Canonical IS.
46 if os.path.isdir('exec.d'):
47 dirnames = os.listdir('exec.d')
48 dirnames.sort()
49 for module in dirnames:
50 filename = os.path.join('exec.d', module, 'charm-pre-install')
51 try:
52 bootstrap_utils.run(filename)
53 except OSError, e:
54 # If the exec.d file does not exist or is not runnable,
55 # assume we can recover. Log the problem and proceed.
56 if e.errno in (errno.ENOENT, errno.EACCES):
57 log('{}: {}'.format(e.strerror, filename))
58 else:
59 raise
42 config = get_config()60 config = get_config()
43 backend = Backend(config)61 backend = Backend(config)
44 backend.install()62 backend.install()
4563
=== modified file 'hooks/utils.py'
--- hooks/utils.py 2013-04-25 16:46:07 +0000
+++ hooks/utils.py 2013-04-28 01:09:28 +0000
@@ -45,6 +45,7 @@
45import shutil45import shutil
46from subprocess import CalledProcessError46from subprocess import CalledProcessError
47import tempfile47import tempfile
48from urlparse import urlparse
4849
49from launchpadlib.launchpad import Launchpad50from launchpadlib.launchpad import Launchpad
50from shelltoolbox import (51from shelltoolbox import (
@@ -191,7 +192,7 @@
191192
192@contextmanager193@contextmanager
193def log_hook():194def log_hook():
194 """Log when an hook starts and stops its execution.195 """Log when a hook starts and stops its execution.
195196
196 Also log to stdout possible CalledProcessError exceptions raised executing197 Also log to stdout possible CalledProcessError exceptions raised executing
197 the hook.198 the hook.
@@ -217,10 +218,17 @@
217 - ('stable', '0.1.0'): stable release v0.1.0;218 - ('stable', '0.1.0'): stable release v0.1.0;
218 - ('trunk', None): latest trunk release;219 - ('trunk', None): latest trunk release;
219 - ('trunk', '0.1.0+build.1'): trunk release v0.1.0 bzr revision 1;220 - ('trunk', '0.1.0+build.1'): trunk release v0.1.0 bzr revision 1;
220 - ('branch', 'lp:juju-gui'): release is made from a branch.221 - ('branch', 'lp:juju-gui'): release is made from a branch;
222 - ('url', 'http://example.com/gui'): release from a downloaded file.
221 """223 """
222 if source.startswith('url:'):224 if source.startswith('url:'):
223 return 'url', source[4:]225 source = source[4:]
226 # Support file paths, including relative paths.
227 if urlparse(source).scheme == '':
228 if not source.startswith('/'):
229 source = os.path.join(os.path.abspath(CURRENT_DIR), source)
230 source = "file://%s" % source
231 return 'url', source
224 if source in ('stable', 'trunk'):232 if source in ('stable', 'trunk'):
225 return source, None233 return source, None
226 if source.startswith('lp:') or source.startswith('http://'):234 if source.startswith('lp:') or source.startswith('http://'):
@@ -310,7 +318,7 @@
310318
311def start_gui(319def start_gui(
312 console_enabled, login_help, readonly, in_staging, ssl_cert_path,320 console_enabled, login_help, readonly, in_staging, ssl_cert_path,
313 serve_tests, haproxy_path='/etc/haproxy/haproxy.cfg',321 charmworld_url, serve_tests, haproxy_path='/etc/haproxy/haproxy.cfg',
314 config_js_path=None, secure=True, sandbox=False):322 config_js_path=None, secure=True, sandbox=False):
315 """Set up and start the Juju GUI server."""323 """Set up and start the Juju GUI server."""
316 with su('root'):324 with su('root'):
@@ -350,6 +358,7 @@
350 'user': json.dumps(user),358 'user': json.dumps(user),
351 'protocol': json.dumps(protocol),359 'protocol': json.dumps(protocol),
352 'sandbox': json.dumps(sandbox),360 'sandbox': json.dumps(sandbox),
361 'charmworld_url': json.dumps(charmworld_url),
353 }362 }
354 if config_js_path is None:363 if config_js_path is None:
355 config_js_path = os.path.join(364 config_js_path = os.path.join(
356365
=== added file 'hooks/web-relation-joined'
--- hooks/web-relation-joined 1970-01-01 00:00:00 +0000
+++ hooks/web-relation-joined 2013-04-28 01:09:28 +0000
@@ -0,0 +1,23 @@
1#!/usr/bin/env python2
2#-*- python -*-
3
4import socket
5from charmhelpers import (
6 get_config,
7 relation_set,
8)
9from utils import log_hook
10
11
12def main():
13 hostname = socket.getfqdn()
14 config = get_config()
15 if config['secure']:
16 port = 443
17 else:
18 port = 80
19 relation_set(port=port, hostname=hostname)
20
21if __name__ == '__main__':
22 with log_hook():
23 main()
024
=== modified file 'revision'
--- revision 2013-04-23 07:32:46 +0000
+++ revision 2013-04-28 01:09:28 +0000
@@ -1,1 +1,1 @@
134140
22
=== modified file 'tests/deploy.test'
--- tests/deploy.test 2013-03-13 21:24:31 +0000
+++ tests/deploy.test 2013-04-28 01:09:28 +0000
@@ -166,7 +166,7 @@
166 # XXX 2012-11-29 frankban bug=872264: see *stop_services* above.166 # XXX 2012-11-29 frankban bug=872264: see *stop_services* above.
167 self.addCleanup(167 self.addCleanup(
168 self.stop_services,168 self.stop_services,
169 hostname, ['haproxy', 'nginx', 'juju-api-agent'])169 hostname, ['haproxy', 'apache2', 'juju-api-agent'])
170 self.navigate_to(hostname)170 self.navigate_to(hostname)
171 self.handle_browser_warning()171 self.handle_browser_warning()
172 self.assertEnvironmentIsConnected()172 self.assertEnvironmentIsConnected()
@@ -177,7 +177,7 @@
177 # XXX 2012-11-29 frankban bug=872264: see *stop_services* above.177 # XXX 2012-11-29 frankban bug=872264: see *stop_services* above.
178 self.addCleanup(178 self.addCleanup(
179 self.stop_services,179 self.stop_services,
180 hostname, ['haproxy', 'nginx', 'juju-api-improv'])180 hostname, ['haproxy', 'apache2', 'juju-api-improv'])
181 self.navigate_to(hostname)181 self.navigate_to(hostname)
182 self.handle_browser_warning()182 self.handle_browser_warning()
183 self.assertEnvironmentIsConnected()183 self.assertEnvironmentIsConnected()
@@ -190,7 +190,7 @@
190 # XXX 2012-11-29 frankban bug=872264: see *stop_services* above.190 # XXX 2012-11-29 frankban bug=872264: see *stop_services* above.
191 self.addCleanup(191 self.addCleanup(
192 self.stop_services,192 self.stop_services,
193 hostname, ['haproxy', 'nginx', 'juju-api-agent'])193 hostname, ['haproxy', 'apache2', 'juju-api-agent'])
194 self.navigate_to(hostname)194 self.navigate_to(hostname)
195 self.handle_browser_warning()195 self.handle_browser_warning()
196 self.assertEnvironmentIsConnected()196 self.assertEnvironmentIsConnected()
@@ -222,7 +222,7 @@
222 # XXX 2012-11-29 frankban bug=872264: see *stop_services* above.222 # XXX 2012-11-29 frankban bug=872264: see *stop_services* above.
223 self.addCleanup(223 self.addCleanup(
224 self.stop_services,224 self.stop_services,
225 hostname, ['haproxy', 'nginx', 'juju-api-agent'])225 hostname, ['haproxy', 'apache2', 'juju-api-agent'])
226 self.navigate_to(hostname)226 self.navigate_to(hostname)
227 self.handle_browser_warning()227 self.handle_browser_warning()
228 self.assertEnvironmentIsConnected()228 self.assertEnvironmentIsConnected()
229229
=== modified file 'tests/test_utils.py'
--- tests/test_utils.py 2013-04-23 16:55:56 +0000
+++ tests/test_utils.py 2013-04-28 01:09:28 +0000
@@ -366,6 +366,15 @@
366366
367class ParseSourceTest(unittest.TestCase):367class ParseSourceTest(unittest.TestCase):
368368
369 def setUp(self):
370 # Monkey patch utils.CURRENT_DIR.
371 self.original_current_dir = utils.CURRENT_DIR
372 utils.CURRENT_DIR = '/current/dir'
373
374 def tearDown(self):
375 # Restore the original utils.CURRENT_DIR.
376 utils.CURRENT_DIR = self.original_current_dir
377
369 def test_latest_stable_release(self):378 def test_latest_stable_release(self):
370 # Ensure the latest stable release is correctly parsed.379 # Ensure the latest stable release is correctly parsed.
371 expected = ('stable', None)380 expected = ('stable', None)
@@ -392,6 +401,19 @@
392 for source in sources:401 for source in sources:
393 self.assertTupleEqual(('branch', source), parse_source(source))402 self.assertTupleEqual(('branch', source), parse_source(source))
394403
404 def test_url(self):
405 expected = ('url', 'http://example.com/gui')
406 self.assertTupleEqual(
407 expected, parse_source('url:http://example.com/gui'))
408
409 def test_file_url(self):
410 expected = ('url', 'file:///foo/bar')
411 self.assertTupleEqual(expected, parse_source('url:/foo/bar'))
412
413 def test_relative_file_url(self):
414 expected = ('url', 'file:///current/dir/foo/bar')
415 self.assertTupleEqual(expected, parse_source('url:foo/bar'))
416
395417
396class RenderToFileTest(unittest.TestCase):418class RenderToFileTest(unittest.TestCase):
397419
@@ -539,9 +561,11 @@
539561
540 def test_start_gui(self):562 def test_start_gui(self):
541 ssl_cert_path = '/tmp/certificates/'563 ssl_cert_path = '/tmp/certificates/'
564 charmworld_url = 'http://charmworld.example'
542 start_gui(565 start_gui(
543 False, 'This is login help.', True, True, ssl_cert_path, True,566 False, 'This is login help.', True, True, ssl_cert_path,
544 haproxy_path='haproxy', config_js_path='config')567 charmworld_url, True, haproxy_path='haproxy',
568 config_js_path='config')
545 haproxy_conf = self.files['haproxy']569 haproxy_conf = self.files['haproxy']
546 self.assertIn('ca-base {0}'.format(ssl_cert_path), haproxy_conf)570 self.assertIn('ca-base {0}'.format(ssl_cert_path), haproxy_conf)
547 self.assertIn('crt-base {0}'.format(ssl_cert_path), haproxy_conf)571 self.assertIn('crt-base {0}'.format(ssl_cert_path), haproxy_conf)
@@ -558,6 +582,7 @@
558 self.assertIn('readOnly: true', js_conf)582 self.assertIn('readOnly: true', js_conf)
559 self.assertIn("socket_url: 'wss://", js_conf)583 self.assertIn("socket_url: 'wss://", js_conf)
560 self.assertIn('socket_protocol: "wss"', js_conf)584 self.assertIn('socket_protocol: "wss"', js_conf)
585 self.assertIn('charmworldURL: "http://charmworld.example"', js_conf)
561 apache_conf = self.files['juju-gui']586 apache_conf = self.files['juju-gui']
562 self.assertIn('juju-gui/build-', apache_conf)587 self.assertIn('juju-gui/build-', apache_conf)
563 self.assertIn('VirtualHost *:{0}'.format(WEB_PORT), apache_conf)588 self.assertIn('VirtualHost *:{0}'.format(WEB_PORT), apache_conf)
@@ -565,9 +590,11 @@
565590
566 def test_start_gui_insecure(self):591 def test_start_gui_insecure(self):
567 ssl_cert_path = '/tmp/certificates/'592 ssl_cert_path = '/tmp/certificates/'
593 charmworld_url = 'http://charmworld.example'
568 start_gui(594 start_gui(
569 False, 'This is login help.', True, True, ssl_cert_path, True,595 False, 'This is login help.', True, True, ssl_cert_path,
570 haproxy_path='haproxy', config_js_path='config', secure=False)596 charmworld_url, True, haproxy_path='haproxy',
597 config_js_path='config', secure=False)
571 js_conf = self.files['config']598 js_conf = self.files['config']
572 self.assertIn("socket_url: 'ws://", js_conf)599 self.assertIn("socket_url: 'ws://", js_conf)
573 self.assertIn('socket_protocol: "ws"', js_conf)600 self.assertIn('socket_protocol: "ws"', js_conf)

Subscribers

People subscribed via source and target branches

to all changes: