]> git.apps.os.sepia.ceph.com Git - teuthology.git/commitdiff
teuthology-suite: add Rocket.Chat notification 1585/head
authorKyr Shatskyy <kyrylo.shatskyy@suse.com>
Mon, 30 Nov 2020 20:37:05 +0000 (21:37 +0100)
committerKyr Shatskyy <kyrylo.shatskyy@suse.com>
Tue, 8 Dec 2020 15:27:50 +0000 (16:27 +0100)
Add Rocket.Chat notification for sleep before teardown.
For details see https://rocket.chat/

Signed-off-by: Kyr Shatskyy <kyrylo.shatskyy@suse.com>
scripts/suite.py
setup.py
teuthology/config.py
teuthology/run_tasks.py
teuthology/suite/run.py
teuthology/templates/rocketchat-sleep-before-teardown.jinja2 [new file with mode: 0644]

index 98f74481114d2ae08cfc9029efe2b3ddeb536f65..e826d57a3ec0b16d55af3de3db611f7a76a0bc19 100644 (file)
@@ -109,6 +109,9 @@ Scheduler arguments:
                               When tests finish or time out, send an email
                               here. May also be specified in ~/.teuthology.yaml
                               as 'results_email'
+  --rocketchat <rocketchat>   Comma separated list of Rocket.Chat channels where
+                              to send a message when tests finished or time out.
+                              To be used with --sleep-before-teardown option.
   -N <num>, --num <num>       Number of times to run/queue the job
                               [default: 1]
   -l <jobs>, --limit <jobs>   Queue at most this many jobs
index 7b08ee831383d1a7edb495d2bd0d55754c4546ab..e595da4a646751bf285d20eb0f00f7cbd6fd29b8 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -64,6 +64,7 @@ setup(
                       'configparser',
                       'ansible>=2.0',
                       'prettytable',
+                      'rocket-python >= 1.2.15',
                       'manhole',
                       'humanfriendly',
                       ],
index 1d5cee59b2e0c5fd2b0aed22707073afd9083719..18e26d2cc311d1448fa6a9d77ee046afce888b69 100644 (file)
@@ -185,6 +185,7 @@ class TeuthologyConfig(YamlConfig):
                 'size': 1,
             },
         },
+        'rocketchat': None,
         'sleep_before_teardown': 0,
     }
 
index 99e5a4abb72b003d83ed1c5455b6b46b9fba60ca..ab392261b433636bdccce9a8ad1b00ec31da5978 100644 (file)
@@ -4,6 +4,7 @@ import os
 import sys
 import time
 import types
+import yaml
 
 from copy import deepcopy
 from humanfriendly import format_timespan
@@ -203,6 +204,41 @@ def run_tasks(tasks, ctx):
             del exc_info
         timer.mark("tasks complete")
 
+
+def build_rocketchat_message(ctx, stack, sleep_time_sec, template_path=None):
+    message_template_path = template_path or os.path.dirname(__file__) + \
+            '/templates/rocketchat-sleep-before-teardown.jinja2'
+
+    with open(message_template_path) as f:
+        template_text = f.read()
+
+    template = jinja2.Template(template_text)
+    archive_path = ctx.config.get('archive_path')
+    job_id = ctx.config.get('job_id')
+    status = get_status(ctx.summary)
+    stack_path = ' -> '.join(task for task, _ in stack)
+    suite_name=ctx.config.get('suite')
+    sleep_date=time.time()
+    sleep_date_str=time.strftime('%Y-%m-%d %H:%M:%S',
+                                 time.gmtime(sleep_date))
+
+    message = template.render(
+        sleep_time=format_timespan(sleep_time_sec),
+        sleep_time_sec=sleep_time_sec,
+        sleep_date=sleep_date_str,
+        owner=ctx.owner,
+        run_name=ctx.name,
+        job_id=ctx.config.get('job_id'),
+        job_desc=ctx.config.get('description'),
+        job_info=get_results_url(ctx.name, job_id),
+        job_logs=get_http_log_path(archive_path, job_id),
+        suite_name=suite_name,
+        status=status,
+        task_stack=stack_path,
+    )
+    return message
+
+
 def build_email_body(ctx, stack, sleep_time_sec):
     email_template_path = os.path.dirname(__file__) + \
             '/templates/email-sleep-before-teardown.jinja2'
@@ -239,7 +275,57 @@ def build_email_body(ctx, stack, sleep_time_sec):
     )
     return (subject.strip(), body.strip())
 
+
+def rocketchat_send_message(ctx, message, channels):
+    """
+    Send the message to the given RocketChat channels
+
+    Before sending the message we read the config file
+    from `~/.config/rocketchat.api/settings.yaml` which
+    must include next records:
+
+        username: 'userloginname'
+        password: 'userbigsecret'
+        domain: 'https://chat.suse.de'
+
+    :param message:     plain text message content in the Rocket.Chat
+                        messaging format
+    :param channels:    a list of channels where to send the message,
+                        the user private channel should be prefixed
+                        with '@' symbol
+    """
+    try:
+        from rocketchat.api import RocketChatAPI
+    except Exception as e:
+        log.warning(f'rocketchat: Failed to import rocketchat.api: {e}')
+        return
+
+    settings_path = \
+        os.environ.get('HOME') + '/.config/rocketchat.api/settings.yaml'
+
+    try:
+        with open(settings_path) as f:
+            settings = yaml.safe_load(f)
+    except Exception as e:
+        log.warning(f'rocketchat: Failed to load settings from {settings_path}: {e}')
+
+    r = RocketChatAPI(settings=settings)
+    for channel in channels:
+        try:
+            r.send_message(message, channel)
+        except Exception as e:
+            log.warning(f'rocketchat: Failed to send message to "{channel}" channel: {e}')
+
+
 def notify_sleep_before_teardown(ctx, stack, sleep_time):
+    rocketchat = ctx.config.get('rocketchat', None)
+
+    if rocketchat:
+        channels = [_ for _ in [_.strip() for _ in rocketchat.split(',')] if _]
+        log.info("Sending a message to Rocket.Chat channels: %s", channels)
+        message = build_rocketchat_message(ctx, stack, sleep_time)
+        rocketchat_send_message(ctx, message, channels)
+
     email = ctx.config.get('email', None)
     if not email:
         # we have no email configured, return silently
index b84a6312b05ea8a41e4aa95ee47f4a3a3abbb981..3b64185ee9b3c29150a50932990446daac6371c1 100644 (file)
@@ -323,6 +323,8 @@ class Run(object):
             job_config.owner = self.args.owner
         if self.args.sleep_before_teardown:
             job_config.sleep_before_teardown = int(self.args.sleep_before_teardown)
+        if self.args.rocketchat:
+            job_config.rocketchat = self.args.rocketchat
         return job_config
 
     def build_base_args(self):
diff --git a/teuthology/templates/rocketchat-sleep-before-teardown.jinja2 b/teuthology/templates/rocketchat-sleep-before-teardown.jinja2
new file mode 100644 (file)
index 0000000..4109ec5
--- /dev/null
@@ -0,0 +1,6 @@
+The teuthology job [{{ job_id }}]({{ job_info }}) for suite *{{ suite_name }}* owned by '{{ owner }}' has fallen asleep with status '{{ status }}' at {{ sleep_date }} for __{{ sleep_time }}__ ({{ sleep_time_sec }} seconds).
+Open [teuthology.log]({{ job_logs }}teuthology.log) for details, or go to [all logs]({{ job_logs}}).
+
+Job Description: {{ job_desc }}
+Run Name: {{ run_name }}
+Task Stack: {{ task_stack }}