Merge lp:~bloodearnest/charms/precise/gunicorn/upgrade-path into lp:~charmers/charms/precise/gunicorn/trunk

Proposed by Simon Davy
Status: Merged
Merged at revision: 30
Proposed branch: lp:~bloodearnest/charms/precise/gunicorn/upgrade-path
Merge into: lp:~charmers/charms/precise/gunicorn/trunk
Diff against target: 159 lines (+76/-11)
3 files modified
hooks/hooks.py (+49/-8)
hooks/tests/test_hooks.py (+26/-2)
revision (+1/-1)
To merge this branch: bzr merge lp:~bloodearnest/charms/precise/gunicorn/upgrade-path
Reviewer Review Type Date Requested Status
Matt Bruzek (community) Approve
Wes Mason (community) Approve
Michael Nelson (community) Approve
Review via email: mp+213236@code.launchpad.net

Commit message

Allow an easier upgrade path from old bash version of charm by adding support for old env_extra relation data format, and removing old service. Plus, and fix bug/wart in config-changed hook.

Description of the change

add support for old env_extra relation data format, to allow an upgrade path.

The old format was a partial python dict format, e.g.

'A': 1, 'B': 'C'

The new format is standard env format, e.g

A=1 B="C"

This update adds support back for the old format, to allow an upgrade path, as it's impossible to upgrade a subordinate and its principle in lock-step.

It also removes the older-style gunicorn config and service from previous versions of the charm, if found.

Also, using remote_unit as job name doesn't work well in config-changed hooks, so switched to local_unit, as avoids unnecessary complications.

To post a comment you must log in.
32. By Simon Davy

catch additional missing exception

Revision history for this message
Michael Nelson (michael.nelson) wrote :

I ran into the issue related to remote_unit. Updated to this branch to fix that. Everything works except that I had to manually `juju ssh my-service/0 "sudo service gunicorn stop" (but that might just be related to the *very* old gunicorn charm I was using.

review: Approve
33. By Simon Davy

remove old gunicorn config if exists

Revision history for this message
Simon Davy (bloodearnest) wrote :

I had added code to remove the old non-upstart service on upgrade, if it exists.

34. By Simon Davy

bump to revision 4

Revision history for this message
Wes Mason (wesmason) :
review: Approve
35. By Simon Davy

fix string/int issue for wsgi_worker config

Revision history for this message
Simon Davy (bloodearnest) wrote :
36. By Simon Davy

better fix for wsgi_workers quoting issue

Revision history for this message
Matt Bruzek (mbruzek) wrote :

+1 LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'hooks/hooks.py'
--- hooks/hooks.py 2014-02-27 14:54:18 +0000
+++ hooks/hooks.py 2014-04-22 13:27:23 +0000
@@ -1,10 +1,12 @@
1#!/usr/bin/env python1#!/usr/bin/env python
2# vim: et ai ts=4 sw=4:2# vim: et ai ts=4 sw=4:
33
4import ast
4import os5import os
5import sys6import sys
6from multiprocessing import cpu_count7from multiprocessing import cpu_count
7import shlex8import shlex
9import glob
810
9from charmhelpers.core import hookenv11from charmhelpers.core import hookenv
10from charmhelpers.core import host12from charmhelpers.core import host
@@ -30,7 +32,7 @@
3032
3133
32def sanitized_service_name():34def sanitized_service_name():
33 return sanitize(hookenv.remote_unit().split('/')[0])35 return sanitize(hookenv.local_unit().split('/')[0])
3436
3537
36def upstart_conf_path(name):38def upstart_conf_path(name):
@@ -55,13 +57,39 @@
55# Hook functions57# Hook functions
56###############################################################################58###############################################################################
5759
5860def ensure_packages():
59@hooks.hook('install', 'upgrade-charm')
60def install():
61 fetch.apt_update()61 fetch.apt_update()
62 fetch.apt_install(CHARM_PACKAGES)62 fetch.apt_install(CHARM_PACKAGES)
6363
6464
65@hooks.hook('install')
66def install():
67 ensure_packages()
68
69
70@hooks.hook('upgrade-charm')
71def upgrade():
72 ensure_packages()
73 # if we are upgrading from older charm that used gunicorn runner rather
74 # than upstart, remove that job/config
75 # sadly, we don't 100% know the name of the job, as it depends on the
76 # remote unit name, which we don't know in upgrade-charm hook
77 # TODO: remove this at somepoint
78 files = glob.glob('/etc/gunicorn.d/*.conf')
79 if files:
80 try:
81 hookenv.log('stopping system gunicorn service')
82 host.service_stop('gunicorn')
83 except:
84 pass
85 for file in files:
86 try:
87 hookenv.log('removing old guncorn config: %s' % file)
88 os.remove(file)
89 except:
90 pass
91
92
65@hooks.hook(93@hooks.hook(
66 "config-changed",94 "config-changed",
67 "wsgi-file-relation-joined",95 "wsgi-file-relation-joined",
@@ -100,13 +128,26 @@
100 elif wsgi_config['wsgi_worker_class'] == 'tornado':128 elif wsgi_config['wsgi_worker_class'] == 'tornado':
101 fetch.apt_install('python-tornado')129 fetch.apt_install('python-tornado')
102130
103 if wsgi_config['wsgi_workers'] == 0:131 if str(wsgi_config['wsgi_workers']) == '0':
104 wsgi_config['wsgi_workers'] = cpu_count() + 1132 wsgi_config['wsgi_workers'] = cpu_count() + 1
105133
106 env_extra = wsgi_config.get('env_extra', '')134 env_extra = wsgi_config.get('env_extra', '')
107 wsgi_config['env_extra'] = [135
108 v.split('=') for v in shlex.split(env_extra) if '=' in v136 # support old python dict format for upgrade path
109 ]137 extra = []
138 # attempt dict parsing
139 try:
140 dict_str = '{' + env_extra + '}'
141 extra = [[k, str(v)] for k, v in ast.literal_eval(dict_str).items()]
142 except (SyntaxError, ValueError):
143 pass
144
145 if not extra:
146 extra = [
147 v.split('=', 1) for v in shlex.split(env_extra) if '=' in v
148 ]
149
150 wsgi_config['env_extra'] = extra
110151
111 process_template('upstart.tmpl', wsgi_config, project_conf)152 process_template('upstart.tmpl', wsgi_config, project_conf)
112153
113154
=== modified file 'hooks/tests/test_hooks.py'
--- hooks/tests/test_hooks.py 2014-02-27 14:54:18 +0000
+++ hooks/tests/test_hooks.py 2014-04-22 13:27:23 +0000
@@ -87,6 +87,19 @@
87 self.fetch.apt_install.assert_called_once_with(87 self.fetch.apt_install.assert_called_once_with(
88 ['gunicorn', 'python-jinja2'])88 ['gunicorn', 'python-jinja2'])
8989
90 @patch('hooks.glob.glob')
91 @patch('os.remove')
92 def test_python_upgrade_hook(self, mock_remove, mock_glob):
93 path = '/etc/gunicorn.d/unit.conf'
94 mock_glob.return_value = [path]
95 hooks.upgrade()
96 self.assertTrue(self.fetch.apt_update.called)
97 self.fetch.apt_install.assert_called_once_with(
98 ['gunicorn', 'python-jinja2'])
99
100 self.host.service_stop.assert_called_once_with('gunicorn')
101 mock_remove.assert_called_once_with(path)
102
90 def test_default_configure_gunicorn(self):103 def test_default_configure_gunicorn(self):
91 hooks.configure_gunicorn()104 hooks.configure_gunicorn()
92 expected = self.get_default_context()105 expected = self.get_default_context()
@@ -129,6 +142,19 @@
129142
130 self.assert_wsgi_config_applied(expected)143 self.assert_wsgi_config_applied(expected)
131144
145 def test_env_extra_old_style_parsing(self):
146 self.relation_data['env_extra'] = "'A': '1', 'B': 2"
147
148 hooks.configure_gunicorn()
149
150 expected = self.get_default_context()
151 expected['env_extra'] = [
152 ['A', '1'],
153 ['B', '2'],
154 ]
155
156 self.assert_wsgi_config_applied(expected)
157
132 def do_worker_class(self, worker_class):158 def do_worker_class(self, worker_class):
133 self.relation_data['wsgi_worker_class'] = worker_class159 self.relation_data['wsgi_worker_class'] = worker_class
134 hooks.configure_gunicorn()160 hooks.configure_gunicorn()
@@ -147,8 +173,6 @@
147 def test_configure_worker_class_gevent(self):173 def test_configure_worker_class_gevent(self):
148 self.do_worker_class('gevent')174 self.do_worker_class('gevent')
149175
150
151
152 @patch('hooks.os.remove')176 @patch('hooks.os.remove')
153 def test_wsgi_file_relation_broken(self, remove):177 def test_wsgi_file_relation_broken(self, remove):
154 hooks.wsgi_file_relation_broken()178 hooks.wsgi_file_relation_broken()
155179
=== modified file 'revision'
--- revision 2013-05-29 18:40:56 +0000
+++ revision 2014-04-22 13:27:23 +0000
@@ -1,1 +1,1 @@
1314

Subscribers

People subscribed via source and target branches

to all changes: