From 1c9f97b602bfc15cedfe0261328bb371c648dc1b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver <thomas.kluyver@xfel.eu> Date: Wed, 12 Jun 2024 15:26:16 +0100 Subject: [PATCH] Use MUNGE credential with update_conf requests --- setup.py | 1 + webservice/update_config.py | 10 ++++++++++ webservice/webservice.py | 28 +++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 01ef0a0f2..518138927 100644 --- a/setup.py +++ b/setup.py @@ -90,6 +90,7 @@ install_requires = [ "pasha==0.1.1", "prettytable==0.7.2", "princess==0.5", + "pymunge==0.1.3", "pypandoc==1.4", "python-dateutil==2.8.2", "pyyaml==5.3", diff --git a/webservice/update_config.py b/webservice/update_config.py index 53e002ce1..8933956c7 100755 --- a/webservice/update_config.py +++ b/webservice/update_config.py @@ -4,6 +4,7 @@ from pathlib import Path import argparse import json +import subprocess import sys import yaml @@ -263,6 +264,14 @@ def _create_new_config_from_args_input( return new_conf +def munge(): + """Make a MUNGE credential to send""" + res = subprocess.run(['munge', '-n'], stdout=subprocess.PIPE, text=True) + if res.returncode == 0: + return res.stdout + return None # Something went wrong - for now, this is ignored + + def main(): # remove help calls, to avoid exiting the argument parser. argv = sys.argv[1:] @@ -332,6 +341,7 @@ def main(): args["proposal"], json.dumps(new_conf), str(args["apply"]), + munge(), ]) socket.send(f"['{msg}']".encode()) resp = socket.recv_multipart()[0] diff --git a/webservice/webservice.py b/webservice/webservice.py index 61be728e0..63d577f35 100644 --- a/webservice/webservice.py +++ b/webservice/webservice.py @@ -9,6 +9,7 @@ import json import locale import logging import os +import pwd import re import shlex import sqlite3 @@ -21,7 +22,9 @@ from getpass import getuser from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Union +import git import requests +import pymunge import yaml import zmq import zmq.asyncio @@ -194,7 +197,7 @@ def merge(source: Dict, destination: Dict) -> Dict: def change_config(config, updated_config, instrument, - cycle, proposal, apply=False) -> bytes: + cycle, proposal, apply=False, munge_cred=None) -> bytes: """ Change the configuration of a proposal If no proposal specific configuration yet exists, one is first created @@ -243,6 +246,22 @@ def change_config(config, updated_config, instrument, existing_conf = yaml.safe_load(rf) new_conf = merge(updated_config, existing_conf) + author = None + if munge_cred is not None: + try: + uid = pymunge.decode(munge_cred.encode())[1] + user_details = pwd.getpwuid(uid) + logging.debug("MUNGE credential from user %s", user_details.pw_name) + full_name = user_details.pw_gecos.split(',')[0] + email = full_name.lower().replace(' ', '.') + '@xfel.eu' # Hopefully + author = git.Actor(full_name, email) + except Exception: + logging.warning( + "Failed to recognise author from MUNGE credential", exc_info=True + ) + else: + logging.info("update_conf request without MUNGE credential") + if apply: # Apply updated configuration to the proposal.yaml # and push it to the calibration_configurations remote reporsitory. @@ -250,7 +269,9 @@ def change_config(config, updated_config, instrument, wf.write(yaml.safe_dump(new_conf, default_flow_style=False)) repo.index.add([str(fpath)]) repo.index.commit( - f"Update to proposal YAML: {datetime.now().isoformat()}") + f"Update to proposal {proposal} YAML: {datetime.now().isoformat()}", + author=author, + ) repo.remote().push() logging.info(Success.UPLOADED_CONFIG.format(cycle, proposal)) return yaml.safe_dump(new_conf, default_flow_style=False).encode() @@ -1453,7 +1474,7 @@ class ActionsServer: async def handle_update_conf( self, sase, karabo_id, instrument, cycle, proposal, config_yaml, - apply + apply, munge_cred=None, ): updated_config = None try: @@ -1465,6 +1486,7 @@ class ActionsServer: cycle, proposal, apply.upper() == "TRUE", + munge_cred, ) except Exception as e: err_msg = (f"Failure applying config for {proposal}:" -- GitLab