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:
parent
d48deac395
commit
d17c95406e
7
.zuul.yaml
Normal file
7
.zuul.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
- project:
|
||||
check:
|
||||
jobs:
|
||||
- noop
|
||||
gate:
|
||||
jobs:
|
||||
- noop
|
25
README.rst
25
README.rst
@ -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.
|
||||
|
@ -1,6 +0,0 @@
|
||||
collections:
|
||||
- containers.podman
|
||||
- community.general
|
||||
- ansible.posix
|
||||
- ansible.netcommon
|
||||
- openstack.cloud
|
@ -1 +0,0 @@
|
||||
ansible-core>=2.11,<2.12.0
|
42
bindep.txt
42
bindep.txt
@ -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]
|
@ -1,5 +0,0 @@
|
||||
ansible-core>=2.11,<2.12.0
|
||||
docker
|
||||
molecule
|
||||
molecule-podman
|
||||
testinfra
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
six>=1.10.0 # MIT
|
||||
PyYAML>=3.12 # MIT
|
||||
netaddr>=0.7.18 # BSD
|
@ -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
|
@ -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"
|
32
setup.cfg
32
setup.cfg
@ -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
|
20
setup.py
20
setup.py
@ -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)
|
@ -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
|
@ -1 +0,0 @@
|
||||
test ansible_connection=local ansible_host=localhost
|
63
tox.ini
63
tox.ini
@ -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
|
@ -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
|
@ -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).
|
@ -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}
|
@ -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()
|
@ -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"]
|
@ -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]'
|
@ -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
|
@ -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
|
@ -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 }}"
|
@ -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))
|
@ -1,9 +0,0 @@
|
||||
---
|
||||
# This is an example playbook to execute Ansible tests.
|
||||
|
||||
- name: Verify
|
||||
hosts: centos9
|
||||
tasks:
|
||||
- name: Example assertion
|
||||
assert:
|
||||
that: true
|
@ -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"]
|
@ -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"
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
```
|
@ -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 }}"
|
@ -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 }}"
|
@ -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 }"
|
@ -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 }}"
|
@ -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
|
@ -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: []
|
@ -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
|
@ -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
|
@ -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: []
|
@ -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 + "$")
|
@ -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 }}"
|
@ -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
|
@ -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: []
|
@ -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
|
@ -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
|
@ -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: []
|
@ -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
|
@ -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"
|
@ -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
|
@ -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
|
@ -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."""
|
@ -1,2 +0,0 @@
|
||||
localhost
|
||||
|
@ -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)
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
- hosts: localhost
|
||||
remote_user: root
|
||||
roles:
|
||||
- tripleo_ipa
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user