Merge lp:~ajkavanagh/charms/trusty/keystone/add-service-checks-lp1524388 into lp:~openstack-charmers-archive/charms/trusty/keystone/next
- Trusty Tahr (14.04)
- add-service-checks-lp1524388
- Merge into next
Status: | Merged |
---|---|
Merged at revision: | 209 |
Proposed branch: | lp:~ajkavanagh/charms/trusty/keystone/add-service-checks-lp1524388 |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/keystone/next |
Diff against target: |
220 lines (+109/-5) 6 files modified
charmhelpers/contrib/network/ip.py (+15/-0) charmhelpers/contrib/openstack/context.py (+5/-1) charmhelpers/contrib/openstack/templates/section-keystone-authtoken (+11/-0) charmhelpers/contrib/openstack/utils.py (+73/-2) hooks/keystone_utils.py (+2/-1) unit_tests/test_keystone_utils.py (+3/-1) |
To merge this branch: | bzr merge lp:~ajkavanagh/charms/trusty/keystone/add-service-checks-lp1524388 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
David Ames (community) | Approve | ||
Review via email: mp+285608@code.launchpad.net |
Commit message
Description of the change
For review/comments only:
Synced in lp:~ajkavanagh/charm-helpers/add-service-checks-lp1524388 version
of charm-helpers to test that modification will work - this is for demo
purposes only and will be revised prior to merge proposal.
The modified version of charm-helpers actually checks if the service is running
and listening on any ports specified. This change to keystone adds the service
and port checks as part of assess_status().
Also changed tests to to work with revision 514:
"misc changes for haproxy template and context ..."
which required changes to the test_haproxy_
uosci-testing-bot (uosci-testing-bot) wrote : | # |
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #307 keystone-next for ajkavanagh mp285608
UNIT OK: passed
David Ames (thedac) wrote : | # |
This looks great. And will be ready to merge after two more steps.
One, we have some text conflicts that need to be resolved.
Two, my manual run of unit tests are failing due to issues not related to your change. I'd like to see the result of the automated run of unit tests so I have moved this from WIP to needs review which should kick that off.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #157 keystone-next for ajkavanagh mp285608
AMULET OK: passed
Alex Kavanagh (ajkavanagh) wrote : | # |
> One, we have some text conflicts that need to be resolved.
I'm guessing this means some more changes in keystone?
I'm also guessing we need to get the charm-helpers change(s) merged first, then re-sync on keystone (on this one) + any further changes on keystone, and get that in as a merge? Also, did the 'determine_ports()' change alleviate your concerns around ports and HA?
Thanks again for the review :)
David Ames (thedac) wrote : | # |
Alex, Sorry about this I meant my comments above to be on the Charm helpers MP.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #832 keystone-next for ajkavanagh mp285608
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #735 keystone-next for ajkavanagh mp285608
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #333 keystone-next for ajkavanagh mp285608
AMULET OK: passed
David Ames (thedac) wrote : | # |
> > One, we have some text conflicts that need to be resolved.
>
> I'm guessing this means some more changes in keystone?
We still have text conflicts for this one.
bzr branch lp:~openstack-charmers/charms/trusty/keystone/next
cd keystone
bzr merge lp:~ajkavanagh/charms/trusty/keystone/add-service-checks-lp1524388
bzr st # shows text conflicts
> I'm also guessing we need to get the charm-helpers change(s) merged first,
> then re-sync on keystone (on this one) + any further changes on keystone, and
> get that in as a merge? Also, did the 'determine_ports()' change alleviate
> your concerns around ports and HA?
>
> Thanks again for the review :)
CH changes were merged. They may need to be resynced to fix part of the above text conflicts.
I like the determine_ports() solution. We might want to add the ports the keystone service is listening on as well (not haproxy) for extra thouroughness. 35347 and 4990 while still including the well known ports 35357 and 5000.
After the above is resolved, we can merge this thing.
- 201. By Alex Kavanagh
-
Resync charmhelpers to current version
- 202. By Alex Kavanagh
-
Merge keystone/next into change to get ready for final merge
Alex Kavanagh (ajkavanagh) wrote : | # |
> > > One, we have some text conflicts that need to be resolved.
> >
> > I'm guessing this means some more changes in keystone?
>
> We still have text conflicts for this one.
>
> bzr branch lp:~openstack-charmers/charms/trusty/keystone/next
> cd keystone
> bzr merge lp:~ajkavanagh/charms/trusty/keystone/add-service-checks-lp1524388
> bzr st # shows text conflicts
>
> > I'm also guessing we need to get the charm-helpers change(s) merged first,
> > then re-sync on keystone (on this one) + any further changes on keystone,
> and
> > get that in as a merge? Also, did the 'determine_ports()' change alleviate
> > your concerns around ports and HA?
> >
> > Thanks again for the review :)
>
> CH changes were merged. They may need to be resynced to fix part of the above
> text conflicts.
>
> I like the determine_ports() solution. We might want to add the ports the
> keystone service is listening on as well (not haproxy) for extra
> thouroughness. 35347 and 4990 while still including the well known ports 35357
> and 5000.
>
> After the above is resolved, we can merge this thing.
Sortee the CH changes and also merged latest keystone/next into the branch.
Re the extra ports, would you like them hard-coded into the file, or determined from config (if there is any?)
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #917 keystone-next for ajkavanagh mp285608
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #817 keystone-next for ajkavanagh mp285608
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #363 keystone-next for ajkavanagh mp285608
AMULET OK: passed
David Ames (thedac) wrote : | # |
This looks good. We can discuss the other ports in our next meeting and do a trivial push if needed.
Merging.
Preview Diff
1 | === modified file 'charmhelpers/contrib/network/ip.py' | |||
2 | --- charmhelpers/contrib/network/ip.py 2016-01-04 21:27:51 +0000 | |||
3 | +++ charmhelpers/contrib/network/ip.py 2016-02-19 14:51:35 +0000 | |||
4 | @@ -456,3 +456,18 @@ | |||
5 | 456 | return result | 456 | return result |
6 | 457 | else: | 457 | else: |
7 | 458 | return result.split('.')[0] | 458 | return result.split('.')[0] |
8 | 459 | |||
9 | 460 | |||
10 | 461 | def port_has_listener(address, port): | ||
11 | 462 | """ | ||
12 | 463 | Returns True if the address:port is open and being listened to, | ||
13 | 464 | else False. | ||
14 | 465 | |||
15 | 466 | @param address: an IP address or hostname | ||
16 | 467 | @param port: integer port | ||
17 | 468 | |||
18 | 469 | Note calls 'zc' via a subprocess shell | ||
19 | 470 | """ | ||
20 | 471 | cmd = ['nc', '-z', address, str(port)] | ||
21 | 472 | result = subprocess.call(cmd) | ||
22 | 473 | return not(bool(result)) | ||
23 | 459 | 474 | ||
24 | === modified file 'charmhelpers/contrib/openstack/context.py' | |||
25 | --- charmhelpers/contrib/openstack/context.py 2016-02-11 14:43:33 +0000 | |||
26 | +++ charmhelpers/contrib/openstack/context.py 2016-02-19 14:51:35 +0000 | |||
27 | @@ -410,6 +410,7 @@ | |||
28 | 410 | auth_host = format_ipv6_addr(auth_host) or auth_host | 410 | auth_host = format_ipv6_addr(auth_host) or auth_host |
29 | 411 | svc_protocol = rdata.get('service_protocol') or 'http' | 411 | svc_protocol = rdata.get('service_protocol') or 'http' |
30 | 412 | auth_protocol = rdata.get('auth_protocol') or 'http' | 412 | auth_protocol = rdata.get('auth_protocol') or 'http' |
31 | 413 | api_version = rdata.get('api_version') or '2.0' | ||
32 | 413 | ctxt.update({'service_port': rdata.get('service_port'), | 414 | ctxt.update({'service_port': rdata.get('service_port'), |
33 | 414 | 'service_host': serv_host, | 415 | 'service_host': serv_host, |
34 | 415 | 'auth_host': auth_host, | 416 | 'auth_host': auth_host, |
35 | @@ -418,7 +419,8 @@ | |||
36 | 418 | 'admin_user': rdata.get('service_username'), | 419 | 'admin_user': rdata.get('service_username'), |
37 | 419 | 'admin_password': rdata.get('service_password'), | 420 | 'admin_password': rdata.get('service_password'), |
38 | 420 | 'service_protocol': svc_protocol, | 421 | 'service_protocol': svc_protocol, |
40 | 421 | 'auth_protocol': auth_protocol}) | 422 | 'auth_protocol': auth_protocol, |
41 | 423 | 'api_version': api_version}) | ||
42 | 422 | 424 | ||
43 | 423 | if self.context_complete(ctxt): | 425 | if self.context_complete(ctxt): |
44 | 424 | # NOTE(jamespage) this is required for >= icehouse | 426 | # NOTE(jamespage) this is required for >= icehouse |
45 | @@ -1471,6 +1473,8 @@ | |||
46 | 1471 | rdata.get('service_protocol') or 'http', | 1473 | rdata.get('service_protocol') or 'http', |
47 | 1472 | 'auth_protocol': | 1474 | 'auth_protocol': |
48 | 1473 | rdata.get('auth_protocol') or 'http', | 1475 | rdata.get('auth_protocol') or 'http', |
49 | 1476 | 'api_version': | ||
50 | 1477 | rdata.get('api_version') or '2.0', | ||
51 | 1474 | } | 1478 | } |
52 | 1475 | if self.context_complete(ctxt): | 1479 | if self.context_complete(ctxt): |
53 | 1476 | return ctxt | 1480 | return ctxt |
54 | 1477 | 1481 | ||
55 | === modified file 'charmhelpers/contrib/openstack/templates/section-keystone-authtoken' | |||
56 | --- charmhelpers/contrib/openstack/templates/section-keystone-authtoken 2015-03-25 09:18:33 +0000 | |||
57 | +++ charmhelpers/contrib/openstack/templates/section-keystone-authtoken 2016-02-19 14:51:35 +0000 | |||
58 | @@ -1,4 +1,14 @@ | |||
59 | 1 | {% if auth_host -%} | 1 | {% if auth_host -%} |
60 | 2 | {% if api_version == '3' -%} | ||
61 | 3 | [keystone_authtoken] | ||
62 | 4 | auth_url = {{ service_protocol }}://{{ service_host }}:{{ service_port }} | ||
63 | 5 | project_name = {{ admin_tenant_name }} | ||
64 | 6 | username = {{ admin_user }} | ||
65 | 7 | password = {{ admin_password }} | ||
66 | 8 | project_domain_name = default | ||
67 | 9 | user_domain_name = default | ||
68 | 10 | auth_plugin = password | ||
69 | 11 | {% else -%} | ||
70 | 2 | [keystone_authtoken] | 12 | [keystone_authtoken] |
71 | 3 | identity_uri = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/{{ auth_admin_prefix }} | 13 | identity_uri = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/{{ auth_admin_prefix }} |
72 | 4 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/{{ service_admin_prefix }} | 14 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/{{ service_admin_prefix }} |
73 | @@ -7,3 +17,4 @@ | |||
74 | 7 | admin_password = {{ admin_password }} | 17 | admin_password = {{ admin_password }} |
75 | 8 | signing_dir = {{ signing_dir }} | 18 | signing_dir = {{ signing_dir }} |
76 | 9 | {% endif -%} | 19 | {% endif -%} |
77 | 20 | {% endif -%} | ||
78 | 10 | 21 | ||
79 | === modified file 'charmhelpers/contrib/openstack/utils.py' | |||
80 | --- charmhelpers/contrib/openstack/utils.py 2016-02-11 15:44:13 +0000 | |||
81 | +++ charmhelpers/contrib/openstack/utils.py 2016-02-19 14:51:35 +0000 | |||
82 | @@ -23,6 +23,7 @@ | |||
83 | 23 | import os | 23 | import os |
84 | 24 | import sys | 24 | import sys |
85 | 25 | import re | 25 | import re |
86 | 26 | import itertools | ||
87 | 26 | 27 | ||
88 | 27 | import six | 28 | import six |
89 | 28 | import tempfile | 29 | import tempfile |
90 | @@ -60,6 +61,7 @@ | |||
91 | 60 | from charmhelpers.contrib.network.ip import ( | 61 | from charmhelpers.contrib.network.ip import ( |
92 | 61 | get_ipv6_addr, | 62 | get_ipv6_addr, |
93 | 62 | is_ipv6, | 63 | is_ipv6, |
94 | 64 | port_has_listener, | ||
95 | 63 | ) | 65 | ) |
96 | 64 | 66 | ||
97 | 65 | from charmhelpers.contrib.python.packages import ( | 67 | from charmhelpers.contrib.python.packages import ( |
98 | @@ -67,7 +69,7 @@ | |||
99 | 67 | pip_install, | 69 | pip_install, |
100 | 68 | ) | 70 | ) |
101 | 69 | 71 | ||
103 | 70 | from charmhelpers.core.host import lsb_release, mounts, umount | 72 | from charmhelpers.core.host import lsb_release, mounts, umount, service_running |
104 | 71 | from charmhelpers.fetch import apt_install, apt_cache, install_remote | 73 | from charmhelpers.fetch import apt_install, apt_cache, install_remote |
105 | 72 | from charmhelpers.contrib.storage.linux.utils import is_block_device, zap_disk | 74 | from charmhelpers.contrib.storage.linux.utils import is_block_device, zap_disk |
106 | 73 | from charmhelpers.contrib.storage.linux.loopback import ensure_loopback_device | 75 | from charmhelpers.contrib.storage.linux.loopback import ensure_loopback_device |
107 | @@ -860,13 +862,23 @@ | |||
108 | 860 | return wrap | 862 | return wrap |
109 | 861 | 863 | ||
110 | 862 | 864 | ||
112 | 863 | def set_os_workload_status(configs, required_interfaces, charm_func=None): | 865 | def set_os_workload_status(configs, required_interfaces, charm_func=None, services=None, ports=None): |
113 | 864 | """ | 866 | """ |
114 | 865 | Set workload status based on complete contexts. | 867 | Set workload status based on complete contexts. |
115 | 866 | status-set missing or incomplete contexts | 868 | status-set missing or incomplete contexts |
116 | 867 | and juju-log details of missing required data. | 869 | and juju-log details of missing required data. |
117 | 868 | charm_func is a charm specific function to run checking | 870 | charm_func is a charm specific function to run checking |
118 | 869 | for charm specific requirements such as a VIP setting. | 871 | for charm specific requirements such as a VIP setting. |
119 | 872 | |||
120 | 873 | This function also checks for whether the services defined are ACTUALLY | ||
121 | 874 | running and that the ports they advertise are open and being listened to. | ||
122 | 875 | |||
123 | 876 | @param services - OPTIONAL: a [{'service': <string>, 'ports': [<int>]] | ||
124 | 877 | The ports are optional. | ||
125 | 878 | If services is a [<string>] then ports are ignored. | ||
126 | 879 | @param ports - OPTIONAL: an [<int>] representing ports that shoudl be | ||
127 | 880 | open. | ||
128 | 881 | @returns None | ||
129 | 870 | """ | 882 | """ |
130 | 871 | incomplete_rel_data = incomplete_relation_data(configs, required_interfaces) | 883 | incomplete_rel_data = incomplete_relation_data(configs, required_interfaces) |
131 | 872 | state = 'active' | 884 | state = 'active' |
132 | @@ -945,6 +957,65 @@ | |||
133 | 945 | else: | 957 | else: |
134 | 946 | message = charm_message | 958 | message = charm_message |
135 | 947 | 959 | ||
136 | 960 | # If the charm thinks the unit is active, check that the actual services | ||
137 | 961 | # really are active. | ||
138 | 962 | if services is not None and state == 'active': | ||
139 | 963 | # if we're passed the dict() then just grab the values as a list. | ||
140 | 964 | if isinstance(services, dict): | ||
141 | 965 | services = services.values() | ||
142 | 966 | # either extract the list of services from the dictionary, or if | ||
143 | 967 | # it is a simple string, use that. i.e. works with mixed lists. | ||
144 | 968 | _s = [] | ||
145 | 969 | for s in services: | ||
146 | 970 | if isinstance(s, dict) and 'service' in s: | ||
147 | 971 | _s.append(s['service']) | ||
148 | 972 | if isinstance(s, str): | ||
149 | 973 | _s.append(s) | ||
150 | 974 | services_running = [service_running(s) for s in _s] | ||
151 | 975 | if not all(services_running): | ||
152 | 976 | not_running = [s for s, running in zip(_s, services_running) | ||
153 | 977 | if not running] | ||
154 | 978 | message = ("Services not running that should be: {}" | ||
155 | 979 | .format(", ".join(not_running))) | ||
156 | 980 | state = 'blocked' | ||
157 | 981 | # also verify that the ports that should be open are open | ||
158 | 982 | # NB, that ServiceManager objects only OPTIONALLY have ports | ||
159 | 983 | port_map = OrderedDict([(s['service'], s['ports']) | ||
160 | 984 | for s in services if 'ports' in s]) | ||
161 | 985 | if state == 'active' and port_map: | ||
162 | 986 | all_ports = list(itertools.chain(*port_map.values())) | ||
163 | 987 | ports_open = [port_has_listener('0.0.0.0', p) | ||
164 | 988 | for p in all_ports] | ||
165 | 989 | if not all(ports_open): | ||
166 | 990 | not_opened = [p for p, opened in zip(all_ports, ports_open) | ||
167 | 991 | if not opened] | ||
168 | 992 | map_not_open = OrderedDict() | ||
169 | 993 | for service, ports in port_map.items(): | ||
170 | 994 | closed_ports = set(ports).intersection(not_opened) | ||
171 | 995 | if closed_ports: | ||
172 | 996 | map_not_open[service] = closed_ports | ||
173 | 997 | # find which service has missing ports. They are in service | ||
174 | 998 | # order which makes it a bit easier. | ||
175 | 999 | message = ( | ||
176 | 1000 | "Services with ports not open that should be: {}" | ||
177 | 1001 | .format( | ||
178 | 1002 | ", ".join([ | ||
179 | 1003 | "{}: [{}]".format( | ||
180 | 1004 | service, | ||
181 | 1005 | ", ".join([str(v) for v in ports])) | ||
182 | 1006 | for service, ports in map_not_open.items()]))) | ||
183 | 1007 | state = 'blocked' | ||
184 | 1008 | |||
185 | 1009 | if ports is not None and state == 'active': | ||
186 | 1010 | # and we can also check ports which we don't know the service for | ||
187 | 1011 | ports_open = [port_has_listener('0.0.0.0', p) for p in ports] | ||
188 | 1012 | if not all(ports_open): | ||
189 | 1013 | message = ( | ||
190 | 1014 | "Ports which should be open, but are not: {}" | ||
191 | 1015 | .format(", ".join([str(p) for p, v in zip(ports, ports_open) | ||
192 | 1016 | if not v]))) | ||
193 | 1017 | state = 'blocked' | ||
194 | 1018 | |||
195 | 948 | # Set to active if all requirements have been met | 1019 | # Set to active if all requirements have been met |
196 | 949 | if state == 'active': | 1020 | if state == 'active': |
197 | 950 | message = "Unit is ready" | 1021 | message = "Unit is ready" |
198 | 951 | 1022 | ||
199 | === modified file 'hooks/keystone_utils.py' | |||
200 | --- hooks/keystone_utils.py 2016-02-18 10:02:59 +0000 | |||
201 | +++ hooks/keystone_utils.py 2016-02-19 14:51:35 +0000 | |||
202 | @@ -1871,4 +1871,5 @@ | |||
203 | 1871 | 1871 | ||
204 | 1872 | # set the status according to the current state of the contexts | 1872 | # set the status according to the current state of the contexts |
205 | 1873 | set_os_workload_status( | 1873 | set_os_workload_status( |
207 | 1874 | configs, REQUIRED_INTERFACES, charm_func=check_optional_relations) | 1874 | configs, REQUIRED_INTERFACES, charm_func=check_optional_relations, |
208 | 1875 | services=services(), ports=determine_ports()) | ||
209 | 1875 | 1876 | ||
210 | === modified file 'unit_tests/test_keystone_utils.py' | |||
211 | --- unit_tests/test_keystone_utils.py 2016-01-19 16:54:03 +0000 | |||
212 | +++ unit_tests/test_keystone_utils.py 2016-02-19 14:51:35 +0000 | |||
213 | @@ -758,4 +758,6 @@ | |||
214 | 758 | set_os_workload_status.assert_called_with( | 758 | set_os_workload_status.assert_called_with( |
215 | 759 | "TEST CONFIG", | 759 | "TEST CONFIG", |
216 | 760 | utils.REQUIRED_INTERFACES, | 760 | utils.REQUIRED_INTERFACES, |
218 | 761 | charm_func=utils.check_optional_relations) | 761 | charm_func=utils.check_optional_relations, |
219 | 762 | services=['haproxy', 'keystone', 'apache2'], | ||
220 | 763 | ports=[5000, 35357]) |
charm_lint_check #386 keystone-next for ajkavanagh mp285608
LINT OK: passed
Build: http:// 10.245. 162.36: 8080/job/ charm_lint_ check/386/