Merge lp:~frankban/charms/precise/juju-gui/bug-1092515-certificates into lp:~juju-gui/charms/precise/juju-gui/trunk

Proposed by Francesco Banconi
Status: Merged
Merged at revision: 19
Proposed branch: lp:~frankban/charms/precise/juju-gui/bug-1092515-certificates
Merge into: lp:~juju-gui/charms/precise/juju-gui/trunk
Diff against target: 283 lines (+94/-24)
7 files modified
config.yaml (+12/-0)
config/nginx.conf.template (+2/-2)
hooks/config-changed (+13/-4)
hooks/install (+5/-1)
hooks/start (+3/-1)
hooks/utils.py (+30/-14)
tests/test_utils.py (+29/-2)
To merge this branch: bzr merge lp:~frankban/charms/precise/juju-gui/bug-1092515-certificates
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+141105@code.launchpad.net

Description of the change

Allow using an own SSL cert and private key.

Added two new config options, one for the certificate, one
for the private key. If they are both provided, they are used
by nginx, otherwise, a new certificate is automatically
generated.

Fixed a pre-existent bug: even if you can specify the
directory where to store the certificates, this path
was not used by nginx, because an hardcoded one was
present in the configuration file.

Improved how ssl options are handled in config-changes.
If the SSL path is changed using 'juju set', now that
change is reflected in the nginx config file, and the
service correctly restarted.

Added tests for the process of saving or generating SSL
certificates.

Some code clean up.

Please note that all the SSL stuff is still
disabled/commented.

https://codereview.appspot.com/6976046/

To post a comment you must log in.
Revision history for this message
Francesco Banconi (frankban) wrote :

Reviewers: mp+141105_code.launchpad.net,

Message:
Please take a look.

Description:
Allow using an own SSL cert and private key.

Added two new config options, one for the certificate, one
for the private key. If they are both provided, they are used
by nginx, otherwise, a new certificate is automatically
generated.

Fixed a pre-existent bug: even if you can specify the
directory where to store the certificates, this path
was not used by nginx, because an hardcoded one was
present in the configuration file.

Improved how ssl options are handled in config-changes.
If the SSL path is changed using 'juju set', now that
change is reflected in the nginx config file, and the
service correctly restarted.

Added tests for the process of saving or generating SSL
certificates.

Some code clean up.

Please note that all the SSL stuff is still
disabled/commented.

https://code.launchpad.net/~frankban/charms/precise/juju-gui/bug-1092515-certificates/+merge/141105

(do not edit description out of merge proposal)

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

Affected files:
   [revision details]
   config.yaml
   config/nginx.conf.template
   hooks/config-changed
   hooks/install
   hooks/start
   hooks/utils.py
   tests/test_utils.py

Revision history for this message
Francesco Banconi (frankban) wrote :
Revision history for this message
Nicola Larosa (teknico) wrote :
Revision history for this message
Madison Scott-Clary (makyo) wrote :

Looks good to me, land as is.

Thanks for the changes.

https://codereview.appspot.com/6976046/

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

I'm distracted that I can't run the tests successfully--part of the
problem was that a new d3 release broke our build, and I asked bac to
fix that with a better package spec--but this looks good and should
land. Thank you!

Gary

https://codereview.appspot.com/6976046/

Revision history for this message
Francesco Banconi (frankban) wrote :

*** Submitted:

Allow using an own SSL cert and private key.

Added two new config options, one for the certificate, one
for the private key. If they are both provided, they are used
by nginx, otherwise, a new certificate is automatically
generated.

Fixed a pre-existent bug: even if you can specify the
directory where to store the certificates, this path
was not used by nginx, because an hardcoded one was
present in the configuration file.

Improved how ssl options are handled in config-changes.
If the SSL path is changed using 'juju set', now that
change is reflected in the nginx config file, and the
service correctly restarted.

Added tests for the process of saving or generating SSL
certificates.

Some code clean up.

Please note that all the SSL stuff is still
disabled/commented.

R=teknico, matthew.scott, gary.poster
CC=
https://codereview.appspot.com/6976046

https://codereview.appspot.com/6976046/

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

fwiw, jujucharms.com supports ssl

On Sat, Dec 22, 2012 at 4:55 AM, Francesco Banconi <
<email address hidden>> wrote:

> *** Submitted:
>
> Allow using an own SSL cert and private key.
>
> Added two new config options, one for the certificate, one
> for the private key. If they are both provided, they are used
> by nginx, otherwise, a new certificate is automatically
> generated.
>
> Fixed a pre-existent bug: even if you can specify the
> directory where to store the certificates, this path
> was not used by nginx, because an hardcoded one was
> present in the configuration file.
>
> Improved how ssl options are handled in config-changes.
> If the SSL path is changed using 'juju set', now that
> change is reflected in the nginx config file, and the
> service correctly restarted.
>
> Added tests for the process of saving or generating SSL
> certificates.
>
> Some code clean up.
>
> Please note that all the SSL stuff is still
> disabled/commented.
>
> R=teknico, matthew.scott, gary.poster
> CC=
> https://codereview.appspot.com/6976046
>
>
> https://codereview.appspot.com/6976046/
>
> --
>
> https://code.launchpad.net/~frankban/charms/precise/juju-gui/bug-1092515-certificates/+merge/141105
> Your team Juju GUI Hackers is requested to review the proposed merge of
> lp:~frankban/charms/precise/juju-gui/bug-1092515-certificates into
> lp:~juju-gui/charms/precise/juju-gui/trunk.
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'config.yaml'
2--- config.yaml 2012-12-20 14:56:29 +0000
3+++ config.yaml 2012-12-21 17:47:23 +0000
4@@ -51,3 +51,15 @@
5 The path to the directory where the SSL certificates are stored.
6 type: string
7 default: /etc/ssl/private/juju-gui
8+ ssl-cert-contents:
9+ description: |
10+ The contents of the certificate file to be used in SSL connections to
11+ the GUI. Both ssl-cert-contents and ssl-key-contents must be provided.
12+ If not, cetificates will be automatically generated.
13+ type: string
14+ ssl-key-contents:
15+ description: |
16+ The contents of the private key file to be used in SSL connections to
17+ the GUI. Both ssl-cert-contents and ssl-key-contents must be provided.
18+ If not, cetificates will be automatically generated.
19+ type: string
20
21=== modified file 'config/nginx.conf.template'
22--- config/nginx.conf.template 2012-12-20 18:02:44 +0000
23+++ config/nginx.conf.template 2012-12-21 17:47:23 +0000
24@@ -13,8 +13,8 @@
25 root %(server_root)s;
26 index index.html;
27 # Uncomment to switch back to TLS connections.
28- # ssl_certificate /etc/ssl/private/juju-gui/server.pem;
29- # ssl_certificate_key /etc/ssl/private/juju-gui/server.key;
30+ # ssl_certificate %(ssl_cert_path)s/server.pem;
31+ # ssl_certificate_key %(ssl_cert_path)s/server.key;
32
33 # Serve static assets.
34 location ^~ /juju-ui/ {
35
36=== modified file 'hooks/config-changed'
37--- hooks/config-changed 2012-12-20 14:56:29 +0000
38+++ hooks/config-changed 2012-12-21 17:47:23 +0000
39@@ -27,8 +27,8 @@
40 fetch_gui,
41 GUI,
42 IMPROV,
43+ save_or_create_certificates,
44 setup_gui,
45- setup_nginx,
46 start_agent,
47 start_gui,
48 start_improv,
49@@ -55,11 +55,18 @@
50 release_tarball = fetch_gui(
51 config['juju-gui-source'], config['command-log-file'])
52 setup_gui(release_tarball)
53- setup_nginx(config['ssl-cert-path'])
54 if 'juju-api-branch' in added_or_changed:
55 juju_api_branch_changed = True
56 fetch_api(config['juju-api-branch'])
57
58+ # Handle changes to SSL certificates.
59+ ssl_properties = set(
60+ ['ssl-cert-path', 'ssl-cert-contents', 'ssl-key-contents'])
61+ if added_or_changed & ssl_properties:
62+ save_or_create_certificates(
63+ config['ssl-cert-path'], config.get('ssl-cert-contents'),
64+ config.get('ssl-key-contents'))
65+
66 # Handle changes to the improv server configuration.
67 if staging:
68 staging_properties = set(
69@@ -99,11 +106,13 @@
70 gui_properties = set(
71 ['juju-gui-console-enabled', 'juju-api-port', 'staging'])
72 gui_changed = added_or_changed & gui_properties
73- if gui_changed or juju_gui_source_changed:
74+ ssl_cert_path_changed = 'ssl-cert-path' in added_or_changed
75+ if gui_changed or juju_gui_source_changed or ssl_cert_path_changed:
76 with su('root'):
77 service_control(GUI, STOP)
78 console_enabled = config.get('juju-gui-console-enabled')
79- start_gui(juju_api_port, console_enabled, staging)
80+ ssl_cert_path = config['ssl-cert-path']
81+ start_gui(juju_api_port, console_enabled, staging, ssl_cert_path)
82
83
84 def main():
85
86=== modified file 'hooks/install'
87--- hooks/install 2012-12-20 14:56:29 +0000
88+++ hooks/install 2012-12-21 17:47:23 +0000
89@@ -28,6 +28,7 @@
90 config_json,
91 fetch_api,
92 fetch_gui,
93+ save_or_create_certificates,
94 setup_gui,
95 setup_nginx,
96 )
97@@ -51,7 +52,10 @@
98 release_tarball = fetch_gui(
99 config['juju-gui-source'], config['command-log-file'])
100 setup_gui(release_tarball)
101- setup_nginx(config['ssl-cert-path'])
102+ setup_nginx()
103+ save_or_create_certificates(
104+ config['ssl-cert-path'], config.get('ssl-cert-contents'),
105+ config.get('ssl-key-contents'))
106 fetch_api(config['juju-api-branch'])
107 config_json.set(config)
108
109
110=== modified file 'hooks/start'
111--- hooks/start 2012-12-20 18:02:44 +0000
112+++ hooks/start 2012-12-21 17:47:23 +0000
113@@ -31,7 +31,9 @@
114 config = get_config()
115 juju_api_port = config['juju-api-port']
116 staging = config.get('staging')
117- start_gui(juju_api_port, config['juju-gui-console-enabled'], staging)
118+ start_gui(
119+ juju_api_port, config['juju-gui-console-enabled'], staging,
120+ config['ssl-cert-path'])
121 if staging:
122 start_improv(juju_api_port, config['staging-environment'])
123 else:
124
125=== modified file 'hooks/utils.py'
126--- hooks/utils.py 2012-12-20 14:56:29 +0000
127+++ hooks/utils.py 2012-12-21 17:47:23 +0000
128@@ -16,6 +16,7 @@
129 'JUJU_GUI_DIR',
130 'parse_source',
131 'render_to_file',
132+ 'save_or_create_certificates',
133 'setup_gui',
134 'setup_nginx',
135 'start_agent',
136@@ -27,7 +28,6 @@
137 import json
138 import os
139 import logging
140-import shutil
141 import tempfile
142
143 from launchpadlib.launchpad import Launchpad
144@@ -55,6 +55,7 @@
145 CURRENT_DIR = os.getcwd()
146 JUJU_DIR = os.path.join(CURRENT_DIR, 'juju')
147 JUJU_GUI_DIR = os.path.join(CURRENT_DIR, 'juju-gui')
148+JUJU_GUI_SITE = '/etc/nginx/sites-available/juju-gui'
149
150 # Store the configuration from on invocation to the next.
151 config_json = Serializer('/tmp/config.json')
152@@ -210,9 +211,9 @@
153 service_control(AGENT, START)
154
155
156-def start_gui(juju_api_port, console_enabled, staging,
157+def start_gui(juju_api_port, console_enabled, staging, ssl_cert_path,
158 config_path='/etc/init/juju-gui.conf',
159- nginx_path='/etc/nginx/sites-available/juju-gui',
160+ nginx_path=JUJU_GUI_SITE,
161 config_js_path=None):
162 """Set up and start the Juju GUI server."""
163 with su('root'):
164@@ -233,7 +234,8 @@
165 render_to_file('config.js.template', context, config_js_path)
166 log('Generating the nginx site configuration file.')
167 context = {
168- 'server_root': build_dir
169+ 'server_root': build_dir,
170+ 'ssl_cert_path': ssl_cert_path.rstrip('/'),
171 }
172 render_to_file('nginx.conf.template', context, nginx_path)
173 log('Starting Juju GUI.')
174@@ -307,25 +309,39 @@
175 cmd_log(run('ln', '-sf', first_path_in_dir(release_dir), JUJU_GUI_DIR))
176
177
178-def setup_nginx(ssl_cert_path):
179+def setup_nginx():
180 """Set up nginx."""
181 log('Setting up nginx.')
182 nginx_default_site = '/etc/nginx/sites-enabled/default'
183- juju_gui_site = '/etc/nginx/sites-available/juju-gui'
184 if os.path.exists(nginx_default_site):
185 os.remove(nginx_default_site)
186- if not os.path.exists(juju_gui_site):
187- cmd_log(run('touch', juju_gui_site))
188- cmd_log(run('chown', 'ubuntu:', juju_gui_site))
189+ if not os.path.exists(JUJU_GUI_SITE):
190+ cmd_log(run('touch', JUJU_GUI_SITE))
191+ cmd_log(run('chown', 'ubuntu:', JUJU_GUI_SITE))
192 cmd_log(
193- run('ln', '-s', juju_gui_site,
194+ run('ln', '-s', JUJU_GUI_SITE,
195 '/etc/nginx/sites-enabled/juju-gui'))
196- # Generate the nginx SSL certificates, if needed.
197+
198+
199+def save_or_create_certificates(
200+ ssl_cert_path, ssl_cert_contents, ssl_key_contents):
201+ """Generate the SSL certificates.
202+
203+ If both *ssl_cert_contents* and *ssl_key_contents* are provided, use them
204+ as certificates; otherwise, generate them.
205+ """
206 pem_path = os.path.join(ssl_cert_path, 'server.pem')
207 key_path = os.path.join(ssl_cert_path, 'server.key')
208- if not (os.path.exists(pem_path) and os.path.exists(key_path)):
209- if not os.path.exists(ssl_cert_path):
210- os.makedirs(ssl_cert_path)
211+ if not os.path.exists(ssl_cert_path):
212+ os.makedirs(ssl_cert_path)
213+ if ssl_cert_contents and ssl_key_contents:
214+ # Save the provided certificates.
215+ with open(pem_path, 'w') as cert_file:
216+ cert_file.write(ssl_cert_contents)
217+ with open(key_path, 'w') as key_file:
218+ key_file.write(ssl_key_contents)
219+ else:
220+ # Generate certificates.
221 # See http://superuser.com/questions/226192/openssl-without-prompt
222 cmd_log(run(
223 'openssl', 'req', '-new', '-newkey', 'rsa:4096',
224
225=== modified file 'tests/test_utils.py'
226--- tests/test_utils.py 2012-12-20 13:27:30 +0000
227+++ tests/test_utils.py 2012-12-21 17:47:23 +0000
228@@ -16,6 +16,7 @@
229 get_zookeeper_address,
230 parse_source,
231 render_to_file,
232+ save_or_create_certificates,
233 start_agent,
234 start_gui,
235 start_improv,
236@@ -288,6 +289,29 @@
237 self.assertEqual(expected, self.destination_file.read())
238
239
240+class SaveOrCreateCertificatesTest(unittest.TestCase):
241+
242+ def setUp(self):
243+ base_dir = tempfile.mkdtemp()
244+ self.addCleanup(shutil.rmtree, base_dir)
245+ self.cert_path = os.path.join(base_dir, 'certificates')
246+ self.cert_file = os.path.join(self.cert_path, 'server.pem')
247+ self.key_file = os.path.join(self.cert_path, 'server.key')
248+
249+ def test_generation(self):
250+ """Ensure certificates are correctly generated."""
251+ save_or_create_certificates(
252+ self.cert_path, 'some ignored contents', None)
253+ self.assertIn('CERTIFICATE', open(self.cert_file).read())
254+ self.assertIn('PRIVATE KEY', open(self.key_file).read())
255+
256+ def test_provided_certificates(self):
257+ # Ensure files are correctly saved if their contents are provided.
258+ save_or_create_certificates(self.cert_path, 'mycert', 'mykey')
259+ self.assertIn('mycert', open(self.cert_file).read())
260+ self.assertIn('mykey', open(self.key_file).read())
261+
262+
263 class CmdLogTest(unittest.TestCase):
264 def setUp(self):
265 # Patch the charmhelpers 'command', which powers get_config. The
266@@ -382,12 +406,15 @@
267 self.addCleanup(nginx_file.close)
268 config_js_file = tempfile.NamedTemporaryFile()
269 self.addCleanup(config_js_file.close)
270- start_gui(port, False, True, self.destination_file.name,
271- nginx_file.name, config_js_file.name)
272+ start_gui(
273+ port, False, True, '/tmp/certificates/',
274+ self.destination_file.name, nginx_file.name, config_js_file.name)
275 conf = self.destination_file.read()
276 self.assertTrue('/usr/sbin/nginx' in conf)
277 nginx_conf = nginx_file.read()
278 self.assertTrue('juju-gui/build-debug' in nginx_conf)
279+ self.assertIn('/tmp/certificates/server.pem', nginx_conf)
280+ self.assertIn('/tmp/certificates/server.key', nginx_conf)
281 self.assertEqual(self.svc_ctl_call_count, 1)
282 self.assertEqual(self.service_names, ['juju-gui'])
283 self.assertEqual(self.actions, [charmhelpers.START])

Subscribers

People subscribed via source and target branches