Merge lp:~johnsca/charms/trusty/haproxy/xenial-support into lp:~jamesj/charms/trusty/haproxy/xenial-support

Proposed by Cory Johns
Status: Merged
Approved by: James Jesudason
Approved revision: 105
Merged at revision: 106
Proposed branch: lp:~johnsca/charms/trusty/haproxy/xenial-support
Merge into: lp:~jamesj/charms/trusty/haproxy/xenial-support
Diff against target: 603 lines (+372/-184)
6 files modified
hooks/hooks.py (+2/-1)
hooks/tests/test_install.py (+3/-1)
metadata.yaml (+3/-0)
tests/10_deploy_test.py (+0/-182)
tests/11_deploy_test_trusty.py (+182/-0)
tests/12_deploy_test_xenial.py (+182/-0)
To merge this branch: bzr merge lp:~johnsca/charms/trusty/haproxy/xenial-support
Reviewer Review Type Date Requested Status
James Jesudason Approve
Review via email: mp+299470@code.launchpad.net

Description of the change

I added a deploy test for Xenial, and while running tests with that, hit a failure in the unit tests and an import error in the Xenial test, so I added fixes for both of those. I tried to add support for precise, but got a hook error so I removed it: http://pastebin.ubuntu.com/18729639/

I also added the supported series to the metadata per the new convention.

To post a comment you must log in.
Revision history for this message
James Jesudason (jamesj) wrote :

Thanks, that looks good.

I can't run tests locally at the moment as I'm on Juju 2.0. The two tests look as though they are very similar and could be refactored to call a function to remove the code duplication. I'll approve and merge for now and we can look at refactoring later.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/hooks.py'
2--- hooks/hooks.py 2016-07-04 16:40:17 +0000
3+++ hooks/hooks.py 2016-07-07 20:08:09 +0000
4@@ -914,7 +914,8 @@
5 apt_install(['haproxy', 'python-jinja2'], fatal=True)
6 # Install pyasn1 library and modules for inspecting SSL certificates
7 apt_install(
8- ['python-pyasn1', 'python-pyasn1-modules', 'python-apt'], fatal=False)
9+ ['python-pyasn1', 'python-pyasn1-modules', 'python-apt',
10+ 'python-openssl'], fatal=False)
11 ensure_package_status(service_affecting_packages,
12 config_data['package_status'])
13 enable_haproxy()
14
15=== modified file 'hooks/tests/test_install.py'
16--- hooks/tests/test_install.py 2015-09-23 15:12:08 +0000
17+++ hooks/tests/test_install.py 2016-07-07 20:08:09 +0000
18@@ -48,7 +48,9 @@
19 self.assertEqual((['haproxy', 'python-jinja2'],), calls[0][0])
20 self.assertEqual({'fatal': True}, calls[0][1])
21 self.assertEqual(
22- (['python-pyasn1', 'python-pyasn1-modules'],), calls[1][0])
23+ (['python-pyasn1', 'python-pyasn1-modules', 'python-apt',
24+ 'python-openssl'],),
25+ calls[1][0])
26 self.assertEqual({'fatal': False}, calls[1][1])
27
28 def test_add_source(self):
29
30=== modified file 'metadata.yaml'
31--- metadata.yaml 2016-03-03 20:08:09 +0000
32+++ metadata.yaml 2016-07-07 20:08:09 +0000
33@@ -8,6 +8,9 @@
34 has request blocking capabilities and provides interface to display server
35 status.
36 tags: ["cache-proxy"]
37+series:
38+ - xenial
39+ - trusty
40 requires:
41 reverseproxy:
42 interface: http
43
44=== removed file 'tests/10_deploy_test.py'
45--- tests/10_deploy_test.py 2015-11-19 18:13:43 +0000
46+++ tests/10_deploy_test.py 1970-01-01 00:00:00 +0000
47@@ -1,182 +0,0 @@
48-#!/usr/bin/python3
49-
50-# This Amulet test deploys haproxy and related charms.
51-
52-import os
53-import amulet
54-import requests
55-import base64
56-import yaml
57-import time
58-
59-d = amulet.Deployment(series='trusty')
60-# Add the haproxy charm to the deployment.
61-d.add('haproxy')
62-d.add('apache2', units=2)
63-
64-# Get the directory this way to load the file when CWD is different.
65-path = os.path.abspath(os.path.dirname(__file__))
66-template_path = os.path.join(path, 'default_apache.tmpl')
67-# Read in the Apache2 default template file.
68-with open(template_path) as f:
69- template = f.read()
70- encodedTemplate = base64.b64encode(template.encode('utf-8'))
71-# Create a dictionary with configuration values for apache2.
72-configuration = {'vhost_http_template': encodedTemplate.decode('ascii')}
73-# Apache2 needs a base64 encoded template to configure the web site.
74-d.configure('apache2', configuration)
75-
76-# Relate the haproxy to apache2.
77-d.relate('haproxy:reverseproxy', 'apache2:website')
78-# Make the haproxy visible to the outside world.
79-d.expose('haproxy')
80-
81-# The number of seconds to wait for the environment to setup.
82-seconds = 900
83-try:
84- # Execute the deployer with the current mapping.
85- d.setup(timeout=seconds)
86- # Wait for the relation to finish the transations.
87- d.sentry.wait(seconds)
88-except amulet.helpers.TimeoutError:
89- message = 'The environment did not setup in %d seconds.' % seconds
90- # The SKIP status enables skip or fail the test based on configuration.
91- amulet.raise_status(amulet.SKIP, msg=message)
92-except:
93- raise
94-
95-# Test that haproxy is acting as the proxy for apache2.
96-
97-# Get the haproxy unit.
98-haproxy_unit = d.sentry['haproxy'][0]
99-haproxy_address = haproxy_unit.info['public-address']
100-page = requests.get('http://%s/index.html' % haproxy_address)
101-# Raise an error if the page does not load through haproxy.
102-page.raise_for_status()
103-print('Successfully got the Apache2 web page through haproxy IP address.')
104-
105-# Test that sticky session cookie is present
106-if page.cookies.get('SRVNAME') != 'S0':
107- msg = 'Missing or invalid sticky session cookie value: %s' % page.cookies.get('SRVNAME')
108- amulet.raise_status(amulet.FAIL, msg=msg)
109-
110-# Test that the apache2 relation data is saved on the haproxy server.
111-
112-# Get the sentry for apache and get the private IP address.
113-apache_unit = d.sentry['apache2'][0]
114-# Get the relation.
115-relation = apache_unit.relation('website', 'haproxy:reverseproxy')
116-# Get the private address from the relation.
117-apache_private = relation['private-address']
118-
119-print('Private address of the apache2 relation ', apache_private)
120-
121-# Grep the configuration file for the private address
122-output, code = haproxy_unit.run('grep %s /etc/haproxy/haproxy.cfg' %
123- apache_private)
124-if code == 0:
125- print('Found the relation IP address in the haproxy configuration file!')
126- print(output)
127-else:
128- print(output)
129- message = 'Unable to find the Apache IP address %s in the haproxy ' \
130- 'configuration file.' % apache_private
131- amulet.raise_status(amulet.FAIL, msg=message)
132-
133-# Test SSL termination
134-d.configure('haproxy', {
135- 'source': 'backports',
136- 'ssl_cert': 'SELFSIGNED',
137- 'services': yaml.safe_dump([
138- {'service_name': 'apache',
139- 'service_host': '0.0.0.0',
140- 'service_port': 80,
141- 'service_options': [
142- 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0'
143- ],
144- 'servers': [
145- ['apache', apache_private, 80, 'maxconn 50']]},
146- {'service_name': 'apache-ssl',
147- 'service_port': 443,
148- 'service_host': '0.0.0.0',
149- 'service_options': [
150- 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0'
151- ],
152- 'crts': ['DEFAULT'],
153- 'servers': [['apache', apache_private, 80, 'maxconn 50']]}])
154-})
155-time.sleep(10)
156-d.sentry.wait(seconds)
157-
158-# We need a retry loop here, since there's no way to tell when the new
159-# configuration is in place.
160-url = 'http://%s/index.html' % haproxy_address
161-secure_url = 'https://%s/index.html' % haproxy_address
162-retries = 10
163-for i in range(retries):
164- try:
165- page = requests.get(url)
166- page.raise_for_status()
167- page = requests.get(secure_url, verify=False)
168- page.raise_for_status()
169- success = True
170- except requests.exceptions.ConnectionError:
171- if i == retries - 1:
172- # This was the last one, let's fail
173- raise
174- time.sleep(6)
175- else:
176- break
177-
178-print('Successfully got the Apache2 web page through haproxy SSL termination.')
179-
180-apache_unit2 = d.sentry['apache2'][1]
181-apache_private2 = apache_unit2.run("unit-get private-address")[0]
182-
183-# Create a file on the second apache unit's www directory.
184-apache_unit2.run("echo foo > /var/www/html/foo")
185-
186-d.configure('haproxy', {
187- 'services': yaml.safe_dump([
188- {'service_name': 'apache',
189- 'service_host': '0.0.0.0',
190- 'service_port': 80,
191- 'service_options': [
192- 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0',
193- 'acl foo path_beg -i /foo', 'use_backend foo if foo',
194- ],
195- 'servers': [
196- ['apache', apache_private, 80, 'maxconn 50']],
197- 'backends': [
198- {'backend_name': 'foo',
199- 'servers': [
200- ['apache2', apache_private2, 80, 'maxconn 50']]}
201- ]}])
202-})
203-time.sleep(10)
204-d.sentry.wait(seconds)
205-
206-# Let's exercise our URL-based routing by trying to fetch a URL that will
207-# only work for the second apache unit (which is configured as server
208-# of the extra backend).
209-url = 'http://%s/foo' % haproxy_address
210-
211-# We need a retry loop here, since there's no way to tell when the new
212-# configuration is in place.
213-retries = 10
214-for i in range(retries):
215- try:
216- page = requests.get(url)
217- page.raise_for_status()
218- except:
219- if i == retries - 1:
220- # This was the last one, let's fail
221- raise
222- time.sleep(6)
223- else:
224- break
225-
226-print('Successfully got the /foo URL from the second Apache unit.')
227-
228-# Send a message that the tests are complete.
229-print('The haproxy tests are complete.')
230
231=== added file 'tests/11_deploy_test_trusty.py'
232--- tests/11_deploy_test_trusty.py 1970-01-01 00:00:00 +0000
233+++ tests/11_deploy_test_trusty.py 2016-07-07 20:08:09 +0000
234@@ -0,0 +1,182 @@
235+#!/usr/bin/python3
236+
237+# This Amulet test deploys haproxy and related charms.
238+
239+import os
240+import amulet
241+import requests
242+import base64
243+import yaml
244+import time
245+
246+d = amulet.Deployment(series='trusty')
247+# Add the haproxy charm to the deployment.
248+d.add('haproxy')
249+d.add('apache2', units=2)
250+
251+# Get the directory this way to load the file when CWD is different.
252+path = os.path.abspath(os.path.dirname(__file__))
253+template_path = os.path.join(path, 'default_apache.tmpl')
254+# Read in the Apache2 default template file.
255+with open(template_path) as f:
256+ template = f.read()
257+ encodedTemplate = base64.b64encode(template.encode('utf-8'))
258+# Create a dictionary with configuration values for apache2.
259+configuration = {'vhost_http_template': encodedTemplate.decode('ascii')}
260+# Apache2 needs a base64 encoded template to configure the web site.
261+d.configure('apache2', configuration)
262+
263+# Relate the haproxy to apache2.
264+d.relate('haproxy:reverseproxy', 'apache2:website')
265+# Make the haproxy visible to the outside world.
266+d.expose('haproxy')
267+
268+# The number of seconds to wait for the environment to setup.
269+seconds = 900
270+try:
271+ # Execute the deployer with the current mapping.
272+ d.setup(timeout=seconds)
273+ # Wait for the relation to finish the transations.
274+ d.sentry.wait(seconds)
275+except amulet.helpers.TimeoutError:
276+ message = 'The environment did not setup in %d seconds.' % seconds
277+ # The SKIP status enables skip or fail the test based on configuration.
278+ amulet.raise_status(amulet.SKIP, msg=message)
279+except:
280+ raise
281+
282+# Test that haproxy is acting as the proxy for apache2.
283+
284+# Get the haproxy unit.
285+haproxy_unit = d.sentry['haproxy'][0]
286+haproxy_address = haproxy_unit.info['public-address']
287+page = requests.get('http://%s/index.html' % haproxy_address)
288+# Raise an error if the page does not load through haproxy.
289+page.raise_for_status()
290+print('Successfully got the Apache2 web page through haproxy IP address.')
291+
292+# Test that sticky session cookie is present
293+if page.cookies.get('SRVNAME') != 'S0':
294+ msg = 'Missing or invalid sticky session cookie value: %s' % page.cookies.get('SRVNAME')
295+ amulet.raise_status(amulet.FAIL, msg=msg)
296+
297+# Test that the apache2 relation data is saved on the haproxy server.
298+
299+# Get the sentry for apache and get the private IP address.
300+apache_unit = d.sentry['apache2'][0]
301+# Get the relation.
302+relation = apache_unit.relation('website', 'haproxy:reverseproxy')
303+# Get the private address from the relation.
304+apache_private = relation['private-address']
305+
306+print('Private address of the apache2 relation ', apache_private)
307+
308+# Grep the configuration file for the private address
309+output, code = haproxy_unit.run('grep %s /etc/haproxy/haproxy.cfg' %
310+ apache_private)
311+if code == 0:
312+ print('Found the relation IP address in the haproxy configuration file!')
313+ print(output)
314+else:
315+ print(output)
316+ message = 'Unable to find the Apache IP address %s in the haproxy ' \
317+ 'configuration file.' % apache_private
318+ amulet.raise_status(amulet.FAIL, msg=message)
319+
320+# Test SSL termination
321+d.configure('haproxy', {
322+ 'source': 'backports',
323+ 'ssl_cert': 'SELFSIGNED',
324+ 'services': yaml.safe_dump([
325+ {'service_name': 'apache',
326+ 'service_host': '0.0.0.0',
327+ 'service_port': 80,
328+ 'service_options': [
329+ 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0'
330+ ],
331+ 'servers': [
332+ ['apache', apache_private, 80, 'maxconn 50']]},
333+ {'service_name': 'apache-ssl',
334+ 'service_port': 443,
335+ 'service_host': '0.0.0.0',
336+ 'service_options': [
337+ 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0'
338+ ],
339+ 'crts': ['DEFAULT'],
340+ 'servers': [['apache', apache_private, 80, 'maxconn 50']]}])
341+})
342+time.sleep(10)
343+d.sentry.wait(seconds)
344+
345+# We need a retry loop here, since there's no way to tell when the new
346+# configuration is in place.
347+url = 'http://%s/index.html' % haproxy_address
348+secure_url = 'https://%s/index.html' % haproxy_address
349+retries = 10
350+for i in range(retries):
351+ try:
352+ page = requests.get(url)
353+ page.raise_for_status()
354+ page = requests.get(secure_url, verify=False)
355+ page.raise_for_status()
356+ success = True
357+ except requests.exceptions.ConnectionError:
358+ if i == retries - 1:
359+ # This was the last one, let's fail
360+ raise
361+ time.sleep(6)
362+ else:
363+ break
364+
365+print('Successfully got the Apache2 web page through haproxy SSL termination.')
366+
367+apache_unit2 = d.sentry['apache2'][1]
368+apache_private2 = apache_unit2.run("unit-get private-address")[0]
369+
370+# Create a file on the second apache unit's www directory.
371+apache_unit2.run("echo foo > /var/www/html/foo")
372+
373+d.configure('haproxy', {
374+ 'services': yaml.safe_dump([
375+ {'service_name': 'apache',
376+ 'service_host': '0.0.0.0',
377+ 'service_port': 80,
378+ 'service_options': [
379+ 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0',
380+ 'acl foo path_beg -i /foo', 'use_backend foo if foo',
381+ ],
382+ 'servers': [
383+ ['apache', apache_private, 80, 'maxconn 50']],
384+ 'backends': [
385+ {'backend_name': 'foo',
386+ 'servers': [
387+ ['apache2', apache_private2, 80, 'maxconn 50']]}
388+ ]}])
389+})
390+time.sleep(10)
391+d.sentry.wait(seconds)
392+
393+# Let's exercise our URL-based routing by trying to fetch a URL that will
394+# only work for the second apache unit (which is configured as server
395+# of the extra backend).
396+url = 'http://%s/foo' % haproxy_address
397+
398+# We need a retry loop here, since there's no way to tell when the new
399+# configuration is in place.
400+retries = 10
401+for i in range(retries):
402+ try:
403+ page = requests.get(url)
404+ page.raise_for_status()
405+ except:
406+ if i == retries - 1:
407+ # This was the last one, let's fail
408+ raise
409+ time.sleep(6)
410+ else:
411+ break
412+
413+print('Successfully got the /foo URL from the second Apache unit.')
414+
415+# Send a message that the tests are complete.
416+print('The haproxy tests are complete.')
417
418=== added file 'tests/12_deploy_test_xenial.py'
419--- tests/12_deploy_test_xenial.py 1970-01-01 00:00:00 +0000
420+++ tests/12_deploy_test_xenial.py 2016-07-07 20:08:09 +0000
421@@ -0,0 +1,182 @@
422+#!/usr/bin/python3
423+
424+# This Amulet test deploys haproxy and related charms.
425+
426+import os
427+import amulet
428+import requests
429+import base64
430+import yaml
431+import time
432+
433+d = amulet.Deployment(series='xenial')
434+# Add the haproxy charm to the deployment.
435+d.add('haproxy')
436+d.add('apache2', 'cs:trusty/apache2', units=2)
437+
438+# Get the directory this way to load the file when CWD is different.
439+path = os.path.abspath(os.path.dirname(__file__))
440+template_path = os.path.join(path, 'default_apache.tmpl')
441+# Read in the Apache2 default template file.
442+with open(template_path) as f:
443+ template = f.read()
444+ encodedTemplate = base64.b64encode(template.encode('utf-8'))
445+# Create a dictionary with configuration values for apache2.
446+configuration = {'vhost_http_template': encodedTemplate.decode('ascii')}
447+# Apache2 needs a base64 encoded template to configure the web site.
448+d.configure('apache2', configuration)
449+
450+# Relate the haproxy to apache2.
451+d.relate('haproxy:reverseproxy', 'apache2:website')
452+# Make the haproxy visible to the outside world.
453+d.expose('haproxy')
454+
455+# The number of seconds to wait for the environment to setup.
456+seconds = 900
457+try:
458+ # Execute the deployer with the current mapping.
459+ d.setup(timeout=seconds)
460+ # Wait for the relation to finish the transations.
461+ d.sentry.wait(seconds)
462+except amulet.helpers.TimeoutError:
463+ message = 'The environment did not setup in %d seconds.' % seconds
464+ # The SKIP status enables skip or fail the test based on configuration.
465+ amulet.raise_status(amulet.SKIP, msg=message)
466+except:
467+ raise
468+
469+# Test that haproxy is acting as the proxy for apache2.
470+
471+# Get the haproxy unit.
472+haproxy_unit = d.sentry['haproxy'][0]
473+haproxy_address = haproxy_unit.info['public-address']
474+page = requests.get('http://%s/index.html' % haproxy_address)
475+# Raise an error if the page does not load through haproxy.
476+page.raise_for_status()
477+print('Successfully got the Apache2 web page through haproxy IP address.')
478+
479+# Test that sticky session cookie is present
480+if page.cookies.get('SRVNAME') != 'S0':
481+ msg = 'Missing or invalid sticky session cookie value: %s' % page.cookies.get('SRVNAME')
482+ amulet.raise_status(amulet.FAIL, msg=msg)
483+
484+# Test that the apache2 relation data is saved on the haproxy server.
485+
486+# Get the sentry for apache and get the private IP address.
487+apache_unit = d.sentry['apache2'][0]
488+# Get the relation.
489+relation = apache_unit.relation('website', 'haproxy:reverseproxy')
490+# Get the private address from the relation.
491+apache_private = relation['private-address']
492+
493+print('Private address of the apache2 relation ', apache_private)
494+
495+# Grep the configuration file for the private address
496+output, code = haproxy_unit.run('grep %s /etc/haproxy/haproxy.cfg' %
497+ apache_private)
498+if code == 0:
499+ print('Found the relation IP address in the haproxy configuration file!')
500+ print(output)
501+else:
502+ print(output)
503+ message = 'Unable to find the Apache IP address %s in the haproxy ' \
504+ 'configuration file.' % apache_private
505+ amulet.raise_status(amulet.FAIL, msg=message)
506+
507+# Test SSL termination
508+d.configure('haproxy', {
509+ 'source': 'backports',
510+ 'ssl_cert': 'SELFSIGNED',
511+ 'services': yaml.safe_dump([
512+ {'service_name': 'apache',
513+ 'service_host': '0.0.0.0',
514+ 'service_port': 80,
515+ 'service_options': [
516+ 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0'
517+ ],
518+ 'servers': [
519+ ['apache', apache_private, 80, 'maxconn 50']]},
520+ {'service_name': 'apache-ssl',
521+ 'service_port': 443,
522+ 'service_host': '0.0.0.0',
523+ 'service_options': [
524+ 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0'
525+ ],
526+ 'crts': ['DEFAULT'],
527+ 'servers': [['apache', apache_private, 80, 'maxconn 50']]}])
528+})
529+time.sleep(10)
530+d.sentry.wait(seconds)
531+
532+# We need a retry loop here, since there's no way to tell when the new
533+# configuration is in place.
534+url = 'http://%s/index.html' % haproxy_address
535+secure_url = 'https://%s/index.html' % haproxy_address
536+retries = 10
537+for i in range(retries):
538+ try:
539+ page = requests.get(url)
540+ page.raise_for_status()
541+ page = requests.get(secure_url, verify=False)
542+ page.raise_for_status()
543+ success = True
544+ except requests.exceptions.ConnectionError:
545+ if i == retries - 1:
546+ # This was the last one, let's fail
547+ raise
548+ time.sleep(6)
549+ else:
550+ break
551+
552+print('Successfully got the Apache2 web page through haproxy SSL termination.')
553+
554+apache_unit2 = d.sentry['apache2'][1]
555+apache_private2 = apache_unit2.run("unit-get private-address")[0]
556+
557+# Create a file on the second apache unit's www directory.
558+apache_unit2.run("echo foo > /var/www/html/foo")
559+
560+d.configure('haproxy', {
561+ 'services': yaml.safe_dump([
562+ {'service_name': 'apache',
563+ 'service_host': '0.0.0.0',
564+ 'service_port': 80,
565+ 'service_options': [
566+ 'mode http', 'balance leastconn', 'option httpchk GET / HTTP/1.0',
567+ 'acl foo path_beg -i /foo', 'use_backend foo if foo',
568+ ],
569+ 'servers': [
570+ ['apache', apache_private, 80, 'maxconn 50']],
571+ 'backends': [
572+ {'backend_name': 'foo',
573+ 'servers': [
574+ ['apache2', apache_private2, 80, 'maxconn 50']]}
575+ ]}])
576+})
577+time.sleep(10)
578+d.sentry.wait(seconds)
579+
580+# Let's exercise our URL-based routing by trying to fetch a URL that will
581+# only work for the second apache unit (which is configured as server
582+# of the extra backend).
583+url = 'http://%s/foo' % haproxy_address
584+
585+# We need a retry loop here, since there's no way to tell when the new
586+# configuration is in place.
587+retries = 10
588+for i in range(retries):
589+ try:
590+ page = requests.get(url)
591+ page.raise_for_status()
592+ except:
593+ if i == retries - 1:
594+ # This was the last one, let's fail
595+ raise
596+ time.sleep(6)
597+ else:
598+ break
599+
600+print('Successfully got the /foo URL from the second Apache unit.')
601+
602+# Send a message that the tests are complete.
603+print('The haproxy tests are complete.')

Subscribers

People subscribed via source and target branches

to all changes: