orchestrator: Support getting kerberos ticket

If the configuration sets keytab path and principal, run kinit with
custom cache file, and delete the file at the end of the run.

JIRA: COMPOSE-3288
Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
This commit is contained in:
Lubomír Sedlář 2019-03-06 10:12:43 +01:00
parent b80efbfd97
commit 86fb93d603
3 changed files with 60 additions and 1 deletions

View File

@ -39,6 +39,14 @@ General settings
If specified, a current event will be retrieved from the Koji instance and If specified, a current event will be retrieved from the Koji instance and
used for all parts. used for all parts.
**kerberos**
If set to yes, a kerberos ticket will be automatically created at the start.
Set keytab and principal as well.
**kerberos_keytab**
Path to keytab file used to create the kerberos ticket.
**kerberos_principal**
Kerberos principal for the ticket
Partial compose settings Partial compose settings
------------------------ ------------------------

View File

@ -3,6 +3,7 @@
from __future__ import print_function from __future__ import print_function
import argparse import argparse
import atexit
import errno import errno
import json import json
import logging import logging
@ -11,11 +12,13 @@ import re
import shutil import shutil
import subprocess import subprocess
import sys import sys
import tempfile
from collections import namedtuple from collections import namedtuple
import kobo.conf import kobo.conf
import kobo.log import kobo.log
import productmd import productmd
from kobo import shortcuts
from six.moves import configparser, shlex_quote from six.moves import configparser, shlex_quote
from pungi.compose import get_compose_dir from pungi.compose import get_compose_dir
@ -465,14 +468,33 @@ def setup_for_restart(global_config, parts, to_restart):
raise RuntimeError("All restarted parts are blocked. Nothing to do.") raise RuntimeError("All restarted parts are blocked. Nothing to do.")
def run_kinit(config):
if not config.getboolean("general", "kerberos"):
return
keytab = config.get("general", "kerberos_keytab")
principal = config.get("general", "kerberos_principal")
fd, fname = tempfile.mkstemp(prefix="krb5cc_pungi-orchestrate_")
os.close(fd)
os.environ["KRB5CCNAME"] = fname
shortcuts.run(["kinit", "-k", "-t", keytab, principal])
log.debug("Created a kerberos ticket for %s", principal)
atexit.register(os.remove, fname)
def run(work_dir, main_config_file, args): def run(work_dir, main_config_file, args):
config_dir = os.path.join(work_dir, "config") config_dir = os.path.join(work_dir, "config")
shutil.copytree(os.path.dirname(main_config_file), config_dir) shutil.copytree(os.path.dirname(main_config_file), config_dir)
# Read main config # Read main config
parser = configparser.RawConfigParser() parser = configparser.RawConfigParser(defaults={"kerberos": "false"})
parser.read(main_config_file) parser.read(main_config_file)
# Create kerberos ticket
run_kinit(parser)
compose_info = dict(parser.items("general")) compose_info = dict(parser.items("general"))
compose_type = parser.get("general", "compose_type") compose_type = parser.get("general", "compose_type")

View File

@ -804,3 +804,32 @@ class TestSetupForRestart(BaseTestCase):
self.assertEqual(parts["p1"].path, "/p1") self.assertEqual(parts["p1"].path, "/p1")
self.assertEqual(parts["p2"].status, "WAITING") self.assertEqual(parts["p2"].status, "WAITING")
self.assertEqual(parts["p2"].path, None) self.assertEqual(parts["p2"].path, None)
@mock.patch("atexit.register")
@mock.patch("kobo.shortcuts.run")
class TestRunKinit(BaseTestCase):
def test_without_config(self, run, register):
conf = mock.Mock()
conf.getboolean.return_value = False
o.run_kinit(conf)
self.assertEqual(run.call_args_list, [])
self.assertEqual(register.call_args_list, [])
@mock.patch.dict("os.environ")
def test_with_config(self, run, register):
conf = mock.Mock()
conf.getboolean.return_value = True
conf.get.side_effect = lambda section, option: option
o.run_kinit(conf)
self.assertEqual(
run.call_args_list,
[mock.call(["kinit", "-k", "-t", "kerberos_keytab", "kerberos_principal"])],
)
self.assertEqual(
register.call_args_list, [mock.call(os.remove, os.environ["KRB5CCNAME"])]
)