Merge lp:~cprov/adt-continuous-deployer/better-monitor into lp:adt-continuous-deployer

Proposed by Celso Providelo
Status: Merged
Approved by: Celso Providelo
Approved revision: 48
Merged at revision: 43
Proposed branch: lp:~cprov/adt-continuous-deployer/better-monitor
Merge into: lp:adt-continuous-deployer
Diff against target: 643 lines (+312/-229)
6 files modified
ci_automation/nova.py (+92/-0)
ci_automation/tests/test_branch.py (+6/-6)
ci_automation/tests/test_nova.py (+90/-81)
ci_automation/utils.py (+30/-0)
list.py (+56/-0)
monitor.py (+38/-142)
To merge this branch: bzr merge lp:~cprov/adt-continuous-deployer/better-monitor
Reviewer Review Type Date Requested Status
Francis Ginther Approve
Para Siva (community) Approve
Evan (community) Needs Information
Paul Larson Approve
Review via email: mp+257315@code.launchpad.net

Commit message

Refactoring monitor.py and also adding support for basic auto-deployed service listing with list.py script.

Description of the change

Refactoring monitor.py and also adding support for basic service listing via list.py:

{{{
stg-ue-ci-engineering@wendigo:~/adt-continuous-deployer$ ./list.py
* mojo-ue-adt-cloud-service:
        11a8f85b: Thu Apr 16 22:05:46 2015 (4 units)
* mojo-ue-adt-cloud-worker:
        e240a00e: Thu Apr 23 18:50:44 2015 (7 units)
* mojo-ue-adt-image-mapper:
        c1ec6cc8: Wed Apr 15 19:20:48 2015 (4 units)
* mojo-ue-adt-result-checker:
        13d54727: Wed Apr 15 21:35:30 2015 (2 units)
* mojo-ue-core-image-publisher:
        324e91c7: Thu Apr 23 04:15:42 2015 (2 units)
* mojo-ue-core-image-tester:
        057b67aa: Thu Apr 23 19:20:44 2015 (2 units)
* mojo-ue-core-image-watcher:
        1aeb45ff: Thu Apr 23 02:10:52 2015 (2 units)
* mojo-ue-core-result-checker:
        428911cd: Tue Apr 14 15:40:40 2015 (2 units)
}}}

Removal of obsolete deployments still supported by `./monitor.py mojo-ue-adt-cloud-worker -m 0`.

Also fixing some broken and ignored tests from the shortening-identifier change (must double-check tarmac config).

To post a comment you must log in.
45. By Celso Providelo

Sorted service list

Revision history for this message
Paul Larson (pwlars) wrote :

Nice, this will be really useful

review: Approve
Revision history for this message
Evan (ev) wrote :

Does pretty-printing the deployments and purging old deployments really belong in the same program, especially as the algorithm to decide what old environments grows in complexity?

See inline comment.

review: Needs Information
Revision history for this message
Para Siva (psivaa) wrote :

An inline comment about a typo for logstash env variable.
Also tested the 'list' option to be working.

46. By Celso Providelo

Fixing typo.

Revision history for this message
Celso Providelo (cprov) wrote :

Psivaa, nice catch, typo fixed.

I still have to address Ev's comment/suggestion for preserving the old monitor.py behavior and creating a list.py script for the pretty-print task.

47. By Celso Providelo

Dedicated script for listing auto-deployed services (list.py), monitor.py preserves previous behaviour.

Revision history for this message
Celso Providelo (cprov) wrote :

Ev and others,

I've restored monitor.py behaviour (refactored on top of the common nova functions) and introduced list.py for listing auto-deployed services nicely.

Let me know what do you think.

Revision history for this message
Para Siva (psivaa) wrote :

LGTM now, approving.
A docstring for list.py would be a bonus.

review: Approve
48. By Celso Providelo

Docstring fixing.

Revision history for this message
Francis Ginther (fginther) wrote :

I like it

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'ci_automation/nova.py'
--- ci_automation/nova.py 1970-01-01 00:00:00 +0000
+++ ci_automation/nova.py 2015-04-27 18:16:41 +0000
@@ -0,0 +1,92 @@
1# Copyright (C) 2015 Canonical
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation, either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15#
16
17"""CI Automation: nova helpers."""
18
19import io
20import os
21import stat
22import subprocess
23
24
25def nova_list():
26 """Default 'nova list' accessor."""
27 args = [
28 'nova',
29 'list',
30 '--minimal',
31 ]
32
33 output = subprocess.check_output(
34 args, stderr=subprocess.DEVNULL).decode('utf-8').strip()
35
36 return output
37
38
39def get_services_map(base_dir, nova_output=None):
40 """Return a services map dictionary.
41
42 'base_dir' is the path where deployment identifier can be found.
43
44 If 'nova_output' is not provided `nova_list` accessor is used to get
45 this information.
46
47 Returns a dictionary key-ed by service name (middle term of the mojo
48 stage used in the deployment, e.g. 'mojo-ue-core-image-watcher'):
49
50 {
51 'mojo-ue-core-image-watcher': {
52 'DEADBEEF': {
53 'path': <identifier_path>,
54 'epoch': <identifier_ST_MTIME>,
55 'units': [<unit_name>, <unit_name>, ...],
56 },
57 'ABCD1234': {
58 'path': <identifier_path>,
59 'epoch': <identifier_ST_MTIME>,
60 'units': [<unit_name>, <unit_name>, ...],
61 },
62 },
63 }
64
65 Manually deployed environments, i.e. no identifiers on disk, are ignored.
66 """
67 if nova_output is None:
68 nova_output = nova_list()
69
70 services = {}
71
72 for line in io.StringIO(nova_output).readlines()[3:-1]:
73 unit_name = line.split('|')[2].strip()
74 service_name = '-'.join(unit_name.split('-')[1:-3])
75 identifier = unit_name.split('-')[-3]
76
77 path = os.path.join(base_dir, identifier)
78 if not os.path.exists(path):
79 continue
80
81 service = services.setdefault(service_name, {})
82 deployment = service.setdefault(identifier, {})
83 units = deployment.setdefault('units', [])
84 units.append(unit_name)
85
86 if deployment.get('path') is None:
87 deployment.update({
88 'path': path,
89 'epoch': os.stat(path)[stat.ST_MTIME],
90 })
91
92 return services
093
=== modified file 'ci_automation/tests/test_branch.py'
--- ci_automation/tests/test_branch.py 2015-04-02 19:29:27 +0000
+++ ci_automation/tests/test_branch.py 2015-04-27 18:16:41 +0000
@@ -99,13 +99,13 @@
99 self.assertEqual(99 self.assertEqual(
100 ('\n'.join(['bob/devel\t1',100 ('\n'.join(['bob/devel\t1',
101 'lp:foo;revno=1\t1']),101 'lp:foo;revno=1\t1']),
102 '90945bed4b6e27d500ae1ae05c7bba1c'),102 '7ebe5386'),
103 get_identifier(self.branch, stage))103 get_identifier(self.branch, stage))
104 self.branch_add_stage('the-builder/devel')104 self.branch_add_stage('the-builder/devel')
105 self.assertEqual(105 self.assertEqual(
106 ('\n'.join(['bob/devel\t1',106 ('\n'.join(['bob/devel\t1',
107 'lp:foo;revno=1\t1']),107 'lp:foo;revno=1\t1']),
108 '90945bed4b6e27d500ae1ae05c7bba1c'),108 '7ebe5386'),
109 get_identifier(self.branch, stage))109 get_identifier(self.branch, stage))
110110
111 def test_get_identifier_spec_changes(self):111 def test_get_identifier_spec_changes(self):
@@ -115,7 +115,7 @@
115 self.assertEqual(115 self.assertEqual(
116 ('\n'.join(['bob/devel\t1',116 ('\n'.join(['bob/devel\t1',
117 'lp:foo;revno=1\t1']),117 'lp:foo;revno=1\t1']),
118 '90945bed4b6e27d500ae1ae05c7bba1c'),118 '7ebe5386'),
119 get_identifier(self.branch, stage))119 get_identifier(self.branch, stage))
120 repo_path = os.path.join(self.branch, stage, 'repo')120 repo_path = os.path.join(self.branch, stage, 'repo')
121 with open(repo_path, 'w'):121 with open(repo_path, 'w'):
@@ -125,7 +125,7 @@
125 self.assertEqual(125 self.assertEqual(
126 ('\n'.join(['bob/devel\t2',126 ('\n'.join(['bob/devel\t2',
127 'lp:foo;revno=1\t1']),127 'lp:foo;revno=1\t1']),
128 'dce1f2c4a1a1634f49a4572fa8630765'),128 'fd2e0853'),
129 get_identifier(self.branch, stage))129 get_identifier(self.branch, stage))
130130
131 def test_get_identifier_collect_changes(self):131 def test_get_identifier_collect_changes(self):
@@ -136,7 +136,7 @@
136 self.assertEqual(136 self.assertEqual(
137 ('\n'.join(['bob/devel\t2',137 ('\n'.join(['bob/devel\t2',
138 'lp:foo;revno=7\t7']),138 'lp:foo;revno=7\t7']),
139 'f4bdf7cb82d6f1a9fc725d1bf70eef75'),139 '77ff4c59'),
140 get_identifier(self.branch, stage))140 get_identifier(self.branch, stage))
141 self.branch_update_collect(141 self.branch_update_collect(
142 stage, '\n'.join(['foo lp:~cprov/foo;revno=7',142 stage, '\n'.join(['foo lp:~cprov/foo;revno=7',
@@ -145,7 +145,7 @@
145 ('\n'.join(['bob/devel\t3',145 ('\n'.join(['bob/devel\t3',
146 'lp:~cprov/foo;revno=7\t7',146 'lp:~cprov/foo;revno=7\t7',
147 'lp:bar;revno=5\t5']),147 'lp:bar;revno=5\t5']),
148 '261a6c824fa28680e7e0869194a12152'),148 '7a1b03fa'),
149 get_identifier(self.branch, stage))149 get_identifier(self.branch, stage))
150150
151151
152152
=== renamed file 'test_monitor.py' => 'ci_automation/tests/test_nova.py'
--- test_monitor.py 2015-04-08 17:59:46 +0000
+++ ci_automation/tests/test_nova.py 2015-04-27 18:16:41 +0000
@@ -1,93 +1,102 @@
1import logging1#!/usr/bin/env python3
2#
3# Copyright (C) 2015 Canonical
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17#
18
19"""CI Automation tests for nova helpers."""
20
2import os21import os
3import shutil22import shutil
23import sys
4import tempfile24import tempfile
5import time25import time
6import unittest26import unittest
727
8from monitor import (28
9 get_service_deployments,29HERE = os.path.abspath(os.path.dirname(__file__))
10 get_service_info,30sys.path.append(os.path.join(HERE, '../..'))
11 parse_nova_output,31
12)32from ci_automation.nova import get_services_map
1333
1434
15class TestServiceWatcher(unittest.TestCase):35class TestNova(unittest.TestCase):
36
37 identifiers = (
38 '12345',
39 'abcdef',
40 '56789',
41 )
42 service_names = (
43 'mojo-ue-core-result-watcher',
44 'mojo-ue-core-image-watcher',
45 'mojo-ue-core-image-publisher',
46 'mojo-ue-core-image-tester',
47 )
48
16 def setUp(self):49 def setUp(self):
17 self.prefix = 'juju-mojo-ue'
18 self.identifiers = [
19 '12345',
20 'abcdef',
21 '56789',
22 ]
23 self.service_names = [
24 'core-result-watcher',
25 'core-image-watcher',
26 'core-image-publisher',
27 'core-image-tester',
28 ]
29 self.base_dir = tempfile.mkdtemp()50 self.base_dir = tempfile.mkdtemp()
30 self.addCleanup(shutil.rmtree, self.base_dir)51 self.addCleanup(shutil.rmtree, self.base_dir)
31 self.unit_name_pattern = '{}-(.*)-(.*)-machine-\d+'.format(self.prefix)52
3253 def generate_identifiers(self):
33 # generate some fake 'nova list' output54 """Generate deployment identifiers on disk."""
55 for ident in self.identifiers:
56 # get unique timestamps
57 time.sleep(.1)
58 os.makedirs(os.path.join(self.base_dir, ident))
59
60 def create_output(self):
61 """Return some fake 'nova list' output."""
34 count = 062 count = 0
35 self.output = ""63 output = ""
36 for ident in self.identifiers:64 for ident in self.identifiers:
37 count += 165 count += 1
3866 for name in self.service_names:
39 for service_name in self.service_names:67 output += '| id-{} | juju-{}-{}-machine-0 |\n'.format(
40 self.output = '{}| id-{} | {}-{}-{}-machine-0 |\n'.format(68 count, name, ident)
41 self.output, count, self.prefix, service_name, ident)69 return output
4270
43 #self._create_tmp_files()71 def test_service_map_ignores_missing_identifiers(self):
4472 # Deployments with no identifiers on disk are ignored (they were
45 def _create_tmp_files(self):73 # probably deployed manually with mojo.py, not with cd.py via cron).
46 for ident in self.identifiers:74 service_map = get_services_map(
47 # get unique timestamps75 self.base_dir, nova_output=self.create_output())
48 time.sleep(2)76 self.assertEqual({}, service_map)
49 os.makedirs(os.path.join(self.base_dir, ident))77
5078 def test_service_map(self):
51 def test_parse_nova_output_valid(self):79 self.generate_identifiers()
5280 service_map = get_services_map(
53 units = parse_nova_output(self.output, self.service_names[0])81 self.base_dir, nova_output=self.create_output())
54 logging.warn("JOE: units: %s", units)82
5583 # service_map is key-ed by services names.
56 self.assertEqual(len(self.identifiers), len(units))84 self.assertEqual(
5785 sorted(self.service_names), sorted(service_map.keys()))
58 def test_get_service_info_valid(self):86
59 unit_name = '{}-{}-{}-machine-0'.format(87 # Each service points to a dictionary key-ed by the deployment
60 self.prefix,88 # identifier.
61 self.service_names[0],89 service_contents = service_map['mojo-ue-core-image-watcher']
62 self.identifiers[0],90 self.assertEqual(
63 )91 ['56789', 'abcdef'], sorted(service_contents.keys()))
6492
65 service_name, identifier = get_service_info(unit_name,93 # Each deployment contains 'path' (identifier file on disk), 'epoch'
66 self.unit_name_pattern)94 # (identifier file mtime) and 'units' (list of full unit names,
6795 # including the bootstrap node).
68 self.assertEqual(self.service_names[0], service_name)96 deployment_contents = service_contents['abcdef']
69 self.assertEqual(self.identifiers[0], identifier)97 self.assertEqual(
7098 ['epoch', 'path', 'units'], sorted(deployment_contents.keys()))
71 def test_get_service_info_invalid(self):99
72 unit_name = '{}-{}-{}-machine-0'.format(100
73 self.prefix,101if __name__ == '__main__':
74 self.service_names[0],102 unittest.main()
75 self.identifiers[0],
76 )
77
78 service_name, identifier = get_service_info("junk-%s" % unit_name,
79 '')
80
81 self.assertEqual(None, service_name)
82 self.assertEqual(None, identifier)
83
84 def test_get_service_deployments(self):
85 service_deployments = get_service_deployments(self.service_names[0],
86 self.output,
87 self.unit_name_pattern)
88
89 self.assertEqual(1, len(service_deployments))
90 for key in service_deployments:
91 self.assertEqual(len(self.identifiers),
92 len(service_deployments[key]),
93 "mismatch for '{}'".format(key))
94103
=== modified file 'ci_automation/utils.py'
--- ci_automation/utils.py 2015-04-02 19:29:27 +0000
+++ ci_automation/utils.py 2015-04-27 18:16:41 +0000
@@ -16,6 +16,8 @@
1616
17"""CI Automation: miscelaneous utilities."""17"""CI Automation: miscelaneous utilities."""
1818
19import logging
20import os
19import subprocess21import subprocess
20import textwrap22import textwrap
2123
@@ -61,3 +63,31 @@
61 {}"""63 {}"""
62 ''').format(stdout.decode(), stderr.decode())64 ''').format(stdout.decode(), stderr.decode())
63 )65 )
66
67
68def setup_logger():
69 """Return a configured logger instance.
70
71 Defaults to INFO level and if 'CI_LOGSTASH_HOST' environment variable
72 is set and python-logstash is reachable, adds a corresponding 'logstash'
73 handler.
74 """
75 logging.basicConfig(
76 format='%(asctime)s %(name)s %(levelname)s: %(message)s')
77 logger = logging.getLogger()
78 logger.setLevel(logging.INFO)
79
80 # Optional remote logging via logstash.
81 logstash_host = os.environ.get('CI_LOGSTASH_HOST')
82 if logstash_host is not None:
83 try:
84 import logstash
85 except ImportError:
86 print('Follow the README instructions for installing '
87 'python-logstash')
88 return 1
89 else:
90 logger.addHandler(
91 logstash.LogstashHandler(logstash_host, 5959, 1))
92
93 return logger
6494
=== added file 'list.py'
--- list.py 1970-01-01 00:00:00 +0000
+++ list.py 2015-04-27 18:16:41 +0000
@@ -0,0 +1,56 @@
1#!/usr/bin/env python3
2#
3# Copyright (C) 2015 Canonical
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17#
18"""CI Automation: script for listing auto-deployed services."""
19
20import argparse
21import datetime
22import os
23import sys
24
25
26from ci_automation.nova import get_services_map
27from ci_automation.utils import setup_logger
28
29
30def main():
31 parser = argparse.ArgumentParser(
32 description="Check the number of deployments for a service")
33 parser.add_argument('--base-dir', '-b',
34 default=os.path.expanduser("~/ci-cd-identifiers"),
35 help="The directory where identifiers are stored "
36 " (eg. ~/ci-cd-identifiers)")
37 args = parser.parse_args()
38 logger = setup_logger()
39
40 services = get_services_map(args.base_dir)
41 sorted_services = sorted(services.items(), key=lambda s: s[0])
42 for srv, deployments in sorted_services:
43 print('* {}:'.format(srv))
44 sorted_deployments = sorted(
45 deployments.items(), key=lambda d: d[1]['epoch'], reverse=True)
46 for ident, contents in sorted_deployments:
47 date_created = datetime.datetime.utcfromtimestamp(
48 contents['epoch']).ctime()
49 print('\t{}: {} ({} units)'.format(
50 ident, date_created, len(contents['units'])))
51
52 return 0
53
54
55if __name__ == "__main__":
56 sys.exit(main())
057
=== modified file 'monitor.py'
--- monitor.py 2015-04-10 20:20:17 +0000
+++ monitor.py 2015-04-27 18:16:41 +0000
@@ -15,155 +15,51 @@
15# You should have received a copy of the GNU General Public License15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17#17#
18"""CI Automation: monitoring (purging obsolete deployments) services."""
1819
19import argparse20import argparse
20import subprocess
21import io
22import logging
23import operator
24import os21import os
25import re
26import sys22import sys
2723
28from stat import ST_MTIME24
2925from ci_automation.nova import get_services_map
3026from ci_automation.utils import setup_logger
31def parse_args():27
32 desc = "Check the number of deployments for a service"28
33 parser = argparse.ArgumentParser(description=desc)29def main():
34 parser.add_argument('--base-dir', '-b',30 parser = argparse.ArgumentParser(
35 default=os.path.expanduser("~/ci-cd-identifiers"),31 description="Check the number of deployments for a service")
36 help="The directory where identifiers are stored "32 parser.add_argument(
37 " (eg. ~/ci-cd-identifiers)")33 '--base-dir', '-b',
38 parser.add_argument('--max-deployments', '-m', type=int, default=2,34 default=os.path.expanduser("~/ci-cd-identifiers"),
39 help="The maximum number of deployments to keep.")35 help="The directory where identifiers are stored "
40 parser.add_argument('stage_dirname',36 " (eg. ~/ci-cd-identifiers)")
41 help="the mojo stage directory name (eg. "37 parser.add_argument(
42 "mojo-ue-core-image-tester")38 '--max-deployments', '-m', type=int, default=2,
39 help="The maximum number of deployments to keep.")
40 parser.add_argument(
41 'stage_dirname',
42 help="the mojo stage directory name (eg. mojo-ue-core-image-tester")
4343
44 args = parser.parse_args()44 args = parser.parse_args()
4545 logger = setup_logger()
46 return args46
4747 deployments = get_services_map(args.base_dir).get(args.stage_dirname)
4848 if deployments is None:
49def get_service_info(unit_name, unit_name_pattern):49 print('No deployments found!')
5050 return
51 unit_name_regex = re.compile(unit_name_pattern)51
52 match = unit_name_regex.match(unit_name)52 sorted_deployments = sorted(
53 stage_dirname = None53 deployments.items(), key=lambda d: d[1]['epoch'], reverse=True)
54 identifier = None54 for identifier, _ in sorted_deployments[args.max_deployments:]:
5555 extra = {
56 if match and len(match.groups()) == 2:56 "service": "ci/cd",
57 stage_dirname = match.group(1)57 "deployment_status": "DESTROYED",
58 identifier = match.group(2)58 "deployment_name": args.stage_dirname,
5959 "deployment_identifier": identifier,
60 return (stage_dirname, identifier)60 }
6161 logger.info(
6262 "Destroying deployment %s", identifier, extra=extra)
63def nova_list():
64 args = [
65 'nova',
66 'list',
67 '--minimal',
68 ]
69
70 output = subprocess.check_output(
71 args, stderr=subprocess.DEVNULL).decode('utf-8').strip()
72
73 return output
74
75
76def parse_nova_output(output, stage_dirname):
77 units = []
78 buf = io.StringIO(output)
79 for line in buf.readlines():
80 # skip everything but the instance entries
81 if stage_dirname not in line:
82 continue
83 data = line.split('|')
84 instance_id = data[1].strip()
85 unit_name = data[2].strip()
86 units.append({'id': instance_id, 'name': unit_name})
87
88 return units
89
90
91def check_deployments(service_deployments, max_deployments, base_dir, logger):
92 """
93 :param service_deployments: dictionary of the form:
94 {'stage_dirname': ['identifier_1', 'identifier_2', ...]}
95 """
96 for key in service_deployments:
97 if len(service_deployments[key]) > max_deployments:
98 data = []
99 for identifier in service_deployments[key]:
100 path = os.path.join(base_dir, identifier)
101 # Manually deployed environments (i.e. no identifiers
102 # recorded on disk) are ignored and left alone.
103 if not os.path.exists(path):
104 continue
105 data.append((identifier, os.stat(path)[ST_MTIME], path))
106 data = sorted(data, key=operator.itemgetter(1), reverse=True)
107 for identifier, _, _ in data[max_deployments:]:
108 extra = {
109 "service": "ci/cd",
110 "deployment_status": "DESTROYED",
111 "deployment_name": key,
112 "deployment_identifier": identifier,
113 }
114 logger.info(
115 "Destroying deployment %s", identifier, extra=extra)
116
117
118def get_service_deployments(stage_dirname, output, unit_name_pattern):
119 service_deployments = {stage_dirname: []}
120
121 units = parse_nova_output(output, stage_dirname)
122
123 for unit in units:
124 service_name, identifier = get_service_info(unit['name'],
125 unit_name_pattern)
126 # skip unparsable unit names
127 if service_name is None or identifier is None:
128 continue
129
130 service_deployments[stage_dirname].append(identifier)
131
132 return service_deployments
133
134
135def main():
136 args = parse_args()
137
138 base_dir = args.base_dir
139 max_deployments = args.max_deployments
140 stage_dirname = args.stage_dirname
141
142 unit_name_pattern = 'juju-({})-(.*)-machine-\d+'.format(stage_dirname)
143
144 logging.basicConfig(
145 format='%(asctime)s %(name)s %(levelname)s: %(message)s')
146 logger = logging.getLogger()
147 logger.setLevel(logging.INFO)
148
149 # Optional remote logging via logstash.
150 logstash_host = os.environ.get('CI_LOGSTASH_HOST')
151 if logstash_host is not None:
152 try:
153 import logstash
154 except ImportError:
155 print('Follow the README instructions for installing '
156 'python-logstash')
157 return 1
158 else:
159 logger.addHandler(
160 logstash.LogstashHandler(logstash_host, 5959, 1))
161
162 output = nova_list()
163 service_deployments = get_service_deployments(
164 stage_dirname, output, unit_name_pattern)
165 check_deployments(
166 service_deployments, max_deployments, base_dir, logger)
16763
168 return 064 return 0
16965

Subscribers

People subscribed via source and target branches

to all changes: