Blame utils/ansible-ipa-client-install

Packit Service 0e3ff7
#!/usr/libexec/platform-python
Packit Service 0a38ef
# -*- coding: utf-8 -*-
Packit Service 0a38ef
Packit Service 0a38ef
# Authors:
Packit Service 0a38ef
#   Thomas Woerner <twoerner@redhat.com>
Packit Service 0a38ef
#
Packit Service 0a38ef
# Copyright (C) 2019  Red Hat
Packit Service 0a38ef
# see file 'COPYING' for use and warranty information
Packit Service 0a38ef
#
Packit Service 0a38ef
# This program is free software; you can redistribute it and/or modify
Packit Service 0a38ef
# it under the terms of the GNU General Public License as published by
Packit Service 0a38ef
# the Free Software Foundation, either version 3 of the License, or
Packit Service 0a38ef
# (at your option) any later version.
Packit Service 0a38ef
#
Packit Service 0a38ef
# This program is distributed in the hope that it will be useful,
Packit Service 0a38ef
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0a38ef
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 0a38ef
# GNU General Public License for more details.
Packit Service 0a38ef
#
Packit Service 0a38ef
# You should have received a copy of the GNU General Public License
Packit Service 0a38ef
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 0a38ef
Packit Service 0a38ef
import os
Packit Service 0a38ef
import sys
Packit Service 0a38ef
import shutil
Packit Service 0a38ef
import tempfile
Packit Service 0a38ef
import argparse
Packit Service 0a38ef
import traceback
Packit Service 0a38ef
import subprocess
Packit Service 0a38ef
Packit Service 0a38ef
Packit Service 0a38ef
def parse_options():
Packit Service 0a38ef
    usage = "Usage: ansible-ipa-client-install [options] <ansible host>"
Packit Service 0a38ef
Packit Service 0a38ef
    parser = argparse.ArgumentParser(usage=usage)
Packit Service 0a38ef
    parser.add_argument("--version", dest="version",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="show program's version number and exit")
Packit Service 0a38ef
    parser.add_argument("-U", "--unattended", dest="unattended",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="unattended (un)installation never prompts the "
Packit Service 0a38ef
                        "user")
Packit Service 0a38ef
    parser.add_argument("--uninstall", dest="uninstall",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="uninstall an existing installation. The "
Packit Service 0a38ef
                        "uninstall can be run with --unattended option")
Packit Service 0a38ef
    # basic
Packit Service 0a38ef
    parser.add_argument("-p", "--principal", dest="principal",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="principal to use to join the IPA realm")
Packit Service 0a38ef
    parser.add_argument("--ca-cert-file", dest="ca_cert_file",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="load the CA certificate from this file")
Packit Service 0a38ef
    parser.add_argument("--ip-address", dest="ip_addresses",
Packit Service 0a38ef
                        metavar="IP_ADDRESS",
Packit Service 0a38ef
                        action='append', default=None,
Packit Service 0a38ef
                        help="Specify IP address that should be added to DNS. "
Packit Service 0a38ef
                        "This option can be used multiple times")
Packit Service 0a38ef
    parser.add_argument("--all-ip-addresses", dest="all_ip_addresses",
Packit Service 0a38ef
                        action='store_true',
Packit Service 0a38ef
                        help="All routable IP addresses configured on any "
Packit Service 0a38ef
                        "interface will be added to DNS")
Packit Service 0a38ef
    parser.add_argument("--domain", dest="domain",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="primary DNS domain of the IPA deployment (not "
Packit Service 0a38ef
                        "necessarily related to the current hostname)")
Packit Service 0a38ef
    parser.add_argument("--server", dest="servers",
Packit Service 0a38ef
                        metavar="SERVER",
Packit Service 0a38ef
                        action='append', default=None,
Packit Service 0a38ef
                        help="FQDN of IPA server")
Packit Service 0a38ef
    parser.add_argument("--realm", dest="realm",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="Kerberos realm name of the IPA deployment "
Packit Service 0a38ef
                        "(typically an upper-cased name of the primary DNS "
Packit Service 0a38ef
                        "domain)")
Packit Service 0a38ef
    parser.add_argument("--hostname", dest="hostname",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="The hostname of this machine (FQDN). If "
Packit Service 0a38ef
                        "specified, the hostname will be set and the system "
Packit Service 0a38ef
                        "configuration will be updated to persist over "
Packit Service 0a38ef
                        "reboot. By default the result of getfqdn() call "
Packit Service 0a38ef
                        "from Python's socket module is used.")
Packit Service 0a38ef
    # client
Packit Service 0a38ef
    parser.add_argument("-w", "--password", dest="password",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="password to join the IPA realm (assumes bulk "
Packit Service 0a38ef
                        "password unless principal is also set)")
Packit Service 0a38ef
    parser.add_argument("-W", dest="password_prompt",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="Prompt for a password to join the IPA realm")
Packit Service 0a38ef
    parser.add_argument("-f", "--force", dest="force",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="force setting of LDAP/Kerberos conf")
Packit Service 0a38ef
    parser.add_argument("--configure-firefox", dest="configure_firefox",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="configure Firefox to use IPA domain credentials")
Packit Service 0a38ef
    parser.add_argument("--firefox-dir", dest="firefox_dir",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="specify directory where Firefox is installed "
Packit Service 0a38ef
                        "(for example: '/usr/lib/firefox')")
Packit Service 0a38ef
    parser.add_argument("-k", "--keytab", dest="keytab",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="path to backed up keytab from previous "
Packit Service 0a38ef
                        "enrollment")
Packit Service 0a38ef
    parser.add_argument("--mkhomedir", dest="mkhomedir",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="create home directories for users on their "
Packit Service 0a38ef
                        "first login")
Packit Service 0a38ef
    parser.add_argument("--force-join", dest="force_join",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="Force client enrollment even if already "
Packit Service 0a38ef
                        "enrolled")
Packit Service 0a38ef
    parser.add_argument("--ntp-server", dest="ntp_servers",
Packit Service 0a38ef
                        metavar="NTP_SERVER",
Packit Service 0a38ef
                        action='append', default=None,
Packit Service 0a38ef
                        help="ntp server to use. This option can be used "
Packit Service 0a38ef
                        "multiple times")
Packit Service 0a38ef
    parser.add_argument("--ntp-pool", dest="ntp_pool",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="ntp server pool to use")
Packit Service 0a38ef
    parser.add_argument("-N", "--no-ntp", dest="no_ntp",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="do not configure ntp")
Packit Service 0a38ef
    parser.add_argument("--nisdomain", dest="nisdomain",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="NIS domain name")
Packit Service 0a38ef
    parser.add_argument("--no-nisdomain", dest="no_nisdomain",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="do not configure NIS domain name")
Packit Service 0a38ef
    parser.add_argument("--ssh-trust-dns", dest="ssh_trust_dns",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="configure OpenSSH client to trust DNS SSHFP "
Packit Service 0a38ef
                        "records")
Packit Service 0a38ef
    parser.add_argument("--no-ssh", dest="no_ssh",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="do not configure OpenSSH client")
Packit Service 0a38ef
    parser.add_argument("--no-sshd", dest="no_sshd",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="do not configure OpenSSH server")
Packit Service 0a38ef
    parser.add_argument("--no-sudo", dest="no_sudo",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="do not configure SSSD as data source for sudo")
Packit Service 0a38ef
    parser.add_argument("--no-dns-sshfp", dest="no_dns_sshfp",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="do not automatically create DNS SSHFP records")
Packit Service 0a38ef
    parser.add_argument("--kinit-attempts", dest="kinit_attempts",
Packit Service 0a38ef
                        type=int, default=None,
Packit Service 0a38ef
                        help="number of attempts to obtain host TGT (defaults "
Packit Service 0a38ef
                        "to 5)")
Packit Service 0a38ef
    # sssd
Packit Service 0a38ef
    parser.add_argument("--fixed-primary", dest="fixed_primary",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="Configure sssd to use fixed server as primary "
Packit Service 0a38ef
                        "IPA server")
Packit Service 0a38ef
    parser.add_argument("--permit", dest="permit",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="disable access rules by default, permit all "
Packit Service 0a38ef
                        "access")
Packit Service 0a38ef
    parser.add_argument("--enable-dns-updates", dest="enable_dns_updates",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="Configures the machine to attempt dns updates "
Packit Service 0a38ef
                        "when the ip address changes")
Packit Service 0a38ef
    parser.add_argument("--no-krb5-offline-passwords",
Packit Service 0a38ef
                        dest="no_krb5_offline_passwords",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="Configure SSSD not to store user password when "
Packit Service 0a38ef
                        "the server is offline")
Packit Service 0a38ef
    parser.add_argument("--preserve-sssd", dest="preserve_sssd",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="Preserve old SSSD configuration if possible")
Packit Service 0a38ef
Packit Service 0a38ef
    # automount
Packit Service 0a38ef
    parser.add_argument("--automount-location", dest="automount_location",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="Automount location")
Packit Service 0a38ef
    # logging and output
Packit Service 0a38ef
    parser.add_argument("-v", "--verbose", dest="verbose",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="print debugging information")
Packit Service 0a38ef
    parser.add_argument("-d", "--debug", dest="verbose",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="alias for --verbose (deprecated)")
Packit Service 0a38ef
    parser.add_argument("-q", "--quiet", dest="quiet",
Packit Service 0a38ef
                        action="store_true",
Packit Service 0a38ef
                        help="output only errors")
Packit Service 0a38ef
    parser.add_argument("--log-file", dest="log_file",
Packit Service 0a38ef
                        help="log to the given file")
Packit Service 0a38ef
    # ansible
Packit Service 0a38ef
    parser.add_argument("--ipaclient-use-otp", dest="ipaclient_use_otp",
Packit Service 0a38ef
                        choices=("yes", "no"), default=None,
Packit Service 0a38ef
                        help="The bool value defines if a one-time password "
Packit Service 0a38ef
                        "will be generated to join a new or existing host. "
Packit Service 0a38ef
                        "Default: no")
Packit Service 0a38ef
    parser.add_argument("--ipaclient-allow-repair",
Packit Service 0a38ef
                        dest="ipaclient_allow_repair",
Packit Service 0a38ef
                        choices=("yes", "no"), default=None,
Packit Service 0a38ef
                        help="The bool value defines if an already joined or "
Packit Service 0a38ef
                        "partly set-up client can be repaired. Default: no")
Packit Service 0a38ef
    parser.add_argument("--ipaclient-install-packages",
Packit Service 0a38ef
                        dest="ipaclient_install_packages",
Packit Service 0a38ef
                        choices=("yes", "no"), default=None,
Packit Service 0a38ef
                        help="The bool value defines if the needed packages "
Packit Service 0a38ef
                        "are installed on the node. Default: yes")
Packit Service 0a38ef
    # playbook
Packit Service 0a38ef
    parser.add_argument("--playbook-dir",
Packit Service 0a38ef
                        dest="playbook_dir",
Packit Service 0a38ef
                        default=None,
Packit Service 0a38ef
                        help="If defined will be used as to create inventory "
Packit Service 0a38ef
                        "file and playbook in. The files will not be removed "
Packit Service 0a38ef
                        "after the playbook processing ended.")
Packit Service 0a38ef
    parser.add_argument("--become-method",
Packit Service 0a38ef
                        dest="become_method",
Packit Service 0a38ef
                        default="sudo",
Packit Service 0a38ef
                        help="privilege escalation method to use "
Packit Service 0a38ef
                        "(default=sudo), use `ansible-doc -t become -l` to "
Packit Service 0a38ef
                        "list valid choices.")
Packit Service 0a38ef
    parser.add_argument("--ansible-verbose",
Packit Service 0a38ef
                        dest="ansible_verbose",
Packit Service 0a38ef
                        type=int, default=None,
Packit Service 0a38ef
                        help="privilege escalation method to use "
Packit Service 0a38ef
                        "(default=sudo), use `ansible-doc -t become -l` to "
Packit Service 0a38ef
                        "list valid choices.")
Packit Service 0a38ef
Packit Service 0a38ef
    options, args = parser.parse_known_args()
Packit Service 0a38ef
Packit Service 0a38ef
    if options.playbook_dir and not os.path.isdir(options.playbook_dir):
Packit Service 0a38ef
        parser.error("playbook dir does not exist")
Packit Service 0a38ef
Packit Service 0a38ef
    if options.password_prompt:
Packit Service 0a38ef
        parser.error("password prompt is not possible with ansible")
Packit Service 0a38ef
    if options.log_file:
Packit Service 0a38ef
        parser.error("log_file is not supported")
Packit Service 0a38ef
Packit Service 0a38ef
    if len(args) < 1:
Packit Service 0a38ef
        parser.error("ansible host not set")
Packit Service 0a38ef
    elif len(args) > 1:
Packit Service 0a38ef
        parser.error("too many arguments: %s" % ",".join(args))
Packit Service 0a38ef
Packit Service 0a38ef
    return options, args
Packit Service 0a38ef
Packit Service 0a38ef
Packit Service 0a38ef
def run_cmd(args):
Packit Service 0a38ef
    """
Packit Service 0a38ef
    Execute an external command.
Packit Service 0a38ef
    """
Packit Service 0a38ef
    p_out = subprocess.PIPE
Packit Service 0a38ef
    p_err = subprocess.STDOUT
Packit Service 0a38ef
    try:
Packit Service 0a38ef
        p = subprocess.Popen(args, stdout=p_out, stderr=p_err,
Packit Service 0a38ef
                             close_fds=True, bufsize=1,
Packit Service 0a38ef
                             universal_newlines=True)
Packit Service 0a38ef
        while True:
Packit Service 0a38ef
            line = p.stdout.readline()
Packit Service 0a38ef
            if p.poll() is not None and line == "":
Packit Service 0a38ef
                break
Packit Service 0a38ef
            sys.stdout.write(line)
Packit Service 0a38ef
    except KeyboardInterrupt:
Packit Service 0a38ef
        p.wait()
Packit Service 0a38ef
        raise
Packit Service 0a38ef
    else:
Packit Service 0a38ef
        p.wait()
Packit Service 0a38ef
        return p.returncode
Packit Service 0a38ef
Packit Service 0a38ef
Packit Service 0a38ef
def main(options, args):
Packit Service 0a38ef
    if options.playbook_dir:
Packit Service 0a38ef
        playbook_dir = options.playbook_dir
Packit Service 0a38ef
    else:
Packit Service 0a38ef
        temp_dir = tempfile.mkdtemp(prefix='ansible-ipa-client')
Packit Service 0a38ef
        playbook_dir = temp_dir
Packit Service 0a38ef
Packit Service 0a38ef
    inventory = os.path.join(playbook_dir, "ipaclient-inventory")
Packit Service 0a38ef
    playbook = os.path.join(playbook_dir, "ipaclient-playbook.yml")
Packit Service 0a38ef
Packit Service 0a38ef
    with open(inventory, 'w') as f:
Packit Service 0a38ef
        if options.servers:
Packit Service 0a38ef
            f.write("[ipaservers]\n")
Packit Service 0a38ef
            for server in options.servers:
Packit Service 0a38ef
                f.write("%s\n" % server)
Packit Service 0a38ef
            f.write("\n")
Packit Service 0a38ef
        f.write("[ipaclients]\n")
Packit Service 0a38ef
        f.write("%s\n" % args[0])
Packit Service 0a38ef
        f.write("\n")
Packit Service 0a38ef
        f.write("[ipaclients:vars]\n")
Packit Service 0a38ef
        # basic
Packit Service 0a38ef
        if options.principal:
Packit Service 0a38ef
            f.write("ipaadmin_principal=%s\n" % options.principal)
Packit Service 0a38ef
        if options.ca_cert_file:
Packit Service 0a38ef
            f.write("ipaclient_ca_cert_file=%s\n" % options.ca_cert_file)
Packit Service 0a38ef
        if options.ip_addresses:
Packit Service 0a38ef
            f.write("ipaclient_ip_addresses=%s\n" %
Packit Service 0a38ef
                    ",".join(options.ip_addresses))
Packit Service 0a38ef
        if options.all_ip_addresses:
Packit Service 0a38ef
            f.write("ipaclient_all_ip_addresses=yes\n")
Packit Service 0a38ef
        if options.domain:
Packit Service 0a38ef
            f.write("ipaclient_domain=%s\n" % options.domain)
Packit Service 0a38ef
        # --servers are handled above
Packit Service 0a38ef
        if options.realm:
Packit Service 0a38ef
            f.write("ipaclient_realm=%s\n" % options.realm)
Packit Service 0a38ef
        if options.hostname:
Packit Service 0a38ef
            f.write("ipaclient_hostname=%s\n" % options.hostname)
Packit Service 0a38ef
        # client
Packit Service 0a38ef
        if options.password:
Packit Service 0a38ef
            f.write("ipaadmin_password=%s\n" % options.password)
Packit Service 0a38ef
        if options.force:
Packit Service 0a38ef
            f.write("ipaclient_force=yes\n")
Packit Service 0a38ef
        if options.configure_firefox:
Packit Service 0a38ef
            f.write("ipaclient_configure_firefox=yes\n")
Packit Service 0a38ef
        if options.firefox_dir:
Packit Service 0a38ef
            f.write("ipaclient_firefox_dir=%s\n" % options.firefox_dir)
Packit Service 0a38ef
        if options.keytab:
Packit Service 0a38ef
            f.write("ipaclient_keytab=%s\n" % options.keytab)
Packit Service 0a38ef
        if options.mkhomedir:
Packit Service 0a38ef
            f.write("ipaclient_mkhomedir=yes\n")
Packit Service 0a38ef
        if options.force_join:
Packit Service 0a38ef
            f.write("ipaclient_force_join=%s\n" % options.force_join)
Packit Service 0a38ef
        if options.ntp_servers:
Packit Service 0a38ef
            f.write("ipaclient_ntp_servers=%s\n" %
Packit Service 0a38ef
                    ",".join(options.ntp_servers))
Packit Service 0a38ef
        if options.ntp_pool:
Packit Service 0a38ef
            f.write("ipaclient_ntp_pool=%s\n" % options.ntp_pool)
Packit Service 0a38ef
        if options.no_ntp:
Packit Service 0a38ef
            f.write("ipaclient_no_ntp=yes\n")
Packit Service 0a38ef
        if options.nisdomain:
Packit Service 0a38ef
            f.write("ipaclient_nisdomain=%s\n" % options.nisdomain)
Packit Service 0a38ef
        if options.no_nisdomain:
Packit Service 0a38ef
            f.write("ipaclient_no_nisdomain=yes\n")
Packit Service 0a38ef
        if options.ssh_trust_dns:
Packit Service 0a38ef
            f.write("ipaclient_ssh_trust_dns=yes\n")
Packit Service 0a38ef
        if options.no_ssh:
Packit Service 0a38ef
            f.write("ipaclient_no_ssh=yes\n")
Packit Service 0a38ef
        if options.no_sshd:
Packit Service 0a38ef
            f.write("ipaclient_no_sshd=yes\n")
Packit Service 0a38ef
        if options.no_sudo:
Packit Service 0a38ef
            f.write("ipaclient_no_sudo=yes\n")
Packit Service 0a38ef
        if options.no_dns_sshfp:
Packit Service 0a38ef
            f.write("ipaclient_no_dns_sshfp=yes\n")
Packit Service 0a38ef
        if options.kinit_attempts:
Packit Service 0a38ef
            f.write("ipaclient_kinit_attempts=%d\n" % options.kinit_attempts)
Packit Service 0a38ef
        # sssd
Packit Service 0a38ef
        if options.fixed_primary:
Packit Service 0a38ef
            f.write("ipasssd_fixed_primary=yes\n")
Packit Service 0a38ef
        if options.permit:
Packit Service 0a38ef
            f.write("ipasssd_permit=yes\n")
Packit Service 0a38ef
        if options.enable_dns_updates:
Packit Service 0a38ef
            f.write("ipasssd_enable_dns_updates=yes\n")
Packit Service 0a38ef
        if options.no_krb5_offline_passwords:
Packit Service 0a38ef
            f.write("ipasssd_no_krb5_offline_passwords=yes\n")
Packit Service 0a38ef
        if options.preserve_sssd:
Packit Service 0a38ef
            f.write("ipasssd_preserve_sssd=yes\n")
Packit Service 0a38ef
        # automount
Packit Service 0a38ef
        if options.automount_location:
Packit Service 0a38ef
            f.write("ipaclient_automount_location=%s\n" %
Packit Service 0a38ef
                    options.automount_location)
Packit Service 0a38ef
        # ansible
Packit Service 0a38ef
        if options.ipaclient_use_otp:
Packit Service 0a38ef
            f.write("ipaclient_use_otp=%s\n" % options.ipaclient_use_otp)
Packit Service 0a38ef
        if options.ipaclient_allow_repair:
Packit Service 0a38ef
            f.write("ipaclient_allow_repair=%s\n" %
Packit Service 0a38ef
                    options.ipaclient_allow_repair)
Packit Service 0a38ef
        if options.ipaclient_install_packages:
Packit Service 0a38ef
            f.write("ipaclient_install_packages=%s\n" %
Packit Service 0a38ef
                    options.ipaclient_install_packages)
Packit Service 0a38ef
Packit Service 0a38ef
    if options.uninstall:
Packit Service 0a38ef
        state = "absent"
Packit Service 0a38ef
    else:
Packit Service 0a38ef
        state = "present"
Packit Service 0a38ef
Packit Service 0a38ef
    with open(playbook, 'w') as f:
Packit Service 0a38ef
        f.write("---\n")
Packit Service 0a38ef
        f.write("- name: Playbook to configure IPA clients\n")
Packit Service 0a38ef
        f.write("  hosts: ipaclients\n")
Packit Service 0a38ef
        f.write("  become: true\n")
Packit Service 0a38ef
        if options.become_method:
Packit Service 0a38ef
            f.write("  become_method: %s\n" % options.become_method)
Packit Service 0a38ef
        f.write("\n")
Packit Service 0a38ef
        f.write("  roles:\n")
Packit Service 0a38ef
        f.write("  - role: ipaclient\n")
Packit Service 0a38ef
        f.write("    state: %s\n" % state)
Packit Service 0a38ef
Packit Service 0a38ef
    cmd = [ 'ansible-playbook' ]
Packit Service 0a38ef
    if options.ansible_verbose:
Packit Service 0a38ef
        cmd.append("-"+"v"*options.ansible_verbose)
Packit Service 0a38ef
    cmd.extend(['-i', inventory, playbook])
Packit Service 0a38ef
    try:
Packit Service 0a38ef
        returncode = run_cmd(cmd)
Packit Service 0a38ef
        if returncode != 0:
Packit Service 0a38ef
            raise RuntimeError()
Packit Service 0a38ef
    finally:
Packit Service 0a38ef
        if not options.playbook_dir:
Packit Service 0a38ef
            shutil.rmtree(temp_dir, ignore_errors=True)
Packit Service 0a38ef
Packit Service 0a38ef
Packit Service 0a38ef
options, args = parse_options()
Packit Service 0a38ef
try:
Packit Service 0a38ef
    main(options, args)
Packit Service 0a38ef
except KeyboardInterrupt:
Packit Service 0a38ef
    sys.exit(1)
Packit Service 0a38ef
except SystemExit as e:
Packit Service 0a38ef
    sys.exit(e)
Packit Service 0a38ef
except RuntimeError as e:
Packit Service 0a38ef
    sys.exit(e)
Packit Service 0a38ef
except Exception as e:
Packit Service 0a38ef
    if options.verbose:
Packit Service 0a38ef
        traceback.print_exc(file=sys.stdout)
Packit Service 0a38ef
    else:
Packit Service 0a38ef
        print("Re-run %s with --verbose option to get more information" %
Packit Service 0a38ef
              sys.argv[0])
Packit Service 0a38ef
Packit Service 0a38ef
    print("Unexpected error: %s" % str(e))
Packit Service 0a38ef
    sys.exit(1)