Remove the contents of the master branch

Since tripleo-ipa is used only in TripleO and it is no longer accepting
patches to its master branch, we are alse deprecating tripleo-ipa.
The master branch is deprecated, so we are removing the contents and
updating the README with information that code can still be submitted
to stable/wallaby branch.

Change-Id: I133796af25f2caed1df71a80b5cb107e801438d4
This commit is contained in:
Grzegorz Grasza 2023-04-27 16:44:12 +02:00
parent d48deac395
commit d17c95406e
65 changed files with 9 additions and 3736 deletions

7
.zuul.yaml Normal file
View File

@ -0,0 +1,7 @@
- project:
check:
jobs:
- noop
gate:
jobs:
- noop

View File

@ -4,26 +4,5 @@ tripleo-ipa
This repository contains Ansible for use integrating TripleO with FreeIPA.
Installation
============
.. code-block:: bash
$ pip install --prefix=/usr tripleo-ipa
Or, if you are installing from source, in the project directory:
.. code-block:: bash
$ python setup.py install --prefix=/usr
Contributing
============
You can create an environment to develop locally using the following.
.. code-block:: bash
$ python3.7 -m virtualenv --system-site-packages .venv
$ .venv/bin/pip3 install -r molecule-requirements.txt
Note that the master branch is deprecated, we still support the last release
in the stable/wallaby branch.

View File

@ -1,6 +0,0 @@
collections:
- containers.podman
- community.general
- ansible.posix
- ansible.netcommon
- openstack.cloud

View File

@ -1 +0,0 @@
ansible-core>=2.11,<2.12.0

View File

@ -1,42 +0,0 @@
# 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]
podman [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 !platform:rhel-9 !platform:centos-9 !platform:fedora]
python3-pyyaml [platform:rpm !platform:rhel-7 !platform:centos-7]
python3-dnf [platform:rpm !platform:rhel-7 !platform:centos-7]
# SELinux cent7
libselinux-python3 [platform:rpm !platform:rhel-8 !platform:centos-8]
libsemanage-python3 [platform:redhat !platform:rhel-8 !platform:centos-8]
# SELinux cent8
python3-libselinux [platform:rpm !platform:rhel-7 !platform:centos-7]
python3-libsemanage [platform:redhat !platform:rhel-7 !platform:centos-7]
# Required for compressing collected log files in CI
gzip
# Required to build language docs
gettext
# Install ansible-freeipa to default ansible path
ansible-freeipa [platform:redhat]

View File

@ -1,5 +0,0 @@
ansible-core>=2.11,<2.12.0
docker
molecule
molecule-podman
testinfra

View File

@ -1,71 +0,0 @@
---
# 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 playbook contains things you need if you want to run tripleo_ipa tests
# locally. Note that zuul sets some of this stuff up automatically, so we don't
# need to invoke this specifically for zuul.
- name: pre prepare
hosts: all
gather_facts: false
tasks:
- name: set basic user fact
fail:
msg: >-
The variable `ansible_user` set this option and try again. On the
CLI this can be defined with "-e ansible_user=${USER}"
when:
- ansible_user is undefined
- name: set basic home fact
fail:
msg: >-
The variable `ansible_user_dir` set this option and try again. On
the CLI this can be defined with "-e ansible_user_dir=${HOME}"
when:
- ansible_user_dir is undefined
- name: Ensure the user has a .ssh directory
file:
path: "{{ ansible_user_dir }}/.ssh"
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: "0700"
- name: Create ssh key pair
user:
name: "{{ ansible_user }}"
generate_ssh_key: true
ssh_key_bits: 2048
ssh_key_file: "{{ ansible_user_dir }}/.ssh/id_rsa"
- name: Slurp pub key
slurp:
src: "{{ ansible_user_dir ~ '/.ssh/id_rsa.pub' }}"
register: pub_key
- name: Ensure can ssh to can connect to localhost
authorized_key:
user: "{{ ansible_user }}"
key: "{{ pub_key['content'] | b64decode }}"
- name: Get the zuul/zuul-jobs repo
git:
repo: https://opendev.org/zuul/zuul-jobs
dest: "{{ ansible_user_dir }}/zuul-jobs"
version: master
force: true

View File

@ -1,3 +0,0 @@
six>=1.10.0 # MIT
PyYAML>=3.12 # MIT
netaddr>=0.7.18 # BSD

View File

@ -1,45 +0,0 @@
#!/usr/bin/env bash
# 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.
## Shell Opts ----------------------------------------------------------------
set -o pipefail
set -xeuo
## Vars ----------------------------------------------------------------------
export BINDEP_FILE="${BINDEP_FILE:-$(dirname $(readlink -f ${BASH_SOURCE[0]}))/../bindep.txt}"
## Main ----------------------------------------------------------------------
# Source distribution information
source /etc/os-release || source /usr/lib/os-release
RHT_PKG_MGR=$(command -v dnf || command -v yum)
# NOTE(cloudnull): Get a list of packages to install with bindep. If packages
# need to be installed, bindep exits with an exit code of 1.
BINDEP_PKGS=$(bindep -b -f "${BINDEP_FILE}" test || true)
if [[ ${#BINDEP_PKGS} > 0 ]]; then
case "${ID,,}" in
amzn|rhel|centos|fedora)
sudo "${RHT_PKG_MGR}" install -y ${BINDEP_PKGS}
;;
esac
fi

View File

@ -1,42 +0,0 @@
#!/usr/bin/env bash
# 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.
set -o pipefail
set -xeo
export ANSIBLE_ROLES_PATH="${ANSIBLE_ROLES_PATH}:${HOME}/zuul-jobs/roles"
export PROJECT_DIR="$(dirname $(readlink -f ${BASH_SOURCE[0]}))/../"
export UPPER_CONSTRAINTS_FILE=${UPPER_CONSTRAINTS_FILE:-"https://opendev.org/openstack/requirements/raw/branch/master/upper-constraints.txt"}
function run_pip {
"${HOME}/test-python/bin/pip" install \
-c "${UPPER_CONSTRAINTS_FILE}" \
-r "${PROJECT_DIR}/molecule-requirements.txt" ${@:-}
}
# Create a virtual environment and install dependencies
PYTHON_EXEC=$(command -v python3 || command -v python)
"${PYTHON_EXEC}" -m virtualenv --system-site-packages "${HOME}/test-python"
run_pip
ansible-playbook -i "${PROJECT_DIR}/tests/hosts.ini" \
-e "tripleo_src=$(realpath --relative-to="${HOME}" "${PROJECT_DIR}")" \
-e "ansible_user=${USER}" \
-e "ansible_user_dir=${HOME}" \
"${PROJECT_DIR}/playbooks/prepare-test-host.yml" \
"${PROJECT_DIR}/zuul.d/playbooks/run-local.yml"

View File

@ -1,32 +0,0 @@
[metadata]
name = tripleo-ipa
summary = Ansible assets for interacting with FreeIPA on behalf of TripleO
description-file =
README.rst
author = RedHat
home-page = https://opendev.org/x/tripleo-ipa
classifier =
License :: OSI Approved :: Apache Software License
Development Status :: 4 - Beta
Intended Audience :: Developers
Intended Audience :: System Administrators
Intended Audience :: Information Technology
Topic :: Utilities
[global]
setup-hooks =
pbr.hooks.setup_hook
[files]
data_files =
share/ansible/tripleo-playbooks/ = tripleo_ipa/playbooks/*
share/ansible/plugins/ = tripleo_ipa/ansible_plugins/*
share/ansible/roles/ = tripleo_ipa/roles/*
[wheel]
universal = 1
[pbr]
skip_authors = True
skip_changelog = True

View File

@ -1,20 +0,0 @@
# Copyright 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.
import setuptools
setuptools.setup(
setup_requires=['pbr'],
py_modules=[],
pbr=True)

View File

@ -1,10 +0,0 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
ansible-lint # MIT
pre-commit # MIT
mock>=2.0.0 # BSD
stestr>=2.0.0 # Apache-2.0
oslotest>=3.2.0 # Apache-2.0
yamllint

View File

@ -1 +0,0 @@
test ansible_connection=local ansible_host=localhost

63
tox.ini
View File

@ -1,63 +0,0 @@
[tox]
basepython = python3
minversion = 2.0
# add docs to the list of environments once we actually have docs to generate
envlist = py3,pep8,molecule,linters
skipsdist = True
[testenv]
usedevelop = True
install_command = pip install {opts} {packages}
passenv = *
sitepackages = True
deps =
-r {toxinidir}/requirements.txt
-r {toxinidir}/ansible-requirements.txt
-r {toxinidir}/test-requirements.txt
commands =
ansible-galaxy install -fr {toxinidir}/ansible-collections-requirements.yml
stestr run {posargs}
whitelist_externals =
tox
[testenv:molecule]
install_command = pip install {opts} {packages}
setenv =
ANSIBLE_FILTER_PLUGINS=~/.ansible/plugins/filter:/usr/share/ansible/plugins/filter:{toxinidir}/tripleo_ipa/ansible_plugins/filter
ANSIBLE_LIBRARY=~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules:{toxinidir}/tripleo_ipa/ansible_plugins/modules
ANSIBLE_ROLES_PATH=~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:{toxinidir}/tripleo_ipa/roles
deps =
-r {toxinidir}/requirements.txt
-r {toxinidir}/molecule-requirements.txt
changedir = {toxinidir}/tripleo_ipa
commands =
ansible-galaxy install -fr {toxinidir}/ansible-collections-requirements.yml
molecule test --all
[testenv:ansible-lint]
deps = {[testenv:linters]deps}
commands =
ansible-galaxy install -fr {toxinidir}/ansible-collections-requirements.yml
ansible-lint -c .ansible-lint {toxinidir}/tripleo_ipa
[testenv:yamllint]
deps = {[testenv:linters]deps}
commands =
yamllint -c {toxinidir}/tripleo_ipa/.yamllint {toxinidir}/tripleo_ipa
[testenv:linters]
setenv =
ANSIBLE_FILTER_PLUGINS=~/.ansible/plugins/filter:/usr/share/ansible/plugins/filter:{toxinidir}/tripleo_ipa/ansible_plugins/filter
ANSIBLE_LIBRARY=~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules:{toxinidir}/tripleo_ipa/ansible_plugins/modules
ANSIBLE_ROLES_PATH=~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:{toxinidir}/tripleo_ipa/roles
deps =
-r {toxinidir}/ansible-requirements.txt
-r {toxinidir}/test-requirements.txt
commands =
{[testenv:ansible-lint]commands}
{[testenv:yamllint]commands}
[testenv:pep8]
envdir = {toxworkdir}/linters
commands =
python -m pre_commit run flake8 -a

View File

@ -1,33 +0,0 @@
---
# Based on ansible-lint config
extends: default
rules:
braces:
max-spaces-inside: 1
level: error
brackets:
max-spaces-inside: 1
level: error
colons:
max-spaces-after: -1
level: error
commas:
max-spaces-after: -1
level: error
comments: disable
comments-indentation: disable
document-start: disable
empty-lines:
max: 3
level: error
hyphens:
level: error
indentation: disable
key-duplicates: enable
line-length: disable
new-line-at-end-of-file: disable
new-lines:
type: unix
trailing-spaces: disable
truthy: disable

View File

@ -1,38 +0,0 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
Apache 2.0
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View File

@ -1,82 +0,0 @@
#!/usr/bin/python
#
# 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.
def parse_service_metadata(service_metadata, host_fqdn):
"""Extract managed services from a dictionary of metadata
This filter is useful for parsing server metadata that is loaded on to
instances and describes the services that instance will host. The metadata
is written to disk as JSON on the instance, but this filter expects a
dictionary. You can invoke the filter with the following:
{{ server_metadata | from_json | parse_service_metadata(host_fqdn) }}
This filter is useful for dynamically creating service principals in
FreeIPA for services running on a specific host, which we can later use to
generate TLS certificates. For example:
- name: parse metadata for services
include: register_services.yaml
loop: {{ metadata | from_json | parse_service_metadata(host_fqdn) }}
register_services.yaml
---
- name: add sub-host in FreeIPA
ipa_host:
fqdn: {{ item.0 }}
state: present
- name: add service to FreeIPA
ipa_service:
name: "{{ item.1 }}/{{ sub_host }} "
state: present
:param service_metadata: is a dictionary where keys are strings that
describe the service. The value can be either a
list of networks (compact notation) or a string
that represents the service and principal (managed
notation).
:param host_fqdn: is a string that represents the fully-qualified hostname
of the host we're processing metadata for (e.g.,
'controller-0.example.test')
:returns: a list of tuples where the first element of the tuple is the
fully-qualified domain name of the service (e.g.,
'controller-0.external.example.test') and the second element is
the service (e.g., 'haproxy').
"""
hostname = host_fqdn.split('.')[0]
domain = host_fqdn.split('.', 1)[1]
managed_services = set()
for service_key in service_metadata.keys():
if service_key.startswith('managed_service_'):
principal = service_metadata[service_key]
service_name, service_hostname = principal.split('/', 2)
managed_services.add((service_hostname, service_name))
elif service_key.startswith('compact_service_'):
interfaces = service_metadata[service_key]
service_name = service_key.split('_', 2)[-1]
for interface in interfaces:
service_hostname = '.'.join([hostname, interface, domain])
managed_services.add((service_hostname, service_name))
return list(managed_services)
class FilterModule(object):
def filters(self):
return {'parse_service_metadata': parse_service_metadata}

View File

@ -1,410 +0,0 @@
#!/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 six.moves.configparser import SafeConfigParser
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_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec
from ansible_collections.openstack.cloud.plugins.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:
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:
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):
self.ntries = 5
self.retry_delay = 2
self.keytab = keytab
if self._ipa_client_configured() and not api.isdone('finalize'):
self.ccache = "MEMORY:" + str(uuid.uuid4())
os.environ['KRB5CCNAME'] = self.ccache
(hostname, realm) = self.get_host_and_realm()
kinit_keytab(str('nova/%s@%s' % (hostname, realm)),
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_host_and_realm(self):
"""Return the hostname and IPA realm name."""
config = SafeConfigParser()
config.read('/etc/ipa/default.conf')
hostname = config.get('global', 'host')
realm = config.get('global', 'realm')
return (hostname, realm)
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, hosts):
ipa = IPAClient(keytab)
hosts_to_delete = set()
for host in hosts:
if six.PY3:
hostname = host
else:
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')
hosts = module.params.get('hosts')
cleanup_ipa_services(keytab, hosts)
module.exit_json(changed=True)
except Exception as err:
module.fail_json(msg=str(err))
def main():
run_module()
if __name__ == '__main__':
main()

View File

@ -1,37 +0,0 @@
# Molecule managed
# 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.
{% 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 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 pip install {{ pkg }}
{% endfor %}
CMD ["/sbin/init"]

View File

@ -1,22 +0,0 @@
*******
Podman driver installation guide
*******
Requirements
============
* Podman
Install
=======
Please refer to the `Virtual environment`_ documentation for installation best
practices. If not using a virtual environment, please consider passing the
widely recommended `'--user' flag`_ when invoking ``pip``.
.. _Virtual environment: https://virtualenv.pypa.io/en/latest/
.. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site
.. code-block:: bash
$ pip install 'molecule[podman]'

View File

@ -1,244 +0,0 @@
---
# 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.
- name: Setup server
hosts: centos9
vars:
ipa_domain: example.test
ipa_server_ip: 10.88.0.22
ipa_server_user: admin
ipa_server_password: password123
ipa_server_hostname: ipa.example.test
undercloud_fqdn: test-0.example.test
tasks:
- 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: check FreeIPA LDAP port is open
wait_for:
host=ipa.example.test
port=389
delay=1
timeout=300
ignore_errors: true
- 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: Setup dummy server
hosts: centos9-dummy
vars:
ipa_domain: example.test
ipa_server_ip: 10.88.0.22
ipa_server_user: admin
ipa_server_password: password123
ipa_server_hostname: ipa.example.test
undercloud_fqdn: dummy.example.test
tasks:
- 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 dummy.example.test dummy 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 --debug
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: centos9
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 - add dns entries
hosts: centos9
vars:
cloud_domain: ooo.test
hosts_entry:
- 2001:0db8:85a3:0000:0000:8a2e:0370:7334 foo.ooo.test
- 2001:0db8:85a3:0000:0000:8a2e:0370:7333 foo.ooo.test
- 2001:0db8:85a3:0000:0000:8a2e:0370:7333 bar.ooo.test
- 192.168.24.111 bar.ooo.test
- 192.168.24.10 baz
- 192.168.24.11 baz.different.domain
- 192.168.24.1 undercloud.ctlplane.ooo.test undercloud.ctlplane
- 192.168.24.115 overcloud.ctlplane.ooo.test
- 10.0.0.135 overcloud.ooo.test
- 172.17.0.15 overcloud.internalapi.ooo.test
- 172.18.0.231 overcloud.storage.ooo.test
- 172.19.0.164 overcloud.storagemgmt.ooo.test
- 172.17.0.46 overcloud-controller-0.ooo.test overcloud-controller-0
- 10.0.0.116 overcloud-controller-0.external.ooo.test overcloud-controller-0.external
- 172.17.0.46 overcloud-controller-0.internalapi.ooo.test overcloud-controller-0.internalapi
- 172.18.0.185 overcloud-controller-0.storage.ooo.test overcloud-controller-0.storage
- 172.19.0.107 overcloud-controller-0.storagemgmt.ooo.test overcloud-controller-0.storagemgmt
- 172.16.0.72 overcloud-controller-0.tenant.ooo.test overcloud-controller-0.tenant
- 192.168.24.122 overcloud-controller-0.ctlplane.ooo.test overcloud-controller-0.ctlplane
- 172.17.0.110 overcloud-novacompute-0.ooo.test overcloud-novacompute-0
- 172.17.0.110 overcloud-novacompute-0.internalapi.ooo.test overcloud-novacompute-0.internalapi
- 172.18.0.243 overcloud-novacompute-0.storage.ooo.test overcloud-novacompute-0.storage
- 172.16.0.195 overcloud-novacompute-0.tenant.ooo.test overcloud-novacompute-0.tenant
- 192.168.24.128 overcloud-novacompute-0.ctlplane.ooo.test overcloud-novacompute-0.ctlplane
roles:
- name: tripleo_ipa_dns
environment:
IPA_USER: admin
IPA_HOST: ipa.example.test
IPA_PASS: password123

View File

@ -1,75 +0,0 @@
---
driver:
name: podman
log: true
platforms:
- name: centos9
hostname: test-0.example.test
image: centos/centos:stream9
registry:
url: quay.io
command: /sbin/init
pkg_extras: systemd ipa-client pip
easy_install:
- urllib_gssapi
tmpfs:
- /run
- /tmp
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
- /etc/pki/rpm-gpg:/etc/pki/rpm-gpg
dockerfile: Dockerfile
network_mode: host
environment: &env
http_proxy: "{{ lookup('env', 'http_proxy') }}"
https_proxy: "{{ lookup('env', 'https_proxy') }}"
- name: centos9-dummy
hostname: dummy.example.test
image: centos/centos:stream9
registry:
url: quay.io
command: /sbin/init
pkg_extras: systemd ipa-client pip
easy_install:
- urllib_gssapi
tmpfs:
- /run
- /tmp
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
- /etc/pki/rpm-gpg:/etc/pki/rpm-gpg
dockerfile: Dockerfile
network_mode: host
environment: *env
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}"
inventory:
hosts:
all:
hosts:
centos9:
ansible_python_interpreter: /usr/bin/python3
centos9-dummy:
ansible_python_interpreter: /usr/bin/python3
scenario:
test_sequence:
- destroy
- create
- prepare
- converge
- verify
- destroy
verifier:
name: testinfra

View File

@ -1,109 +0,0 @@
---
# 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
containers.podman.podman_image:
name: quay.io/freeipa/freeipa-server:fedora-36
pull: true
become: true
- name: Make IPA data dir
ansible.builtin.file:
path: /tmp/ipa-data
state: directory
- name: Toggle SELinux boolean
ansible.posix.seboolean:
name: container_manage_cgroup
state: true
persistent: true
become: true
- name: Remove any old IPA container
containers.podman.podman_container:
name: freeipa-server-container
state: absent
become: true
- name: Get configuration from NetworkManager
command: nmcli device show
register: nmcli_device_show
- name: Configure FreeIPA
shell: >
sudo podman run -d --name freeipa-server-container
--sysctl net.ipv6.conf.lo.disable_ipv6=0
--security-opt seccomp=unconfined
--ip 10.88.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-36 no-exit
-U -r {{ domain | upper }} --setup-dns --no-reverse --no-ntp
--no-dnssec-validation
--forwarder={{ nameservers[0] | default('8.8.8.8') }}
vars:
nameservers: "{{ nmcli_device_show.stdout | regex_findall('\\s*IP4.DNS\\[.\\]:\\s*(.*)') }}"
- block:
- 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
rescue:
- name: Get the last lines from IPA install
command: tail -50 /tmp/ipa-data/var/log/ipaserver-install.log
become: true
register: file_log
- name: Print info
debug:
msg: "{{ file_log.stdout }}"
- name: Fail task if timeout reached
fail:
msg: "Timeout of IPA server installation has been reached"
- name: Wait for FreeIPA LDAP port to open
wait_for:
host=10.88.0.22
port=389
delay=1
timeout=300
ignore_errors: true
- name: Check the status of ipactl to make sure all services are started
command: "sudo podman exec freeipa-server-container ipactl status"
retries: 10
delay: 3
register: result
until: result.rc == 0
- name: Print ipactl status
debug:
msg: "{{ result.stdout }}"

View File

@ -1,254 +0,0 @@
import ipaddress
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('centos9')
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('pkg', [
'ipa-client',
])
def test_pkg(host, pkg):
package = host.package(pkg)
assert package.is_installed
@pytest.mark.parametrize('svc', [
'dbus',
'sssd',
])
def test_svc(host, svc):
service = host.service(svc)
assert service.is_running
assert service.is_enabled
@pytest.mark.parametrize('file, content', [
("/etc/ipa/default.conf", "ipa.example.test"),
("/etc/hosts", "test-0.example.test"),
("/etc/resolv.conf", "10.88.0.22"),
("/etc/novajoin/krb5.keytab", "test-0.example.test"),
])
def test_files(host, file, content):
file = host.file(file)
assert file.exists
assert file.contains(content)
@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 'Member services: nova/test-0.example.test@EXAMPLE.TEST, nova/dummy.example.test@EXAMPLE.TEST' 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):
result = host.check_output('ipa host-find {}'.format(name))
assert '1 host matched' in result
@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):
result = host.check_output(
'ipa service-show {}/test-0.{}.example.test@EXAMPLE.TEST'.format(
service, subhost))
assert 'Principal name: {}/test-0.{}.example.test@EXAMPLE.TEST'.format(
service, subhost) in result
assert 'Principal alias: {}/test-0.{}.example.test@EXAMPLE.TEST'.format(
service, subhost) in result
'Roles: Nova Host Manager' in result
assert 'Managed by: test-0.{}.example.test, test-0.example.test'.format(
subhost) in result
@pytest.mark.parametrize('ip, name', [
('2001:0db8:85a3:0000:0000:8a2e:0370:7333', 'foo'),
('2001:0db8:85a3:0000:0000:8a2e:0370:7333', 'bar'),
('192.168.24.111', 'bar'),
('192.168.24.1', 'undercloud.ctlplane'),
('192.168.24.115', 'overcloud.ctlplane'),
('10.0.0.135', 'overcloud'),
('172.17.0.15', 'overcloud.internalapi'),
('172.18.0.231', 'overcloud.storage'),
('172.19.0.164', 'overcloud.storagemgmt'),
('172.17.0.46', 'overcloud-controller-0'),
('10.0.0.116', 'overcloud-controller-0.external'),
('172.17.0.46', 'overcloud-controller-0.internalapi'),
('172.18.0.185', 'overcloud-controller-0.storage'),
('172.19.0.107', 'overcloud-controller-0.storagemgmt'),
('172.16.0.72', 'overcloud-controller-0.tenant'),
('192.168.24.122', 'overcloud-controller-0.ctlplane'),
('172.17.0.110', 'overcloud-novacompute-0'),
('172.17.0.110', 'overcloud-novacompute-0.internalapi'),
('172.18.0.243', 'overcloud-novacompute-0.storage'),
('172.16.0.195', 'overcloud-novacompute-0.tenant'),
('192.168.24.128', 'overcloud-novacompute-0.ctlplane')])
def test_dns(host, ip, name):
name += '.ooo.test'
record_name, zone_name = name.split('.', 1)
result = host.check_output(
'ipa dnsrecord-find {} --name={}'.format(
zone_name, record_name))
assert 'record: {}'.format(ip) in result
@pytest.mark.parametrize('ip, name', [
('192.168.24.10', '.baz'),
('192.168.24.11', 'baz.different.domain'),
])
def test_dns_absent(host, ip, name):
record_name, zone_name = name.split('.', 1)
host.run_expect(
[1, 2], 'ipa dnsrecord-find {} --name={}'.format(
zone_name, record_name))
@pytest.mark.parametrize('ip, name', [
('2001:0db8:85a3:0000:0000:8a2e:0370:7334', 'foo'),
('2001:0db8:85a3:0000:0000:8a2e:0370:7333', 'bar'),
('192.168.24.111', 'bar'),
('192.168.24.1', 'undercloud.ctlplane'),
('192.168.24.115', 'overcloud.ctlplane'),
('10.0.0.135', 'overcloud'),
('172.17.0.15', 'overcloud.internalapi'),
('172.18.0.231', 'overcloud.storage'),
('172.19.0.164', 'overcloud.storagemgmt'),
('172.17.0.46', 'overcloud-controller-0'),
('10.0.0.116', 'overcloud-controller-0.external'),
('172.17.0.46', 'overcloud-controller-0.internalapi'),
('172.18.0.185', 'overcloud-controller-0.storage'),
('172.19.0.107', 'overcloud-controller-0.storagemgmt'),
('172.16.0.72', 'overcloud-controller-0.tenant'),
('192.168.24.122', 'overcloud-controller-0.ctlplane'),
('172.17.0.110', 'overcloud-novacompute-0'),
('172.17.0.110', 'overcloud-novacompute-0.internalapi'),
('172.18.0.243', 'overcloud-novacompute-0.storage'),
('172.16.0.195', 'overcloud-novacompute-0.tenant'),
('192.168.24.128', 'overcloud-novacompute-0.ctlplane')])
def test_reverse_dns(host, ip, name):
reverse = ipaddress.ip_address(ip).reverse_pointer
record, zone = reverse.split('.', 1)
result = host.check_output(
'ipa dnsrecord-find {} --name={}'.format(
zone, record))
assert 'record: {}'.format(name) in result
@pytest.mark.parametrize('ip, name', [
('192.168.24.10', '.baz'),
('192.168.24.11', 'baz.different.domain'),
])
def test_reverse_dns_absent(host, ip, name):
reverse = ipaddress.ip_address(ip).reverse_pointer
record, zone = reverse.split('.', 1)
host.run_expect(
[1, 2], 'ipa dnsrecord-find {} --name={}'.format(
zone, record))

View File

@ -1,9 +0,0 @@
---
# This is an example playbook to execute Ansible tests.
- name: Verify
hosts: centos9
tasks:
- name: Example assertion
assert:
that: true

View File

@ -1,37 +0,0 @@
# 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 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 pip install {{ pkg }}
{% endfor %}
CMD ["/sbin/init"]

View File

@ -1,264 +0,0 @@
---
# 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: 10.88.0.22
ipa_server_user: admin
ipa_server_password: password123
ipa_server_hostname: ipa.example.test
undercloud_fqdn: test-0.example.test
tasks:
- 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-1.example.test test-1 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 for test-1 host
hosts: all
vars:
tripleo_ipa_enroll_base_server: true
tripleo_ipa_base_server_fqdn: test-1.example.test
tripleo_ipa_base_server_short_name: test-1
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/overcloud.ctlplane.example.test",
"managed_service_haproxyexternal": "haproxy/overcloud.example.test",
"managed_service_haproxyinternal_api": "haproxy/overcloud.internalapi.example.test",
"managed_service_haproxystorage": "haproxy/overcloud.storage.example.test",
"managed_service_haproxystorage_mgmt": "haproxy/overcloud.storagemgmt.example.test",
"managed_service_mysqlinternal_api": "mysql/overcloud.internalapi.example.test",
"managed_service_ovn_dbsinternal_api": "ovn_dbs/overcloud.internalapi.example.test",
"managed_service_redisinternal_api": "redis/overcloud.internalapi.example.test"
}
roles:
- name: tripleo_ipa_registration
environment:
IPA_USER: admin
IPA_HOST: ipa.example.test
IPA_PASS: password123
- name: Converge - add host and relevant services for test-2 host
hosts: all
vars:
tripleo_ipa_enroll_base_server: true
tripleo_ipa_base_server_fqdn: test-2.example.test
tripleo_ipa_base_server_short_name: test-2
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/overcloud.ctlplane.example.test",
"managed_service_haproxyexternal": "haproxy/overcloud.example.test",
"managed_service_haproxyinternal_api": "haproxy/overcloud.internalapi.example.test",
"managed_service_haproxystorage": "haproxy/overcloud.storage.example.test",
"managed_service_haproxystorage_mgmt": "haproxy/overcloud.storagemgmt.example.test",
"managed_service_mysqlinternal_api": "mysql/overcloud.internalapi.example.test",
"managed_service_ovn_dbsinternal_api": "ovn_dbs/overcloud.internalapi.example.test",
"managed_service_redisinternal_api": "redis/overcloud.internalapi.example.test"
}
roles:
- name: tripleo_ipa_registration
environment:
IPA_USER: admin
IPA_HOST: ipa.example.test
IPA_PASS: password123
- name: Simulate bad enrollment for test-3 host
hosts: all
vars:
ipa_server_user: admin
ipa_server_password: password123
ipa_server_hostname: ipa.example.test
tasks:
# We do this to simulate a bad enrollment. If the host has already been
# added, but isn't enrolled we need to recreate the host during
# tripleo_ipa_registration. Add this host shouldn't cause the
# tripleo_ipa_registration role to fail. It should handle it gracefully.
# This host isn't enrolled and doesn't have a keytab associated to it
# because it's disabled.
- name: create a pre-existing host test-3
ipa_host:
fqdn: 'test-3.example.test'
force: true
ipa_user: "{{ ipa_server_user }}"
ipa_pass: "{{ ipa_server_password }}"
ipa_host: "{{ ipa_server_hostname }}"
- name: Converge - add host and relevant services for test-3 host
hosts: all
vars:
tripleo_ipa_enroll_base_server: true
tripleo_ipa_base_server_fqdn: test-3.example.test
tripleo_ipa_base_server_short_name: test-3
tripleo_ipa_base_server_domain: example.test
tripleo_ipa_delegate_server: localhost
tripleo_ipa_server_metadata: |
{
"compact_service_libvirt": [
"internalapi"
],
"compact_service_libvirt-vnc": [
"internalapi"
],
"compact_service_ovn_controller": [
"internalapi"
],
"compact_service_ovn_metadata": [
"internalapi"
],
"compact_service_qemu": [
"internalapi"
]
}
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_hostname: ipa.example.test
tasks:
- name: Include IPA Cleanup
include_role:
name: tripleo_ipa_cleanup
vars:
tripleo_ipa_hosts_to_delete: ['test-1.example.test']
tripleo_ipa_keytab: "/etc/novajoin/krb5.keytab"

View File

@ -1,54 +0,0 @@
---
driver:
name: podman
log: true
platforms:
- name: centos9
hostname: test-0.example.test
image: centos/centos:stream9
registry:
url: quay.io
command: /sbin/init
pkg_extras: systemd ipa-client pip
easy_install:
- urllib_gssapi
tmpfs:
- /run
- /tmp
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
- /etc/pki/rpm-gpg:/etc/pki/rpm-gpg
dockerfile: Dockerfile
network_mode: host
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}"
inventory:
hosts:
all:
hosts:
centos9:
ansible_python_interpreter: /usr/bin/python3
scenario:
test_sequence:
- destroy
- create
- prepare
- converge
- verify
- destroy
verifier:
name: testinfra

View File

@ -1,76 +0,0 @@
---
# 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
containers.podman.podman_image:
name: quay.io/freeipa/freeipa-server:fedora-36
pull: true
become: true
- name: Make IPA data dir
ansible.builtin.file:
path: /tmp/ipa-data
state: directory
- name: Toggle SELinux boolean
ansible.posix.seboolean:
name: container_manage_cgroup
state: true
persistent: true
become: true
- name: Remove any old IPA container
containers.podman.podman_container:
name: freeipa-server-container
state: absent
become: true
- name: Get configuration from NetworkManager
command: nmcli device show
register: nmcli_device_show
- name: Configure FreeIPA
shell: >
sudo podman run -d --name freeipa-server-container
--sysctl net.ipv6.conf.lo.disable_ipv6=0
--security-opt seccomp=unconfined
--ip 10.88.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-36 exit-on-finished
-U -r {{ domain | upper }} --setup-dns --no-reverse --no-ntp
--no-dnssec-validation
--forwarder={{ nameservers[0] | default('8.8.8.8') }}
vars:
nameservers: "{{ nmcli_device_show.stdout | regex_findall('\\s*IP4.DNS\\[.\\]:\\s*(.*)') }}"
- 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

View File

@ -1,125 +0,0 @@
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('name', [
'overcloud.example.test',
'overcloud.ctlplane.example.test',
'overcloud.internalapi.example.test',
'overcloud.storage.example.test',
'overcloud.storagemgmt.example.test',
])
def test_hosts_created(host, name):
result = host.check_output('ipa host-find {}'.format(name))
assert '1 host matched' in result
@pytest.mark.parametrize('name', [
'test-1.example.test',
'test-1.ctlplane.example.test',
'test-1.external.example.test',
'test-1.internalapi.example.test',
'test-1.storage.example.test',
'test-1.storagemgmt.example.test',
])
def test_hosts_deleted(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_services1(host, service, subhost):
host.run_expect(
[2],
'ipa service-show {}/test-1.{}.example.test@EXAMPLE.TEST'.format(
service, subhost))
@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_services2(host, service, subhost):
result = host.check_output(
'ipa service-show {}/test-2.{}.example.test@EXAMPLE.TEST'.format(
service, subhost))
assert 'Principal name: {}/test-2.{}.example.test@EXAMPLE.TEST'.format(
service, subhost) in result
assert 'Principal alias: {}/test-2.{}.example.test@EXAMPLE.TEST'.format(
service, subhost) in result
'Roles: Nova Host Manager' in result
assert 'Managed by: test-2.{}.example.test, test-2.example.test'.format(
subhost) in result
@pytest.mark.parametrize('service, subhost', [
('libvirt', 'internalapi'),
('libvirt-vnc', 'internalapi'),
('ovn_controller', 'internalapi'),
('ovn_metadata', 'internalapi'),
('qemu', 'internalapi'),
])
def test_services3(host, service, subhost):
result = host.check_output(
'ipa service-show {}/test-3.{}.example.test@EXAMPLE.TEST'.format(
service, subhost))
assert 'Principal name: {}/test-3.{}.example.test@EXAMPLE.TEST'.format(
service, subhost) in result
assert 'Principal alias: {}/test-3.{}.example.test@EXAMPLE.TEST'.format(
service, subhost) in result
'Roles: Nova Host Manager' in result
assert 'Managed by: test-3.{}.example.test, test-3.example.test'.format(
subhost) in result

View File

@ -1,59 +0,0 @@
# TLS-e IPA Server Configuration Roles
## Included Roles
This directory includes 3 playbooks (`ipa-server-*.yaml`) to be used for the TripleO TLS-e configuration of a FreeIPA server. The playbooks need to be run in the order that follows, however certain playbooks only need to be run once per IPA server:
---
1. `ipa-sever-create-role.yaml` The purpose of this playbook is to create a role on the IPA server with the appropriate permissions and privileges to add and remove hosts, principals, services and dns entries.
> Currently this playbook is required to be executed on an IPA client host with an active Kerberos token.
> This playbook only needs to be run once per IPA server.
---
2. `ipa-server-register-undercloud.yaml` This playbook registers the undercloud host as an IPA client and provides a one time password(OTP) to the operator for use in the undercloud configuration. An example of the final output of a successful run of this play will look like this:
```
TASK [provide OTP generated by IPA server] ****************************
ok: [localhost] => {
"msg": [
"The OTP provided by the IPA server is 9Ok~JEz!ul;&Sf:V<FOi-+",
"Please add the following to your undercloud.conf:",
"ipa_otp = 9Ok~JEz!ul;&Sf:V<FOi-+"
]
}
```
If you're including this playbook via another ansible execution, you can fetch
the one-time password via the ``tripleo_ipa_host_otp`` variable.
> This playbook does not require an active Kerberos token.
> This playbook needs to be run once per openstack deployment.
---
3. `ipa-server-create-principal.yaml` This playbook creates the nova user for the undercloud host created with `ipa-register-undercloud.yaml` and adds it to the Nova Host Manager IPA role created by `ipa-server-create-role.yaml`.
> This playbook does not require an active Kerberos token.
> This playbook needs to be run once per openstack deployment.
---
## Environment/Ansible variables
The playbooks currently require the following variables to be set. These can either be environment variables or ansible variables passed either in a file or on the command line with the `-e` argument to the `ansible-playbook` command.
### `ENVIRONMENT/ansible` variable
* `tripleo_ipa_host` this is the host which ansible will connect to for playbook execution, this is the host that needs to be an IPA client. Defaults to `localhost`.
* `IPA_PRINCIPAL/tripleo_ipa_principal` is the IPA username with appropriate permissions and privileges to add roles and privileges. This value is required and has no default.
* `IPA_PASSWORD/tripleo_ipa_password` is the password for the IPA_PRINCIPAL. This value is required and has no default.
* `UNDERCLOUD_FQDN/tripleo_undercloud_fqdn` is the fully qualified domain name of the undercloud host. This value is required and has no default.
#### Example environment variables
```bash
export IPA_PRINCIPAL=admin
export IPA_PASSWORD=password
export UNDERCLOUD_FQDN=undercloud.ooo.test
```
#### Example ansible variables file
```yaml
---
tripleo_ipa_principal: admin
tripleo_ipa_password: password
tripleo_undercloud_fqdn: undercloud.ooo.test
```

View File

@ -1,69 +0,0 @@
---
# 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 playbook is used to clean up any host and service entries in IPA
# when a stack is deleted. It should be run on the undercloud against the
# inventory generated by tripleo-ansible-inventory.
#
# In particular, we expect the node on which this playbook is run to be an
# IPA client and to have a valid keytab
- name: delete ipa entries for overcloud nodes
connection: "{{ (tripleo_target_host is defined) | ternary('ssh', 'local') }}"
hosts: "{{ tripleo_target_host | default('localhost') }}"
remote_user: "{{ tripleo_target_user | default(lookup('env', 'USER')) }}"
gather_facts: "{{ (tripleo_target_host is defined) | ternary(true, false) }}"
any_errors_fatal: true
pre_tasks:
- name: Check if undercloud is an ipa client
stat:
path: /etc/ipa/default.conf
register: default_conf_stat
- name: End play if undercloud is not an ipa client
meta: end_host
when:
- not default_conf_stat.stat.exists
- name: Get realm and host and keytab
set_fact:
ipa_keytab: "{{ ipa_keytab | default('/etc/novajoin/krb5.keytab') }}"
- name: check if keytab exists
stat:
path: "{{ ipa_keytab }}"
register: ipa_keytab_stat
- name: End play if the keytab does not exist
meta: end_host
when:
- not ipa_keytab_stat.stat.exists
tasks:
- name: initialize the list of hosts to clean up
set_fact:
hosts_list: []
- name: create list of hosts to clean up in IPA
set_fact:
hosts_list: "{{ groups.allovercloud | map('extract', hostvars, 'canonical_hostname') | list }}"
- name: import cleanup tasks from the tripleo-ipa role
include_role:
name: tripleo_ipa_cleanup
vars:
tripleo_ipa_keytab: "{{ ipa_keytab }}"
tripleo_ipa_hosts_to_delete: "{{ hosts_list }}"

View File

@ -1,68 +0,0 @@
---
# 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 playbook creates the nova user and adds it to the Nova Host Manager IPA
# role. This needs to be executed by a user that has permissions to add services
# and to add them to roles. This needs to be run once per openstack deployment.
- name: Playbook to setup a principal for use with tripleo-ipa
connection: "{{ (tripleo_ipa_host is defined) | ternary('ssh', 'local') }}"
hosts: "{{ tripleo_ipa_host | default('localhost') }}"
tasks:
- name: ensure definitions
fail:
msg: >-
{{ item }} is undefined
when: not item.ansible_var and not item.env_var
with_items:
- name: ipa_principal
ansible_var: "{{ ipa_principal | default('') }}"
env_var: "{{ lookup('env', 'IPA_PRINCIPAL') }}"
- name: ipa_password
ansible_var: "{{ ipa_password | default('') }}"
env_var: "{{ lookup('env', 'IPA_PASSWORD') }}"
- name: undercloud_fqdn
ansible_var: "{{ tripleo_undercloud_fqdn | default('') }}"
env_var: "{{ lookup('env', 'UNDERCLOUD_FQDN') }}"
- name: set IPA server facts
set_fact:
ipa_principal: "{{ tripleo_ipa_principal | default(lookup('env', 'IPA_PRINCIPAL')) }}"
ipa_password: "{{ tripleo_ipa_password | default(lookup('env', 'IPA_PASSWORD')) }}"
undercloud_fqdn: "{{ tripleo_undercloud_fqdn | default(lookup('env', 'UNDERCLOUD_FQDN')) }}"
- name: set nova service user facts
set_fact:
nova_service: "nova/{{ undercloud_fqdn }}"
- name: add nova service
ipa_service:
name: "{{ nova_service }}"
ipa_user: "{{ ipa_principal }}"
ipa_pass: "{{ ipa_password }}"
state: present
force: true
- name: add nova host manager role
ipa_role:
name: Nova Host Manager
ipa_user: "{{ ipa_principal }}"
ipa_pass: "{{ ipa_password }}"
description: Nova Host Manager
privilege:
- Nova Host Management
service:
- "{{ nova_service }}"

View File

@ -1,52 +0,0 @@
---
# 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 playbook adds a role with the correct privileges needed by tripleo-ipa
# and TLS-e to add hosts and services to the IPA server. The operations in
# this playbook likely need admin privileges and should be executed on an
# IPA client. This playbook only needs to be run once per IPA server as
# multiple tripleo deployments can utilize the same role.
- name: Playbook to setup an IPA role with correct privileges for TLS-e
connection: "{{ (tripleo_ipa_host is defined) | ternary('ssh', 'local') }}"
hosts: "{{ tripleo_ipa_host | default('localhost') }}"
tasks:
- name: ensure definitions
fail:
msg: >-
{{ item }} is undefined
when: not item.ansible_var and not item.env_var
with_items:
- name: ipa_principal
ansible_var: "{{ ipa_principal | default('') }}"
env_var: "{{ lookup('env', 'IPA_PRINCIPAL') }}"
- name: ipa_password
ansible_var: "{{ ipa_password | default('') }}"
env_var: "{{ lookup('env', 'IPA_PASSWORD') }}"
- name: set IPA server facts
set_fact:
ipa_principal: "{{ tripleo_ipa_principal | default(lookup('env', 'IPA_PRINCIPAL')) }}"
ipa_password: "{{ tripleo_ipa_password | default(lookup('env', 'IPA_PASSWORD')) }}"
- name: set perms, privs, roles
include_role:
name: tripleo_ipa_setup
tasks_from: setup
apply:
environment:
IPA_USER: "{ ipa_principal }"
IPA_PASS: "{ ipa_password }"

View File

@ -1,67 +0,0 @@
---
# 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 playbook registers the undercloud host as an IPA client and provices a
# one time password to be used in the undercloud configuration file. This needs
# to be executed by a user that has permissions to add services and to add them
# to roles. This needs to be run once per openstack deployment.
- name: Playbook to register the undercloud node and generate OTP
connection: "{{ (tripleo_ipa_host is defined) | ternary('ssh', 'local') }}"
hosts: "{{ tripleo_ipa_host | default('localhost') }}"
remote_user: root
tasks:
- name: ensure definitions
fail:
msg: >-
{{ item }} is undefined
when: not item.ansible_var and not item.env_var
with_items:
- name: ipa_principal
ansible_var: "{{ ipa_principal | default('') }}"
env_var: "{{ lookup('env', 'IPA_PRINCIPAL') }}"
- name: ipa_password
ansible_var: "{{ ipa_password | default('') }}"
env_var: "{{ lookup('env', 'IPA_PASSWORD') }}"
- name: undercloud_fqdn
ansible_var: "{{ tripleo_undercloud_fqdn | default('') }}"
env_var: "{{ lookup('env', 'UNDERCLOUD_FQDN') }}"
- name: undercloud_description
ansible_var: "{{ tripleo_undercloud_description | default('Undercloud') }}"
env_var: "{{ lookup('env', 'UNDERCLOUD_DESCRIPTION') }}"
- name: set IPA server facts
set_fact:
ipa_principal: "{{ tripleo_ipa_principal | default(lookup('env', 'IPA_PRINCIPAL')) }}"
ipa_password: "{{ tripleo_ipa_password | default(lookup('env', 'IPA_PASSWORD')) }}"
undercloud_fqdn: "{{ tripleo_undercloud_fqdn | default(lookup('env', 'UNDERCLOUD_FQDN')) }}"
undercloud_description: "{{ tripleo_undercloud_description | default(lookup('env', 'UNDERCLOUD_DESCRIPTION')) }}"
- name: register undercloud as IPA client
ipa_host:
ipa_user: "{{ ipa_principal }}"
ipa_pass: "{{ ipa_password }}"
fqdn: "{{ undercloud_fqdn }}"
random_password: true
force: true
register: tripleo_ipa_host_otp
- name: provide OTP generated by IPA server
debug:
msg:
- "The OTP provided by the IPA server is {{ tripleo_ipa_host_otp.host.randompassword }}"
- "Please add the following to your undercloud.conf:"
- "ipa_otp = {{ tripleo_ipa_host_otp.host.randompassword }}"

View File

@ -1,119 +0,0 @@
---
# Copyright 2019 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.
- name: Playbook to register the undercloud host with an IPA server
connection: "{{ (tripleo_ipa_undercloud_host is defined) | ternary('ssh', 'local') }}"
hosts: "{{ tripleo_ipa_undercloud_host | default('localhost') }}"
tasks:
- name: Ensure definitions
fail:
msg: >-
{{ item }} is undefined
when: not item.ansible_var and not item.env_var
with_items:
- name: ipa_domain
ansible_var: "{{ tripleo_ipa_domain | default('') }}"
env_var: "{{ lookup('env', 'IPA_DOMAIN') }}"
- name: ipa_realm
ansible_var: "{{ tripleo_ipa_realm | default('') }}"
env_var: "{{ lookup('env', 'IPA_REALM') }}"
- name: ipa_server_user
ansible_var: "{{ tripleo_ipa_admin_user | default('') }}"
env_var: "{{ lookup('env', 'IPA_ADMIN_USER') }}"
- name: ipa_server_password
ansible_var: "{{ tripleo_ipa_admin_password | default('') }}"
env_var: "{{ lookup('env', 'IPA_ADMIN_PASSWORD') }}"
- name: ipa_server_hostname
ansible_var: "{{ tripleo_ipa_server_hostname | default('') }}"
env_var: "{{ lookup('env', 'IPA_SERVER_HOSTNAME') }}"
- name: undercloud_fqdn
ansible_var: "{{ tripleo_undercloud_fqdn | default('') }}"
env_var: "{{ lookup('env', 'UNDERCLOUD_FQDN') }}"
- name: ansible_user
ansible_var: "{{ tripleo_ansible_user | default('') }}"
env_var: "{{ lookup('env', 'USER') }}"
- name: cloud_domain
ansible_var: "{{ tripleo_cloud_domain | default('') }}"
env_var: "{{ lookup('env', 'CLOUD_DOMAIN') }}"
- name: Set facts needed for configuration
set_fact:
ipa_domain: "{{ tripleo_ipa_domain | default(lookup('env', 'IPA_DOMAIN')) }}"
ipa_realm: "{{ tripleo_ipa_realm | default(lookup('env', 'IPA_REALM')) }}"
ipa_server_user: "{{ tripleo_ipa_admin_user | default(lookup('env', 'IPA_ADMIN_USER')) }}"
ipa_server_password: "{{ tripleo_ipa_admin_password | default(lookup('env', 'IPA_ADMIN_PASSWORD')) }}"
ipa_server_hostname: "{{ tripleo_ipa_server_hostname | default(lookup('env', 'IPA_SERVER_HOSTNAME')) }}"
undercloud_fqdn: "{{ tripleo_undercloud_fqdn | default(lookup('env', 'UNDERCLOUD_FQDN')) }}"
undercloud_ansible_user: "{{ tripleo_ansible_user | default(lookup('env', 'USER')) }}"
cloud_domain: "{{ tripleo_cloud_domain | default(lookup('env', 'CLOUD_DOMAIN')) }}"
ipa_client_install_packages: "{{ tripleo_ipa_client_install_packages | default(true) | bool }}"
- name: Add host to ipaclients group
add_host:
name: "{{ undercloud_fqdn }}"
group: ipaclients
state: present
ipaclient_domain: "{{ cloud_domain }}"
ipaclient_install_packages: "{{ ipa_client_install_packages }}"
ipaclient_realm: "{{ ipa_realm }}"
ipaclient_force: true
ipaadmin_principal: "{{ ipa_server_user }}"
ipaadmin_password: "{{ ipa_server_password }}"
ansible_user: "{{ undercloud_ansible_user }}"
ansible_ssh_extra_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
no_log: true
- name: Add host to ipaservers group
add_host:
group: ipaservers
name: "{{ ipa_server_hostname }}"
- hosts: ipaclients
become: true
tasks:
- name: Include ipaclient role
include_role:
name: ipaclient
- hosts: "{{ tripleo_ipa_undercloud_host | default('localhost') }}"
become: true
tasks:
- name: Include create admin roles
include_role:
name: "{{ item }}"
with_first_found:
- "/usr/share/ansible/roles/tripleo_create_admin"
- "/usr/share/ansible/roles/tripleo-create-admin"
- hosts: "{{ tripleo_ipa_undercloud_host | default('localhost') }}"
become: true
environment:
IPA_USER: "{{ ipa_server_user }}"
IPA_HOST: "{{ ipa_server_hostname }}"
IPA_PASS: "{{ ipa_server_password }}"
vars:
undercloud_fqdn: "{{ ansible_fqdn }}"
tasks:
- name: kinit to get admin credentials
command: kinit "{{ ipa_server_user }}@{{ ipa_realm }}"
args:
stdin: "{{ ipa_server_password }}"
register: kinit
changed_when: kinit.rc == 0
no_log: true
- name: setup the undercloud and get keytab
include_role:
name: tripleo_ipa_setup

View File

@ -1,45 +0,0 @@
---
# 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:
namespace: openstack
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: []

View File

@ -1,28 +0,0 @@
---
# 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_keytab (file path to keytab to authenticate to FreeIPA)
- name: delete hosts, subhosts and services from freeIPA
cleanup_ipa_services:
keytab: "{{ tripleo_ipa_keytab }}"
hosts: "{{ tripleo_ipa_hosts_to_delete }}"
become: true

View File

@ -1,23 +0,0 @@
---
# 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.
# All variables intended for modification should place placed in this file.
# All variables within this role should have a prefix of "tripleo_ipa"
tripleo_ipa_ptr_zone_split_ipv4: 1
tripleo_ipa_ptr_zone_split_ipv6: 1

View File

@ -1,45 +0,0 @@
---
# 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:
namespace: openstack
author: OpenStack
description: TripleO OpenStack Role -- tripleo_ipa_dns
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: []

View File

@ -1,123 +0,0 @@
---
# 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.
- name: set forward dns record values
set_fact:
record_value: "{{ item.split()[0] }}"
record_name: "{{ item.split()[1].split('.', 1)[0] }}"
zone_name: "{{ item.split()[1].split('.', 1)[1] }}"
when: item.split() | length >= 2 and item.split()[1].split('.') | length >= 2
- name: set alternative record values
set_fact:
record_value: "no record value"
record_name: "no record name"
zone_name: "no record zone name provided"
when: item.split() | length < 2 or item.split()[1].split('.') | length < 2
- name: Notify about not adding entries
debug:
msg: |
"{{ item }}" not added to DNS due to not being managed by us.
Entries with domains outside of cloud_domain are skipped.
when: not zone_name is match("^(|.+\.)" + cloud_domain + "$")
- name: add entries
block:
- name: set record type
set_fact:
record_type: "{{ 'A' if record_value| ansible.netcommon.ipv4 else 'AAAA' }}"
- name: add dns zone
ipadnszone:
name: "{{ zone_name }}"
become: true
- name: Modify or add forward dns
block:
- name: try modifying forward dns record
ipadnsrecord:
zone_name: "{{ zone_name }}"
record_name: "{{ record_name }}"
record_type: "{{ record_type }}"
a_rec: "{{ record_value }}"
a_ip_address: ""
when: record_type == 'A'
become: true
- name: try modifying forward dns record
ipadnsrecord:
zone_name: "{{ zone_name }}"
record_name: "{{ record_name }}"
record_type: "{{ record_type }}"
aaaa_rec: "{{ record_value }}"
aaaa_ip_address: ""
when: record_type == 'AAAA'
become: true
rescue:
- name: add forward dns record
ipadnsrecord:
zone_name: "{{ zone_name }}"
record_name: "{{ record_name }}"
record_type: "{{ record_type }}"
record_value: "{{ record_value }}"
become: true
- name: get reverse record data
set_fact:
reverse_addr: "{{ record_value | ipaddr('revdns') }}"
- name: set reverse record entries for ipv4
set_fact:
reverse_record_zone: "{{ reverse_addr.split('.', tripleo_ipa_ptr_zone_split_ipv4|int)[-1] }}"
reverse_record_name: "{{ '.'.join(reverse_addr.split('.', tripleo_ipa_ptr_zone_split_ipv4|int)[:-1]) }}"
when: record_type == 'A'
- name: set reverse record entries for ipv6
set_fact:
reverse_record_zone: "{{ reverse_addr.split('.', tripleo_ipa_ptr_zone_split_ipv6|int)[-1] }}"
reverse_record_name: "{{ '.'.join(reverse_addr.split('.', tripleo_ipa_ptr_zone_split_ipv6|int)[:-1]) }}"
when: record_type == 'AAAA'
- name: add reverse record dns zone
ipadnszone:
name: "{{ reverse_record_zone }}"
register: reverse_zone_result
failed_when: reverse_zone_result.failed and 'already exists in DNS' not in reverse_zone_result.msg
become: true
- name: Modify or add reverse dns record
block:
- name: try modifying reverse dns record
ipadnsrecord:
zone_name: "{{ reverse_record_zone }}"
record_name: "{{ reverse_record_name }}"
record_type: "PTR"
ptr_rec: "{{ record_name }}.{{ zone_name }}."
ptr_hostname: ""
become: true
rescue:
- name: add reverse dns record
ipadnsrecord:
zone_name: "{{ reverse_record_zone }}"
record_name: "{{ reverse_record_name }}"
record_type: "PTR"
record_value: "{{ record_name }}.{{ zone_name }}."
register: reverse_record_result
failed_when: reverse_zone_result.failed and 'already exists in DNS' not in reverse_zone_result.msg
become: true
when: zone_name is match("^(|.+\.)" + cloud_domain + "$")

View File

@ -1,26 +0,0 @@
---
# 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 adds a host entries to FreeIPA, as defined in the host_entry variable.
#
# The following variables are required:
# - host_entry (host entries string, in a format similar to /etc/hosts)
- name: add dns records
include_tasks:
file: dns.yaml
loop: "{{ hosts_entry }}"

View File

@ -1,23 +0,0 @@
---
# 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.
# All variables intended for modification should place placed in this file.
# All variables within this role should have a prefix of "tripleo_ipa"
# enroll base server
tripleo_ipa_enroll_base_server: false

View File

@ -1,45 +0,0 @@
---
# 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:
namespace: openstack
author: OpenStack
description: TripleO OpenStack Role -- tripleo_ipa_registration
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: []

View File

@ -1,68 +0,0 @@
---
# 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 adds a host and its required sub-hosts and services to
# FreeIPA as defined in the ServerMetadata.
#
# The following variables are required:
# - tripleo_ipa_enroll_base_server (True if base server must be enrolled)
# - tripleo_ipa_base_server_fqdn (FQDN of base host eg. controller-0.example.com)
# - tripleo_ipa_base_server_otp (OTP for enrollment, only required if enroll_server is True)
# - tripleo_ipa_delegate_server (Server for OTP delegation, only required if enroll_server is True)
# - tripleo_ipa_server_metadata (server metadata, which includes required services)
- name: set main facts
set_fact:
base_server_fqdn: "{{ tripleo_ipa_base_server_fqdn }}"
base_server_short_name: "{{ tripleo_ipa_base_server_fqdn.split('.')[0] }}"
base_server_domain: "{{ tripleo_ipa_base_server_fqdn.split('.', 1)[1] }}"
enroll_base_server: "{{ tripleo_ipa_enroll_base_server }}"
- name: get the default.conf file
slurp:
src: /etc/ipa/default.conf
register: ipa_default_conf
- name: set the principal
set_fact:
principal: "nova/{{ ipa_default_conf['content']| b64decode | regex_findall('host = (.+)')|first }}"
- name: add main host to IPA with OTP
when: enroll_base_server|bool
become: true
block:
- name: add new host with one-time password
ipahost:
name: "{{ base_server_fqdn }}"
random: true
force: true
state: present
register: ipa_host
failed_when: ipa_host.failed and "Password cannot be set on enrolled host" not in ipa_host.msg
- name: set otp as a host fact
set_fact:
ipa_host_otp: "{{ ipa_host.host.randompassword }}"
no_log: true
delegate_facts: true
delegate_to: "{{ tripleo_ipa_delegate_server }}"
when: "'host' in ipa_host"
- name: add required services
include: services.yml
loop: "{{ tripleo_ipa_server_metadata | from_json | parse_service_metadata(base_server_fqdn) }}"
loop_control:
loop_var: required_service

View File

@ -1,52 +0,0 @@
---
# 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.
#
# The tasks in this file perform the registration process for a service.
#
# The following variable are required:
# - { required_service } : which is an ordered tuple of the form:
# -- { sub_host, service }
#
# An example of this is:
# { "controller-5.storagemgmt.example.com", "haproxy" }
#
# At this time, the final value in the tuple is unused.
- name: set variables
set_fact:
sub_host: "{{ required_service.0 }}"
service: "{{ required_service.1 }}"
- name: add sub_host
ipahost:
fqdn: "{{ sub_host }}"
force: true
state: present
become: true
- name: add service
ipaservice:
name: "{{ service }}/{{ sub_host }}"
force: true
state: present
become: true
- name: add host to managed_hosts if needed (shell)
shell: |
ipa service-add-host --hosts "{{ base_server_fqdn }}" "{{ service }}"/"{{ sub_host }}"
register: service_add_out
failed_when: service_add_out.failed and 'This entry is already a member' not in service_add_out.stdout
become: true

View File

@ -1,45 +0,0 @@
---
# 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:
namespace: openstack
author: OpenStack
description: TripleO-IPA Role -- tripleo_ipa_setup
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: []

View File

@ -1,43 +0,0 @@
---
# 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 playbook creates the nova user and adds it to the Nova Host Manager IPA
# role. This needs to be executed by a user that has permissions to add services
# and to add them to roles.
#
- name: set nova service user facts
set_fact:
nova_service: "nova/{{ undercloud_fqdn }}"
- name: add nova service
ipaservice:
name: "{{ nova_service }}"
state: present
force: true
- name: add Nova Host Manager role
iparole:
name: Nova Host Manager
description: Nova Host Manager
privilege:
- Nova Host Management
- name: add service to the Nova Host Manager role
iparole:
name: Nova Host Manager
service: "{{ nova_service }}"
action: member

View File

@ -1,44 +0,0 @@
---
# 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 is supposed to be run on the undercloud. In this role,
# we retrieve a keytab for the previously created nova user/service.
# The undercloud is assumed to be enrolled as an ipa client
#
- name: set keytab permissions facts
set_fact:
nova_service: "nova/{{ undercloud_fqdn }}"
nova_keytab: "/etc/novajoin/krb5.keytab"
nova_keytab_group: "root"
- name: add directory for keytab
file:
path: "/etc/novajoin"
state: directory
mode: '0755'
- name: get a keytab for the novajoin service
shell: |
ipa-getkeytab \
-p "{{ nova_service }}" \
-k "{{ nova_keytab }}"
- name: chgrp and chmod the keytab
file:
path: "{{ nova_keytab }}"
group: "{{ nova_keytab_group }}"
mode: "g+r"

View File

@ -1,23 +0,0 @@
---
# Copyright 2019 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.
- name: create ipa_user_role
include: setup.yml
- name: create ipa_user for this undercloud
include: add_ipa_user.yml
- name: get keytab for this user
include: get_ipa_user_keytab.yml

View File

@ -1,81 +0,0 @@
---
# 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 playbook adds the privileges and IPA role needed to do the things that
# tripleo wants to do in FreeIPA to add hosts and services. The operations in
# this playbook likely need admin privileges and should be executed on an
# IPA client.
#
- name: set keytab permissions facts
set_fact:
novajoin_perms:
- {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"]}
novajoin_privilege_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'
- 'System: Modify Realm Domains'
- 'Retrieve Certificates from the CA'
- name: add nova host management permissions
ipapermission:
name: "{{ item.name }}"
right: "{{ item.right }}"
object_type: "{{ item.type }}"
attrs: "{{ item.attrs }}"
loop: "{{ novajoin_perms|flatten(levels=1) }}"
- name: add Nova Host privilege
ipaprivilege:
name: Nova Host Management
description: Nova Host Management
- name: add permissions to the Nova Host privilege
ipaprivilege:
name: Nova Host Management
action: member
permission: "{{ item }}"
register: add_perm_command
failed_when:
- add_perm_command.failed
- '"This entry is already a member" not in add_perm_command.msg'
loop: "{{ novajoin_privilege_perms }}"
- name: add Nova Host Manager role
iparole:
name: Nova Host Manager
description: Nova Host Manager
privilege:
- Nova Host Management

View File

@ -1,35 +0,0 @@
# 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.
from ansible.plugins import loader
from oslotest import base
def load_module_utils(*args):
"""Ensure requested module_utils are loaded into ansible.module_utils"""
if args:
for m in args:
try:
loader.module_utils_loader.get(m)
except AttributeError:
pass
else:
# search and load all module_utils, its noisy and slower
list(loader.module_utils_loader.all())
class TestCase(base.BaseTestCase):
"""Test case base class for all unit tests."""

View File

@ -1,2 +0,0 @@
localhost

View File

@ -1,135 +0,0 @@
# 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.
import copy
from tripleo_ipa.ansible_plugins.filter import service_metadata
from tripleo_ipa.tests import base as tests_base
# Short-hand prefixes
MS = 'managed_service_'
CS = 'compact_service_'
class TestParseServiceMetadata(tests_base.TestCase):
def setUp(self):
super(TestParseServiceMetadata, self).setUp()
def test_parse_service_metadata(self):
domain = 'example.test'
host_fqdn = 'test-0.' + domain
md = {
CS + 'HTTP': [
'ctlplane', 'storage', 'storagemgmt', 'internalapi', 'external'
],
CS + 'haproxy': ['ctlplane', 'storage', 'storagemgmt', 'internalapi'],
CS + 'libvirt-vnc': ['internalapi'],
CS + 'mysql': ['internalapi'],
CS + 'neutron_ovn': ['internalapi'],
CS + 'novnc-proxy': ['internalapi'],
CS + 'ovn_controller': ['internalapi'],
CS + 'ovn_dbs': ['internalapi'],
CS + 'rabbitmq': ['internalapi'],
CS + 'redis': ['internalapi'],
MS + 'haproxyctlplane': 'haproxy/test-0.ctlplane.' + domain,
MS + 'haproxyexternal': 'haproxy/test-0.' + domain,
MS + 'haproxyinternal_api': 'haproxy/test-0.internalapi.' + domain,
MS + 'haproxystorage': 'haproxy/test-0.storage.' + domain,
MS + 'haproxystorage_mgmt': 'haproxy/test-0.storagemgmt.' + domain,
MS + 'mysqlinternal_api': 'mysql/test-0.internalapi.' + domain,
MS + 'ovn_dbsinternal_api': 'ovn_dbs/test-0.internalapi.' + domain,
MS + 'redisinternal_api': 'redis/test-0.internalapi.' + domain
}
expected_services = [
('test-0.ctlplane.example.test', 'HTTP'),
('test-0.storage.example.test', 'HTTP'),
('test-0.storagemgmt.example.test', 'HTTP'),
('test-0.internalapi.example.test', 'HTTP'),
('test-0.external.example.test', 'HTTP'),
('test-0.ctlplane.example.test', 'haproxy'),
('test-0.example.test', 'haproxy'),
('test-0.internalapi.example.test', 'haproxy'),
('test-0.storage.example.test', 'haproxy'),
('test-0.storagemgmt.example.test', 'haproxy'),
('test-0.internalapi.example.test', 'libvirt-vnc'),
('test-0.internalapi.example.test', 'mysql'),
('test-0.internalapi.example.test', 'neutron_ovn'),
('test-0.internalapi.example.test', 'novnc-proxy'),
('test-0.internalapi.example.test', 'ovn_controller'),
('test-0.internalapi.example.test', 'ovn_dbs'),
('test-0.internalapi.example.test', 'rabbitmq'),
('test-0.internalapi.example.test', 'redis')
]
services = service_metadata.parse_service_metadata(md, host_fqdn)
self.assertEqual(len(services), len(expected_services))
for service in services:
self.assertIn(service, expected_services)
def test_parse_service_metadata_with_long_domain_name(self):
domain = 'cloud.example.test'
host_fqdn = 'test-0.' + domain
md = {
CS + 'HTTP': [
'ctlplane', 'storage', 'storagemgmt', 'internalapi', 'external'
],
CS + 'haproxy': ['ctlplane', 'storage', 'storagemgmt', 'internalapi'],
CS + 'libvirt-vnc': ['internalapi'],
CS + 'mysql': ['internalapi'],
CS + 'neutron_ovn': ['internalapi'],
CS + 'novnc-proxy': ['internalapi'],
CS + 'ovn_controller': ['internalapi'],
CS + 'ovn_dbs': ['internalapi'],
CS + 'rabbitmq': ['internalapi'],
CS + 'redis': ['internalapi'],
MS + 'haproxyctlplane': 'haproxy/test-0.ctlplane.' + domain,
MS + 'haproxyexternal': 'haproxy/test-0.' + domain,
MS + 'haproxyinternal_api': 'haproxy/test-0.internalapi.' + domain,
MS + 'haproxystorage': 'haproxy/test-0.storage.' + domain,
MS + 'haproxystorage_mgmt': 'haproxy/test-0.storagemgmt.' + domain,
MS + 'mysqlinternal_api': 'mysql/test-0.internalapi.' + domain,
MS + 'ovn_dbsinternal_api': 'ovn_dbs/test-0.internalapi.' + domain,
MS + 'redisinternal_api': 'redis/test-0.internalapi.' + domain
}
expected_services = [
('test-0.ctlplane.cloud.example.test', 'HTTP'),
('test-0.storage.cloud.example.test', 'HTTP'),
('test-0.storagemgmt.cloud.example.test', 'HTTP'),
('test-0.internalapi.cloud.example.test', 'HTTP'),
('test-0.external.cloud.example.test', 'HTTP'),
('test-0.ctlplane.cloud.example.test', 'haproxy'),
('test-0.cloud.example.test', 'haproxy'),
('test-0.internalapi.cloud.example.test', 'haproxy'),
('test-0.storage.cloud.example.test', 'haproxy'),
('test-0.storagemgmt.cloud.example.test', 'haproxy'),
('test-0.internalapi.cloud.example.test', 'libvirt-vnc'),
('test-0.internalapi.cloud.example.test', 'mysql'),
('test-0.internalapi.cloud.example.test', 'neutron_ovn'),
('test-0.internalapi.cloud.example.test', 'novnc-proxy'),
('test-0.internalapi.cloud.example.test', 'ovn_controller'),
('test-0.internalapi.cloud.example.test', 'ovn_dbs'),
('test-0.internalapi.cloud.example.test', 'rabbitmq'),
('test-0.internalapi.cloud.example.test', 'redis')
]
services = service_metadata.parse_service_metadata(md, host_fqdn)
self.assertEqual(len(services), len(expected_services))
for service in services:
self.assertIn(service, expected_services)

View File

@ -1,5 +0,0 @@
---
- hosts: localhost
remote_user: root
roles:
- tripleo_ipa

View File

@ -1,21 +0,0 @@
---
- job:
description: Runs tox linters job on centos
name: openstack-tox-linters-centos
parent: openstack-tox-linters
nodeset: devstack-single-node-centos-9-stream
- job:
description: tripleo-ipa molecule job
name: tripleo-ipa-centos-9-molecule
nodeset: centos-9-stream
parent: base
success-url: "reports.html"
failure-url: "reports.html"
pre-run:
- zuul.d/playbooks/pre.yml
run:
- zuul.d/playbooks/run.yml
post-run:
- zuul.d/playbooks/post.yml
timeout: 5400
voting: true

View File

@ -1,15 +0,0 @@
---
- project:
templates:
- check-requirements
- openstack-python3-zed-jobs
- publish-to-pypi
- tripleo-standalone-multinode-ipa-pipeline
check:
jobs:
- openstack-tox-linters-centos
- tripleo-ipa-centos-9-molecule
gate:
jobs:
- openstack-tox-linters-centos
- tripleo-ipa-centos-9-molecule

View File

@ -1,44 +0,0 @@
---
# 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.
- name: TripleO IPA Post
hosts: all
tasks:
- name: Make ipaserver logs readable
file:
path: "/tmp/ipa-data/var/log"
mode: u=rwX,g=rX,o=rX
recurse: true
state: directory
become: true
failed_when: false
- name: Create local directory for ipaserver logs
file:
path: "{{ zuul.executor.log_root }}/ipa-logs"
state: directory
mode: u=rwX,g=rX,o=rX
failed_when: false
become: true
- name: Collect ipaserver-install logs
synchronize:
dest: "{{ zuul.executor.log_root }}/ipa-logs"
mode: pull
src: "/tmp/ipa-data/var/log/"
verify_host: true
failed_when: false

View File

@ -1,65 +0,0 @@
---
- hosts: all
pre_tasks:
- name: Set project path fact
set_fact:
tripleo_ipa_project_path: "{{ ansible_user_dir }}/{{ zuul.projects['opendev.org/x/tripleo-ipa'].src_dir }}"
- name: Ensure output dirs
file:
path: "{{ ansible_user_dir }}/zuul-output/logs"
state: directory
- name: Ensure pip is available
include_role:
name: ensure-pip
- name: Setup bindep
pip:
name: "bindep"
virtualenv: "{{ ansible_user_dir }}/test-python"
virtualenv_command: "{{ ensure_pip_virtualenv_command }}"
virtualenv_site_packages: true
- name: Run bindep
shell: |-
. {{ ansible_user_dir }}/test-python/bin/activate
{{ tripleo_ipa_project_path }}/scripts/bindep-install
become: true
- name: Ensure a recent version of pip is installed in virtualenv
pip:
name: "pip>=19.1.1"
virtualenv: "{{ ansible_user_dir }}/test-python"
virtualenv_command: "{{ ensure_pip_virtualenv_command }}"
- name: Setup test-python
pip:
requirements: "{{ tripleo_ipa_project_path }}/molecule-requirements.txt"
virtualenv: "{{ ansible_user_dir }}/test-python"
virtualenv_command: "{{ ensure_pip_virtualenv_command }}"
virtualenv_site_packages: true
- name: Make sure tox is installed in test-python virtualenv
pip:
name: tox
virtualenv: "{{ ansible_user_dir }}/test-python"
- name: Display test-python virtualenv package versions
shell: |-
. {{ ansible_user_dir }}/test-python/bin/activate
pip freeze
- name: Set containers module to 3.0
become: true
shell: |
dnf module disable container-tools:rhel8 -y
dnf module enable container-tools:3.0 -y
dnf clean metadata
when:
- (ansible_distribution_major_version | int) == 8
roles:
# docker is needed by multiple molecule scenarios
- role: ensure-podman

View File

@ -1,15 +0,0 @@
---
- hosts: all
tasks:
- name: set basic zuul fact
set_fact:
zuul:
projects:
"opendev.org/x/tripleo-ipa":
src_dir: "{{ tripleo_src }}"
ansible_connection: local
- import_playbook: pre.yml
- import_playbook: run.yml

View File

@ -1,18 +0,0 @@
---
- hosts: all
environment:
ANSIBLE_LOG_PATH: "{{ ansible_user_dir }}/zuul-output/logs/ansible-execution.log"
pre_tasks:
- name: Set project path fact
set_fact:
tripleo_ipa_project_path: "{{ ansible_user_dir }}/{{ zuul.projects['opendev.org/x/tripleo-ipa'].src_dir }}"
tasks:
- name: Run role test job
shell: |-
. {{ ansible_user_dir }}/test-python/bin/activate
tox -e molecule
args:
chdir: "{{ tripleo_ipa_project_path }}"
executable: /bin/bash