Add code to deregister nodes and services from freeipa
A module has been added to delete hosts and clean up all the sub hosts and services associated with those hosts in IPA. It can be called for a single host - as in the case of a scale_down operation, or for multiple hosts - as in the case of a stack delete. Ultimately, we would like to add this functionality to ansible-freeipa. Co-Authored-By: Grzegorz Grasza <xek@redhat.com> Change-Id: Ib08f038773f8ca28d85a95921cdb522b5cd4de04
This commit is contained in:
parent
c9441fc968
commit
c4b5452672
37
bindep.txt
Normal file
37
bindep.txt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# This file facilitates OpenStack-CI package installation
|
||||||
|
# before the execution of any tests.
|
||||||
|
#
|
||||||
|
# See the following for details:
|
||||||
|
# - https://docs.openstack.org/infra/bindep/
|
||||||
|
# - https://opendev.org/opendev/bindep/
|
||||||
|
#
|
||||||
|
# Even if the role does not make use of this facility, it
|
||||||
|
# is better to have this file empty, otherwise OpenStack-CI
|
||||||
|
# will fall back to installing its default packages which
|
||||||
|
# will potentially be detrimental to the tests executed.
|
||||||
|
|
||||||
|
# The gcc compiler
|
||||||
|
gcc
|
||||||
|
|
||||||
|
# Base requirements for RPM distros
|
||||||
|
gcc-c++ [platform:rpm]
|
||||||
|
git [platform:rpm]
|
||||||
|
libffi-devel [platform:rpm]
|
||||||
|
openssl-devel [platform:rpm]
|
||||||
|
python-devel [platform:rpm !platform:rhel-8 !platform:centos-8]
|
||||||
|
python3-devel [platform:rpm !platform:rhel-7 !platform:centos-7]
|
||||||
|
PyYAML [platform:rpm !platform:rhel-8 !platform:centos-8]
|
||||||
|
python3-pyyaml [platform:rpm !platform:rhel-7 !platform:centos-7]
|
||||||
|
python3-dnf [platform:rpm !platform:rhel-7 !platform:centos-7]
|
||||||
|
|
||||||
|
# For SELinux
|
||||||
|
libselinux-python [platform:rpm !platform:rhel-8 !platform:centos-8]
|
||||||
|
libsemanage-python [platform:redhat !platform:rhel-8 !platform:centos-8]
|
||||||
|
libselinux-python3 [platform:rpm !platform:rhel-7 !platform:centos-7]
|
||||||
|
libsemanage-python3 [platform:redhat !platform:rhel-7 !platform:centos-7]
|
||||||
|
|
||||||
|
# Required for compressing collected log files in CI
|
||||||
|
gzip
|
||||||
|
|
||||||
|
# Required to build language docs
|
||||||
|
gettext
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
six>=1.10.0 # MIT
|
||||||
|
PyYAML>=3.12 # MIT
|
2
tox.ini
2
tox.ini
@ -10,6 +10,7 @@ install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/
|
|||||||
passenv = *
|
passenv = *
|
||||||
sitepackages = True
|
sitepackages = True
|
||||||
deps =
|
deps =
|
||||||
|
-r {toxinidir}/requirements.txt
|
||||||
-r {toxinidir}/ansible-requirements.txt
|
-r {toxinidir}/ansible-requirements.txt
|
||||||
-r {toxinidir}/test-requirements.txt
|
-r {toxinidir}/test-requirements.txt
|
||||||
commands = stestr run {posargs}
|
commands = stestr run {posargs}
|
||||||
@ -19,6 +20,7 @@ whitelist_externals =
|
|||||||
[testenv:molecule]
|
[testenv:molecule]
|
||||||
setenv =
|
setenv =
|
||||||
ANSIBLE_FILTER_PLUGINS={toxinidir}/tripleo_ipa/ansible_plugins/filter
|
ANSIBLE_FILTER_PLUGINS={toxinidir}/tripleo_ipa/ansible_plugins/filter
|
||||||
|
ANSIBLE_LIBRARY={toxinidir}/tripleo_ipa/roles.galaxy/config_template/library:{toxinidir}/tripleo_ipa/ansible_plugins/modules
|
||||||
ANSIBLE_ROLES_PATH={toxinidir}/tripleo_ipa/roles.galaxy:{toxinidir}/tripleo_ipa/roles
|
ANSIBLE_ROLES_PATH={toxinidir}/tripleo_ipa/roles.galaxy:{toxinidir}/tripleo_ipa/roles
|
||||||
deps =
|
deps =
|
||||||
-r {toxinidir}/molecule-requirements.txt
|
-r {toxinidir}/molecule-requirements.txt
|
||||||
|
403
tripleo_ipa/ansible_plugins/modules/cleanup_ipa_services.py
Normal file
403
tripleo_ipa/ansible_plugins/modules/cleanup_ipa_services.py
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2020 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import uuid
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
import six
|
||||||
|
from six.moves import http_client
|
||||||
|
|
||||||
|
from gssapi.exceptions import GSSError
|
||||||
|
from ipalib import api
|
||||||
|
from ipalib import errors
|
||||||
|
|
||||||
|
try:
|
||||||
|
from ipapython.ipautil import kinit_keytab
|
||||||
|
except ImportError:
|
||||||
|
# The import moved in freeIPA 4.5.0
|
||||||
|
from ipalib.install.kinit import kinit_keytab
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.openstack import openstack_full_argument_spec
|
||||||
|
from ansible.module_utils.openstack import openstack_module_kwargs
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {
|
||||||
|
'metadata_version': '1.0',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'
|
||||||
|
}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: cleanup_ipa_services
|
||||||
|
|
||||||
|
short_description: Cleanup IPA Services and Hosts
|
||||||
|
|
||||||
|
version_added: "2.8"
|
||||||
|
|
||||||
|
description:
|
||||||
|
- When hosts are deleted, delete the hosts, subhosts and services
|
||||||
|
associated with the hosts in the FreeIPA server.
|
||||||
|
- If the services are managed exclusively by the hosts, then
|
||||||
|
delete the subhost for that service and the service itself.
|
||||||
|
- If the service is managed by other hosts (not being deleted),
|
||||||
|
then simply remove the host(s) being deleted from the managed_by
|
||||||
|
attribute.
|
||||||
|
|
||||||
|
options:
|
||||||
|
principal:
|
||||||
|
description:
|
||||||
|
- Principal to use when authenticating to FreeIPA.
|
||||||
|
type: str
|
||||||
|
keytab:
|
||||||
|
description:
|
||||||
|
- Keytab to use when authenticating to FreeIPA
|
||||||
|
type: str
|
||||||
|
hosts:
|
||||||
|
description:
|
||||||
|
- Hosts to be deleted (list of FQDNs)
|
||||||
|
type: list
|
||||||
|
author:
|
||||||
|
- Ade Lee (@vakwetu)
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Cleanup IPA hosts and services
|
||||||
|
cleanup_ipa_services:
|
||||||
|
principal: user/my_host@REALM
|
||||||
|
keytab: /etc/krb5.keytab
|
||||||
|
hosts:
|
||||||
|
- test-server-0.exmaple.com
|
||||||
|
- test-server-1.example.com
|
||||||
|
- test-server-2.example.com
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class IPAClient(object):
|
||||||
|
|
||||||
|
def __init__(self, keytab, principal):
|
||||||
|
self.ntries = 5
|
||||||
|
self.retry_delay = 2
|
||||||
|
self.keytab = keytab
|
||||||
|
self.principal = principal
|
||||||
|
|
||||||
|
if self._ipa_client_configured() and not api.isdone('finalize'):
|
||||||
|
self.ccache = "MEMORY:" + str(uuid.uuid4())
|
||||||
|
os.environ['KRB5CCNAME'] = self.ccache
|
||||||
|
kinit_keytab(self.principal, self.keytab, self.ccache)
|
||||||
|
api.bootstrap(context='cleanup')
|
||||||
|
api.finalize()
|
||||||
|
else:
|
||||||
|
self.ccache = os.environ['KRB5CCNAME']
|
||||||
|
self.batch_args = list()
|
||||||
|
|
||||||
|
def split_principal(self, principal):
|
||||||
|
"""Split a principal into its components. Copied from IPA 4.0.0"""
|
||||||
|
service = hostname = realm = None
|
||||||
|
|
||||||
|
# Break down the principal into its component parts, which may or
|
||||||
|
# may not include the realm.
|
||||||
|
sp = principal.split('/')
|
||||||
|
if len(sp) != 2:
|
||||||
|
raise errors.MalformedServicePrincipal(reason='missing service')
|
||||||
|
|
||||||
|
service = sp[0]
|
||||||
|
if len(service) == 0:
|
||||||
|
raise errors.MalformedServicePrincipal(reason='blank service')
|
||||||
|
sr = sp[1].split('@')
|
||||||
|
if len(sr) > 2:
|
||||||
|
raise errors.MalformedServicePrincipal(
|
||||||
|
reason='unable to determine realm')
|
||||||
|
|
||||||
|
hostname = sr[0].lower()
|
||||||
|
if len(sr) == 2:
|
||||||
|
realm = sr[1].upper()
|
||||||
|
# At some point we'll support multiple realms
|
||||||
|
if realm != api.env.realm:
|
||||||
|
raise errors.RealmMismatch()
|
||||||
|
else:
|
||||||
|
realm = api.env.realm
|
||||||
|
|
||||||
|
# Note that realm may be None.
|
||||||
|
return (service, hostname, realm)
|
||||||
|
|
||||||
|
def split_hostname(self, hostname):
|
||||||
|
"""Split a hostname into its host and domain parts"""
|
||||||
|
parts = hostname.split('.')
|
||||||
|
domain = six.text_type('.'.join(parts[1:]) + '.')
|
||||||
|
return (parts[0], domain)
|
||||||
|
|
||||||
|
def __get_connection(self):
|
||||||
|
"""Make a connection to IPA or raise an error."""
|
||||||
|
tries = 0
|
||||||
|
|
||||||
|
while (tries <= self.ntries):
|
||||||
|
logging.debug("Attempt %d of %d", tries, self.ntries)
|
||||||
|
if api.Backend.rpcclient.isconnected():
|
||||||
|
api.Backend.rpcclient.disconnect()
|
||||||
|
try:
|
||||||
|
api.Backend.rpcclient.connect()
|
||||||
|
# ping to force an actual connection in case there is only one
|
||||||
|
# IPA master
|
||||||
|
api.Command[u'ping']()
|
||||||
|
except (errors.CCacheError,
|
||||||
|
errors.TicketExpired,
|
||||||
|
errors.KerberosError) as e:
|
||||||
|
tries += 1
|
||||||
|
|
||||||
|
# pylint: disable=no-member
|
||||||
|
logging.debug("kinit new ccache in get_connection: %s", e)
|
||||||
|
try:
|
||||||
|
kinit_keytab(str('nova/%s@%s' %
|
||||||
|
(api.env.host, api.env.realm)),
|
||||||
|
self.keytab,
|
||||||
|
self.ccache)
|
||||||
|
except GSSError as e:
|
||||||
|
logging.debug("kinit failed: %s", e)
|
||||||
|
except errors.NetworkError:
|
||||||
|
tries += 1
|
||||||
|
except http_client.ResponseNotReady:
|
||||||
|
# NOTE(xek): This means that the server closed the socket,
|
||||||
|
# so keep-alive ended and we can't use that connection.
|
||||||
|
api.Backend.rpcclient.disconnect()
|
||||||
|
tries += 1
|
||||||
|
else:
|
||||||
|
# successful connection
|
||||||
|
return
|
||||||
|
logging.debug("Waiting %s seconds before next retry.",
|
||||||
|
self.retry_delay)
|
||||||
|
time.sleep(self.retry_delay)
|
||||||
|
|
||||||
|
logging.error(" Failed to connect to IPA after %d attempts",
|
||||||
|
self.ntries)
|
||||||
|
raise Exception("Failed to connect to IPA")
|
||||||
|
|
||||||
|
def start_batch_operation(self):
|
||||||
|
"""Start a batch operation.
|
||||||
|
|
||||||
|
IPA method calls will be collected in a batch job
|
||||||
|
and submitted to IPA once all the operations have collected
|
||||||
|
by a call to _flush_batch_operation().
|
||||||
|
"""
|
||||||
|
logging.debug("start batch operation")
|
||||||
|
self.batch_args = list()
|
||||||
|
|
||||||
|
def _add_batch_operation(self, command, *args, **kw):
|
||||||
|
"""Add an IPA call to the batch operation"""
|
||||||
|
self.batch_args.append({
|
||||||
|
"method": six.text_type(command),
|
||||||
|
"params": [args, kw],
|
||||||
|
})
|
||||||
|
|
||||||
|
def flush_batch_operation(self):
|
||||||
|
"""Make an IPA batch call."""
|
||||||
|
logging.debug("flush_batch_operation")
|
||||||
|
if not self.batch_args:
|
||||||
|
return None
|
||||||
|
|
||||||
|
kw = {}
|
||||||
|
logging.debug(" %s", self.batch_args)
|
||||||
|
|
||||||
|
return self._call_ipa('batch', *self.batch_args, **kw)
|
||||||
|
|
||||||
|
def _call_ipa(self, command, *args, **kw):
|
||||||
|
"""Make an IPA call."""
|
||||||
|
if not api.Backend.rpcclient.isconnected():
|
||||||
|
self.__get_connection()
|
||||||
|
if 'version' not in kw:
|
||||||
|
kw['version'] = u'2.146' # IPA v4.2.0 for compatibility
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
result = api.Command[command](*args, **kw)
|
||||||
|
logging.debug(result)
|
||||||
|
return result
|
||||||
|
except (errors.CCacheError,
|
||||||
|
errors.TicketExpired,
|
||||||
|
errors.KerberosError):
|
||||||
|
logging.debug("Refresh authentication")
|
||||||
|
self.__get_connection()
|
||||||
|
except errors.NetworkError:
|
||||||
|
raise
|
||||||
|
except http_client.ResponseNotReady:
|
||||||
|
# NOTE(xek): This means that the server closed the socket,
|
||||||
|
# so keep-alive ended and we can't use that connection.
|
||||||
|
api.Backend.rpcclient.disconnect()
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _ipa_client_configured(self):
|
||||||
|
"""Determine if the machine is an enrolled IPA client.
|
||||||
|
|
||||||
|
Return boolean indicating whether this machine is enrolled
|
||||||
|
in IPA. This is a rather weak detection method but better
|
||||||
|
than nothing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return os.path.exists('/etc/ipa/default.conf')
|
||||||
|
|
||||||
|
def delete_host(self, hostname, batch=True):
|
||||||
|
"""Delete a host from IPA.
|
||||||
|
|
||||||
|
Servers can have multiple network interfaces, and therefore can
|
||||||
|
have multiple aliases. Moreover, they can part of a service using
|
||||||
|
a virtual host (VIP). These aliases are denoted 'subhosts',
|
||||||
|
"""
|
||||||
|
logging.debug("Deleting subhost: %s", hostname)
|
||||||
|
host_params = [hostname]
|
||||||
|
|
||||||
|
(hn, domain) = self.split_hostname(hostname)
|
||||||
|
|
||||||
|
dns_params = [domain, hn]
|
||||||
|
|
||||||
|
# If there is no DNS entry, this operation fails
|
||||||
|
host_kw = {'updatedns': False, }
|
||||||
|
|
||||||
|
dns_kw = {'del_all': True, }
|
||||||
|
|
||||||
|
if batch:
|
||||||
|
self._add_batch_operation('host_del', *host_params, **host_kw)
|
||||||
|
self._add_batch_operation('dnsrecord_del', *dns_params,
|
||||||
|
**dns_kw)
|
||||||
|
else:
|
||||||
|
self._call_ipa('host_del', *host_params, **host_kw)
|
||||||
|
try:
|
||||||
|
self._call_ipa('dnsrecord_del',
|
||||||
|
*dns_params, **dns_kw)
|
||||||
|
except (errors.NotFound, errors.ACIError):
|
||||||
|
# Ignore DNS deletion errors
|
||||||
|
pass
|
||||||
|
|
||||||
|
def host_get_services(self, service_host):
|
||||||
|
"""Return list of services this host manages"""
|
||||||
|
logging.debug("Checking host %s services", service_host)
|
||||||
|
params = []
|
||||||
|
service_args = {'man_by_host': six.text_type(service_host)}
|
||||||
|
result = self._call_ipa('service_find',
|
||||||
|
*params, **service_args)
|
||||||
|
return [service['krbprincipalname'][0] for service in result['result']]
|
||||||
|
|
||||||
|
def service_managed_by_other_hosts(self, service_principal,
|
||||||
|
hosts_to_be_deleted):
|
||||||
|
"""Return True if hosts other than parent manages this service"""
|
||||||
|
|
||||||
|
logging.debug("Checking if principal %s has hosts", service_principal)
|
||||||
|
params = [service_principal]
|
||||||
|
service_args = {}
|
||||||
|
try:
|
||||||
|
result = self._call_ipa('service_show',
|
||||||
|
*params, **service_args)
|
||||||
|
except errors.NotFound:
|
||||||
|
raise KeyError
|
||||||
|
serviceresult = result['result']
|
||||||
|
|
||||||
|
try:
|
||||||
|
(service, hostname, realm) = self.split_principal(
|
||||||
|
service_principal
|
||||||
|
)
|
||||||
|
except errors.MalformedServicePrincipal as e:
|
||||||
|
logging.error("Unable to split principal %s: %s",
|
||||||
|
service_principal, e)
|
||||||
|
raise
|
||||||
|
|
||||||
|
for candidate in serviceresult.get('managedby_host', []):
|
||||||
|
if candidate != hostname:
|
||||||
|
if candidate not in hosts_to_be_deleted:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def find_host(self, hostname):
|
||||||
|
"""Return True if this host exists"""
|
||||||
|
logging.debug("Checking if host %s exists", hostname)
|
||||||
|
params = []
|
||||||
|
service_args = {'fqdn': six.text_type(hostname)}
|
||||||
|
result = self._call_ipa('host_find',
|
||||||
|
*params, **service_args)
|
||||||
|
return result['count'] > 0
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_ipa_services(keytab, principal, hosts):
|
||||||
|
ipa = IPAClient(keytab, principal)
|
||||||
|
|
||||||
|
hosts_to_delete = set()
|
||||||
|
for host in hosts:
|
||||||
|
hostname = host.decode('UTF-8')
|
||||||
|
if ipa.find_host(hostname):
|
||||||
|
hosts_to_delete.add(hostname)
|
||||||
|
|
||||||
|
# get a list of all the services associated with a given hosts
|
||||||
|
principals = set()
|
||||||
|
for host in hosts_to_delete:
|
||||||
|
principals.update(ipa.host_get_services(host))
|
||||||
|
|
||||||
|
# Check the managed_by attribute of each service identified with
|
||||||
|
# the given host. If it is managed by a host other than the
|
||||||
|
# parent or the hosts to be deleted, then it is likely a VIP and it
|
||||||
|
# is not ready to be removed.
|
||||||
|
subhosts_to_delete = set()
|
||||||
|
for principal in principals:
|
||||||
|
(service, subhost, domain) = ipa.split_principal(principal)
|
||||||
|
if ipa.service_managed_by_other_hosts(principal, hosts_to_delete):
|
||||||
|
# this service still has other hosts
|
||||||
|
continue
|
||||||
|
subhosts_to_delete.add(subhost)
|
||||||
|
|
||||||
|
# delete the subhosts. Referential integrity should take care of the
|
||||||
|
# services associated with these hosts.
|
||||||
|
ipa.start_batch_operation()
|
||||||
|
for host in hosts_to_delete:
|
||||||
|
ipa.delete_host(host)
|
||||||
|
for subhost in subhosts_to_delete:
|
||||||
|
ipa.delete_host(subhost)
|
||||||
|
ipa.flush_batch_operation()
|
||||||
|
|
||||||
|
|
||||||
|
def run_module():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
**yaml.safe_load(DOCUMENTATION)['options']
|
||||||
|
)
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**openstack_module_kwargs()
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
keytab = module.params.get('keytab')
|
||||||
|
principal = module.params.get('principal')
|
||||||
|
hosts = module.params.get('hosts')
|
||||||
|
|
||||||
|
cleanup_ipa_services(keytab, principal, hosts)
|
||||||
|
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
except Exception as err:
|
||||||
|
module.fail_json(msg=str(err))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
run_module()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
37
tripleo_ipa/molecule/deregister/Dockerfile
Normal file
37
tripleo_ipa/molecule/deregister/Dockerfile
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Molecule managed
|
||||||
|
# Copyright 2019 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
{% if item.registry is defined %}
|
||||||
|
FROM {{ item.registry.url }}/{{ item.image }}
|
||||||
|
{% else %}
|
||||||
|
FROM {{ item.image }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
|
||||||
|
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \
|
||||||
|
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
|
||||||
|
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \
|
||||||
|
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \
|
||||||
|
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi
|
||||||
|
|
||||||
|
{% for pkg in item.easy_install | default([]) %}
|
||||||
|
# install pip for centos where there is no python-pip rpm in default repos
|
||||||
|
RUN easy_install {{ pkg }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
CMD ["/sbin/init"]
|
163
tripleo_ipa/molecule/deregister/converge.yml
Normal file
163
tripleo_ipa/molecule/deregister/converge.yml
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
---
|
||||||
|
# Copyright 2019 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
- name: Setup server
|
||||||
|
hosts: all
|
||||||
|
vars:
|
||||||
|
ipa_domain: example.test
|
||||||
|
ipa_server_ip: 172.18.0.22
|
||||||
|
ipa_server_user: admin
|
||||||
|
ipa_server_password: password123
|
||||||
|
ipa_server_hostname: ipa.example.test
|
||||||
|
undercloud_fqdn: ipa.example.test
|
||||||
|
tasks:
|
||||||
|
- name: copy requirements file
|
||||||
|
copy:
|
||||||
|
src: "{{playbook_dir}}/../../../requirements.txt"
|
||||||
|
dest: /tmp/requirements.txt
|
||||||
|
- name: install requirements
|
||||||
|
pip:
|
||||||
|
requirements: /tmp/requirements.txt
|
||||||
|
- name: install python urllib gssapi
|
||||||
|
pip:
|
||||||
|
name: urllib_gssapi
|
||||||
|
- name: install ipa client
|
||||||
|
package:
|
||||||
|
name: ipa-client
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: set resolv.conf to point to the ipa server
|
||||||
|
shell:
|
||||||
|
cmd: cat > /etc/resolv.conf
|
||||||
|
stdin: |
|
||||||
|
search {{ ipa_domain }}
|
||||||
|
nameserver {{ ipa_server_ip }}
|
||||||
|
- name: Set fqdn in /etc/hosts
|
||||||
|
shell:
|
||||||
|
cmd: cat > /etc/hosts
|
||||||
|
- name: Set fqdn in /etc/hosts
|
||||||
|
shell:
|
||||||
|
cmd: cat > /etc/hosts
|
||||||
|
stdin: |
|
||||||
|
127.0.0.1 test-0.example.test test-0 localhost localhost.localdomain
|
||||||
|
|
||||||
|
- name: enroll the server as an ipa client using admin creds
|
||||||
|
shell: |
|
||||||
|
ipa-client-install -U \
|
||||||
|
--server "{{ ipa_server_hostname }}" \
|
||||||
|
--domain "{{ ipa_domain }}" \
|
||||||
|
--realm "{{ ipa_domain | upper }}" \
|
||||||
|
--principal "{{ ipa_server_user }}" \
|
||||||
|
--password "{{ ipa_server_password }}" \
|
||||||
|
--no-ntp --force-join --no-nisdomain
|
||||||
|
args:
|
||||||
|
creates: /etc/ipa/default.conf
|
||||||
|
|
||||||
|
# we need this keytab for operations that we cannot do yet with ansible
|
||||||
|
- name: kinit to get admin creds
|
||||||
|
command: kinit "{{ ipa_server_user }}"
|
||||||
|
args:
|
||||||
|
stdin: "{{ ipa_server_password }}"
|
||||||
|
|
||||||
|
- name: ensure "tripleo-admin" group exists
|
||||||
|
group:
|
||||||
|
name: tripleo-admin
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: create users, perms, get keytab
|
||||||
|
include_role:
|
||||||
|
name: tripleo_ipa_setup
|
||||||
|
apply:
|
||||||
|
environment:
|
||||||
|
IPA_USER: "{{ ipa_server_user }}"
|
||||||
|
IPA_HOST: "{{ ipa_server_hostname }}"
|
||||||
|
IPA_PASS: "{{ ipa_server_password }}"
|
||||||
|
|
||||||
|
- name: Converge - add host and relevant services
|
||||||
|
hosts: all
|
||||||
|
vars:
|
||||||
|
tripleo_ipa_enroll_base_server: true
|
||||||
|
tripleo_ipa_base_server_fqdn: test-0.example.test
|
||||||
|
tripleo_ipa_base_server_short_name: test-0
|
||||||
|
tripleo_ipa_base_server_domain: example.test
|
||||||
|
tripleo_ipa_delegate_server: localhost
|
||||||
|
tripleo_ipa_server_metadata: |
|
||||||
|
{
|
||||||
|
"compact_service_HTTP": [
|
||||||
|
"ctlplane",
|
||||||
|
"storage",
|
||||||
|
"storagemgmt",
|
||||||
|
"internalapi",
|
||||||
|
"external"
|
||||||
|
],
|
||||||
|
"compact_service_haproxy": [
|
||||||
|
"ctlplane",
|
||||||
|
"storage",
|
||||||
|
"storagemgmt",
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"compact_service_libvirt-vnc": [
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"compact_service_mysql": [
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"compact_service_neutron_ovn": [
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"compact_service_novnc-proxy": [
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"compact_service_ovn_controller": [
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"compact_service_ovn_dbs": [
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"compact_service_rabbitmq": [
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"compact_service_redis": [
|
||||||
|
"internalapi"
|
||||||
|
],
|
||||||
|
"managed_service_haproxyctlplane": "haproxy/test-0.ctlplane.example.test",
|
||||||
|
"managed_service_haproxyexternal": "haproxy/test-0.example.test",
|
||||||
|
"managed_service_haproxyinternal_api": "haproxy/test-0.internalapi.example.test",
|
||||||
|
"managed_service_haproxystorage": "haproxy/test-0.storage.example.test",
|
||||||
|
"managed_service_haproxystorage_mgmt": "haproxy/test-0.storagemgmt.example.test",
|
||||||
|
"managed_service_mysqlinternal_api": "mysql/test-0.internalapi.example.test",
|
||||||
|
"managed_service_ovn_dbsinternal_api": "ovn_dbs/test-0.internalapi.example.test",
|
||||||
|
"managed_service_redisinternal_api": "redis/test-0.internalapi.example.test"
|
||||||
|
}
|
||||||
|
roles:
|
||||||
|
- name: tripleo_ipa_registration
|
||||||
|
environment:
|
||||||
|
IPA_USER: admin
|
||||||
|
IPA_HOST: ipa.example.test
|
||||||
|
IPA_PASS: password123
|
||||||
|
|
||||||
|
- name: Converge - delete host and relevant services
|
||||||
|
hosts: all
|
||||||
|
vars:
|
||||||
|
ipa_server_user: nova/ipa.example.test
|
||||||
|
ipa_server_hostname: ipa.example.test
|
||||||
|
tasks:
|
||||||
|
- include_role:
|
||||||
|
name: tripleo_ipa_cleanup
|
||||||
|
vars:
|
||||||
|
tripleo_ipa_hosts_to_delete: [ 'test-0.example.test' ]
|
||||||
|
tripleo_ipa_principal: "{{ ipa_server_user }}"
|
||||||
|
tripleo_ipa_keytab: "/etc/novajoin/krb5.keytab"
|
46
tripleo_ipa/molecule/deregister/molecule.yml
Normal file
46
tripleo_ipa/molecule/deregister/molecule.yml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
driver:
|
||||||
|
name: docker
|
||||||
|
|
||||||
|
log: true
|
||||||
|
|
||||||
|
platforms:
|
||||||
|
- name: centos7
|
||||||
|
hostname: test-0.example.test
|
||||||
|
image: centos:7
|
||||||
|
security_opts:
|
||||||
|
- seccomp=unconfined
|
||||||
|
command: /sbin/init
|
||||||
|
tmpfs:
|
||||||
|
- /run
|
||||||
|
- /tmp
|
||||||
|
volumes:
|
||||||
|
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
network_mode: host
|
||||||
|
easy_install:
|
||||||
|
- pip
|
||||||
|
environment: &env
|
||||||
|
http_proxy: "{{ lookup('env', 'http_proxy') }}"
|
||||||
|
https_proxy: "{{ lookup('env', 'https_proxy') }}"
|
||||||
|
|
||||||
|
provisioner:
|
||||||
|
name: ansible
|
||||||
|
log: true
|
||||||
|
env:
|
||||||
|
ANSIBLE_STDOUT_CALLBACK: yaml
|
||||||
|
ANSIBLE_ROLES_PATH: "${ANSIBLE_ROLES_PATH:-/usr/share/ansible/roles}:${HOME}/zuul-jobs/roles"
|
||||||
|
ANSIBLE_LIBRARY: "${ANSIBLE_LIBRARY:-/usr/share/ansible/plugins/modules}"
|
||||||
|
ANSIBLE_FILTER_PLUGINS: "${ANSIBLE_FILTER_PLUGINS:-/usr/share/ansible/plugins/filter}"
|
||||||
|
|
||||||
|
scenario:
|
||||||
|
test_sequence:
|
||||||
|
- destroy
|
||||||
|
- create
|
||||||
|
- prepare
|
||||||
|
- converge
|
||||||
|
- verify
|
||||||
|
- destroy
|
||||||
|
|
||||||
|
verifier:
|
||||||
|
name: testinfra
|
74
tripleo_ipa/molecule/deregister/prepare.yml
Normal file
74
tripleo_ipa/molecule/deregister/prepare.yml
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
# Copyright 2020 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
- hosts: localhost
|
||||||
|
connection: local
|
||||||
|
tasks:
|
||||||
|
- name: set facts for domains
|
||||||
|
set_fact:
|
||||||
|
domain: example.test
|
||||||
|
ipa_password: password123
|
||||||
|
|
||||||
|
- name: Download FreeIPA Container
|
||||||
|
docker_image:
|
||||||
|
name: freeipa/freeipa-server:fedora-28
|
||||||
|
source: pull
|
||||||
|
|
||||||
|
- name: Make IPA data dir
|
||||||
|
file:
|
||||||
|
path: /tmp/ipa-data
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: Toggle SELinux boolean
|
||||||
|
seboolean:
|
||||||
|
name: container_manage_cgroup
|
||||||
|
state: true
|
||||||
|
persistent: true
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Remove any old IPA container
|
||||||
|
docker_container:
|
||||||
|
name: freeipa-server-container
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Create network
|
||||||
|
docker_network:
|
||||||
|
name: ipa_network
|
||||||
|
ipam_config:
|
||||||
|
- subnet: 172.18.0.0/16
|
||||||
|
|
||||||
|
- name: Configure FreeIPA
|
||||||
|
shell: >
|
||||||
|
docker run --name freeipa-server-container
|
||||||
|
--sysctl net.ipv6.conf.lo.disable_ipv6=0
|
||||||
|
--security-opt seccomp=unconfined
|
||||||
|
--net ipa_network --ip 172.18.0.22
|
||||||
|
-e IPA_SERVER_IP={{ ansible_default_ipv4.address | default('127.0.0.1') }}
|
||||||
|
-e PASSWORD={{ ipa_password }}
|
||||||
|
-h ipa.{{ domain }}
|
||||||
|
--read-only --tmpfs /run --tmpfs /tmp
|
||||||
|
-v /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||||
|
-v /tmp/ipa-data:/data:Z freeipa/freeipa-server:fedora-28 exit-on-finished
|
||||||
|
-U -r {{ domain | upper }} --setup-dns --no-reverse --no-ntp
|
||||||
|
--forwarder={{ unbound_primary_nameserver_v4 | default('1.1.1.1') }}
|
||||||
|
--forwarder={{ unbound_secondary_nameserver_v4 | default('8.8.8.8') }} &
|
||||||
|
|
||||||
|
- name: Wait for FreeIPA server install
|
||||||
|
wait_for:
|
||||||
|
path: "/tmp/ipa-data/var/log/ipaserver-install.log"
|
||||||
|
search_regex: "(INFO The ipa-server-install command was successful|ERROR The ipa-server-install command failed)"
|
||||||
|
timeout: 900
|
||||||
|
become: true
|
128
tripleo_ipa/molecule/deregister/tests/test_default.py
Normal file
128
tripleo_ipa/molecule/deregister/tests/test_default.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import testinfra
|
||||||
|
import testinfra.utils.ansible_runner
|
||||||
|
|
||||||
|
inventory = os.environ['MOLECULE_INVENTORY_FILE']
|
||||||
|
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||||
|
inventory).get_hosts('all')
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(module):
|
||||||
|
for host in testinfra_hosts:
|
||||||
|
testinfra.get_host('ansible://' + host,
|
||||||
|
ansible_inventory=inventory
|
||||||
|
).check_output('echo password123 | kinit admin')
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_module(module):
|
||||||
|
for host in testinfra_hosts:
|
||||||
|
testinfra.get_host('ansible://' + host,
|
||||||
|
ansible_inventory=inventory
|
||||||
|
).check_output('kdestroy')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('perm', [
|
||||||
|
{'name': 'Modify host password', 'right': "write",
|
||||||
|
'type': "host", 'attrs': "userpassword"},
|
||||||
|
{'name': 'Write host certificate', 'right': "write",
|
||||||
|
'type': "host", 'attrs': "usercertificate"},
|
||||||
|
{'name': 'Modify host userclass', 'right': "write",
|
||||||
|
'type': "host", 'attrs': "userclass"},
|
||||||
|
{'name': 'Modify service managedBy attribute', 'right': "write",
|
||||||
|
'type': "service", 'attrs': "managedby"},
|
||||||
|
])
|
||||||
|
def test_permissions(host, perm):
|
||||||
|
result = host.check_output('ipa permission-find "{name}"'.format(**perm))
|
||||||
|
assert '1 permission matched' in result
|
||||||
|
assert 'Granted rights: {right}'.format(**perm) in result
|
||||||
|
assert 'Type: {type}'.format(**perm) in result
|
||||||
|
assert 'Effective attributes: {attrs}'.format(**perm) in result
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('pri', [
|
||||||
|
'Nova Host Management',
|
||||||
|
])
|
||||||
|
def test_privilages(host, pri):
|
||||||
|
result = host.check_output('ipa privilege-find "{}"'.format(pri))
|
||||||
|
assert '1 privilege matched' in result
|
||||||
|
assert 'Privilege name: {}'.format(pri) in result
|
||||||
|
assert 'Description: {}'.format(pri) in result
|
||||||
|
|
||||||
|
|
||||||
|
def test_privilege_permissions(host):
|
||||||
|
pri = 'Nova Host Management'
|
||||||
|
perms = [
|
||||||
|
'System: add hosts',
|
||||||
|
'System: remove hosts',
|
||||||
|
'Modify host password',
|
||||||
|
'Modify host userclass',
|
||||||
|
'System: Modify hosts',
|
||||||
|
'Modify service managedBy attribute',
|
||||||
|
'System: Add krbPrincipalName to a Host',
|
||||||
|
'System: Add Services',
|
||||||
|
'System: Remove Services',
|
||||||
|
'Revoke certificate',
|
||||||
|
'System: manage host keytab',
|
||||||
|
'System: Manage host certificates',
|
||||||
|
'System: modify services',
|
||||||
|
'System: manage service keytab',
|
||||||
|
'System: read dns entries',
|
||||||
|
'System: remove dns entries',
|
||||||
|
'System: add dns entries',
|
||||||
|
'System: update dns entries',
|
||||||
|
'Retrieve Certificates from the CA',
|
||||||
|
]
|
||||||
|
result = host.check_output('ipa privilege-show "{}"'.format(pri))
|
||||||
|
assert 'Privilege name: {}'.format(pri) in result
|
||||||
|
for perm in perms:
|
||||||
|
assert perm.lower() in result.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def test_role(host):
|
||||||
|
role = 'Nova Host Manager'
|
||||||
|
pri = 'Nova Host Management'
|
||||||
|
result = host.check_output('ipa role-show "{}"'.format(role))
|
||||||
|
assert 'Role name: {}'.format(role) in result
|
||||||
|
assert 'Description: {}'.format(role) in result
|
||||||
|
assert 'Privileges: {}'.format(pri) in result
|
||||||
|
assert 'nova/test-0.example.test@EXAMPLE.TEST' not in result
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('name', [
|
||||||
|
'test-0.example.test',
|
||||||
|
'test-0.ctlplane.example.test',
|
||||||
|
'test-0.external.example.test',
|
||||||
|
'test-0.internalapi.example.test',
|
||||||
|
'test-0.storage.example.test',
|
||||||
|
'test-0.storagemgmt.example.test',
|
||||||
|
])
|
||||||
|
def test_hosts(host, name):
|
||||||
|
host.run_expect([1], 'ipa host-find {}'.format(name))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('service, subhost', [
|
||||||
|
('HTTP', 'ctlplane'),
|
||||||
|
('HTTP', 'external'),
|
||||||
|
('HTTP', 'internalapi'),
|
||||||
|
('HTTP', 'storage'),
|
||||||
|
('HTTP', 'storagemgmt'),
|
||||||
|
('haproxy', 'ctlplane'),
|
||||||
|
('haproxy', 'internalapi'),
|
||||||
|
('haproxy', 'storage'),
|
||||||
|
('haproxy', 'storagemgmt'),
|
||||||
|
('libvirt-vnc', 'internalapi'),
|
||||||
|
('mysql', 'internalapi'),
|
||||||
|
('neutron_ovn', 'internalapi'),
|
||||||
|
('novnc-proxy', 'internalapi'),
|
||||||
|
('ovn_controller', 'internalapi'),
|
||||||
|
('ovn_dbs', 'internalapi'),
|
||||||
|
('rabbitmq', 'internalapi'),
|
||||||
|
('redis', 'internalapi'),
|
||||||
|
])
|
||||||
|
def test_services(host, service, subhost):
|
||||||
|
host.run_expect(
|
||||||
|
[2],
|
||||||
|
'ipa service-show {}/test-0.{}.example.test@EXAMPLE.TEST'.format(
|
||||||
|
service, subhost))
|
44
tripleo_ipa/roles/tripleo_ipa_cleanup/meta/main.yml
Normal file
44
tripleo_ipa/roles/tripleo_ipa_cleanup/meta/main.yml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
# Copyright 2020 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
galaxy_info:
|
||||||
|
author: OpenStack
|
||||||
|
description: TripleO OpenStack Role -- tripleo_ipa_cleanup
|
||||||
|
company: Red Hat
|
||||||
|
license: Apache-2.0
|
||||||
|
min_ansible_version: 2.7
|
||||||
|
#
|
||||||
|
# Provide a list of supported platforms, and for each platform a list of versions.
|
||||||
|
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
|
||||||
|
# To view available platforms and versions (or releases), visit:
|
||||||
|
# https://galaxy.ansible.com/api/v1/platforms/
|
||||||
|
#
|
||||||
|
platforms:
|
||||||
|
- name: Fedora
|
||||||
|
versions:
|
||||||
|
- 28
|
||||||
|
- name: CentOS
|
||||||
|
versions:
|
||||||
|
- 7
|
||||||
|
|
||||||
|
galaxy_tags:
|
||||||
|
- tripleo
|
||||||
|
|
||||||
|
|
||||||
|
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
||||||
|
# if you add dependencies to this list.
|
||||||
|
dependencies: []
|
29
tripleo_ipa/roles/tripleo_ipa_cleanup/tasks/main.yml
Normal file
29
tripleo_ipa/roles/tripleo_ipa_cleanup/tasks/main.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
# Copyright 2020 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
# This role removes a set of hosts and its required sub-hosts and services
|
||||||
|
# in FreeIPA
|
||||||
|
#
|
||||||
|
# The following variables are required:
|
||||||
|
# - tripleo_ipa_hosts_to_delete (list of FQDNs of hosts to delete)
|
||||||
|
# - tripleo_ipa_principal (principal to use when connecting to FreeIPA)
|
||||||
|
# - tripleo_ipa_keytab (file path to keytab to authenticate to FreeIPA)
|
||||||
|
|
||||||
|
- name: delete hosts, subhosts and services from freeIPA
|
||||||
|
cleanup_ipa_services:
|
||||||
|
principal: "{{ tripleo_ipa_principal }}"
|
||||||
|
keytab: "{{ tripleo_ipa_keytab }}"
|
||||||
|
hosts: "{{ tripleo_ipa_hosts_to_delete }}"
|
@ -12,5 +12,5 @@
|
|||||||
- zuul.d/playbooks/run.yml
|
- zuul.d/playbooks/run.yml
|
||||||
post-run:
|
post-run:
|
||||||
- zuul.d/playbooks/post.yml
|
- zuul.d/playbooks/post.yml
|
||||||
timeout: 1800
|
timeout: 3600
|
||||||
voting: true
|
voting: true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user