Compare commits

...

30 Commits

Author SHA1 Message Date
Thomas Woerner
7897bd4d8e Merge pull request #192 from jesmg/patch-1
Not delete keytab when ipaclient_on_master is true
2020-04-22 13:55:37 +02:00
Rafael Guterres Jeffman
4ba34077f9 Merge pull request #243 from t-woerner/galaxy-fix
Galaxy fix
2020-04-06 20:44:21 -03:00
Thomas Woerner
3a37325a36 galaxyfy-playbook.py: Fixed script name
The old name was galaxyify-playbook.py instead of galaxyfy-playbook.py
2020-04-02 14:46:54 +02:00
Thomas Woerner
57d407f15f utils/*galaxy*: Make galaxy scripts more generic
The namespace and colleciton name have been hard coded. Now variables are
used for them. The project prefix and collection prefix are now passed to
galaxyify-playbook.py.
2020-04-02 11:26:32 +02:00
Thomas Woerner
cd5429a534 ipareplica_setup_krb: krb is assigned to but never used
krb was set, but not used afterwards. Therefore it can be removed.
2020-04-02 10:50:41 +02:00
Thomas Woerner
ffd8585d19 ipareplica_setup_kra: Remove unused ccache parameter
The installer_ccache parameter is used in the module. The ccache parameter
was only set, but not used at all.
2020-04-02 10:48:53 +02:00
Sergio Oliveira
2897267440 Merge pull request #217 from rjeffman/sudorule_test_enhancement
Sudorule test enhancement
2020-03-30 17:35:08 -03:00
Thomas Woerner
2712e39bc4 galaxy.yml: Add system tag 2020-03-30 16:14:12 +02:00
Thomas Woerner
a972beb484 ipaserver docs: Calm down module linter
The use of "default: idstart+199999" in the description of the idmax
parameter was resulting in the galaxy import error:

  Cannot parse "DOCUMENTATION": mapping values are not allowed here in
  "<unicode string>", line 52, column 58: ... value for the IDs range
  (default: idstart+199999)

The ":" has simply been removed to fix this issue.
2020-03-30 15:01:55 +02:00
Thomas Woerner
50a1c2f9cd utils/build-galaxy-release: Do not add release tag to version for galaxy
Galaxy does not like the use of the extra "-1" release tag.

Fixes: #236 (Can't install via Galaxy)
2020-03-30 14:45:02 +02:00
Rafael Guterres Jeffman
0fb05dfaca Merge pull request #240 from seocam/dnszone-update
Fixed a bug in AnsibleFreeIPAParams
2020-03-26 14:03:02 -03:00
Sergio Oliveira Campos
2205907220 Fixed a bug in AnsibleFreeIPAParams
When accessing an instance of AnsibleFreeIPAParams with .get the obj was
by-passing the call to _afm_convert which was the primaty reason why it
was created.

Also the class now extends Mapping instead of dict.
2020-03-26 13:10:54 -03:00
Rafael Guterres Jeffman
d7af454d77 Merge pull request #239 from seocam/dnszone-update
Added aliases for in dnszone module arguments
2020-03-26 09:22:13 -03:00
Sergio Oliveira Campos
35d7658834 Added alias module arguments in dnszone module 2020-03-26 09:15:23 -03:00
Sergio Oliveira
aeaeaadd27 Merge pull request #238 from rjeffman/fix_dnsconfig_passwd
Add admin password to the ipadnsconfig module tests.
2020-03-25 17:51:20 -03:00
Rafael Guterres Jeffman
abe2605a55 Add admin password to the ipadnsconfig module tests.
This change avoid the need to obtain an admin TGT on the testing target before running the tests.
2020-03-25 17:42:24 -03:00
Rafael Guterres Jeffman
492a2bf39e Merge pull request #231 from Akasurde/i115
Handle RuntimeError in fail_json
2020-03-25 11:47:33 -03:00
Rafael Guterres Jeffman
4ab38e8bc6 Merge pull request #233 from t-woerner/setup_logging
ipa[server,replica,client]: setup_logging wrapper for standard_logging setup
2020-03-25 11:39:23 -03:00
Rafael Guterres Jeffman
3400f9556b Merge pull request #224 from seocam/dnszone
DNSZone module
2020-03-24 15:28:29 -03:00
Sergio Oliveira Campos
2ed7e21c1f New IPADNSZone module
There is a new management module placed in the plugins folder:

    plugins/modules/ipadnszone.py

    The dnszone module allows to manage DNS zones.

    Here is the documentation for the module:

    README-dnszone.md

    New example playbooks have been added:

    playbooks/dnszone/disable-zone-forwarders.yml
    playbooks/dnszone/dnszone-absent.yml
    playbooks/dnszone/dnszone-all-params.yml
    playbooks/dnszone/dnszone-disable.yml
    playbooks/dnszone/dnszone-enable.yml
    playbooks/dnszone/dnszone-present.yml

    New tests for the module:

    tests/dnszone/test_dnszone.yml
    tests/dnszone/test_dnszone_mod.yml
2020-03-24 10:52:53 -03:00
Sergio Oliveira Campos
e76047edb0 Created FreeIPABaseModule class to facilitate creation of new modules 2020-03-24 10:40:04 -03:00
Sergio Oliveira
b211b50b2d Merge pull request #232 from t-woerner/ipareplica_prepare_docs
ipareplica_prepare: Fix module DOCUMENTATION
2020-03-20 17:17:55 -03:00
Thomas Woerner
d31a132a59 ipa[server,replica,client]: setup_logging wrapper for standard_logging_setup
The import of ansible_ipa_server, ansible_ipa_replica and ansible_ipa_client
might result in a permission denied error for the log file. It seems that
for collections the module utils seem to be loaded before the needed
permissions are aquired now.

The fix simply adds a wrapper for standard_logging_setup that is called in
all the modules of the server, replica and client roles to do the loggin
setup as one of the first steps of the module execution and not before.
2020-03-20 13:55:42 +01:00
Thomas Woerner
7576732525 ipareplica_prepare: Fix module DOCUMENTATION
The documentation contains the pramaters several times. Reducing the list
to one. Also fixed a typo in options key.
2020-03-20 13:53:46 +01:00
Abhijeet Kasurde
cfdf2896ba Handle RuntimeError in fail_json
Gracefully handle RuntimeError raised during parameter validation
in fail_json.

Fixes: #115

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2020-03-20 16:57:20 +05:30
Rafael Guterres Jeffman
8c2268a560 Enhance sudorule module tests.
This patch adds tests for some options that were not being tested, and
enhances test behavior.
2020-03-18 10:52:35 -03:00
Thomas Woerner
81179b709b Merge pull request #163 from chr15p/master
Add dnsforwardzone module
2020-03-16 17:49:04 +01:00
Thomas Woerner
d33935583c Merge branch 'master' into master 2020-03-16 17:47:57 +01:00
chrisp
708675d9c2 add a module to manage dns forwarder zones in ipa 2020-03-10 16:14:54 +00:00
Jesús
7cf80c59b8 Not delete keytab when ipaclient_on_master is true
Keep the valid keytab file pre-existent in the master node. This fixes #191.
2020-01-23 18:09:10 +01:00
83 changed files with 2836 additions and 1349 deletions

112
README-dnsforwardzone.md Normal file
View File

@@ -0,0 +1,112 @@
Dnsforwardzone module
=====================
Description
-----------
The dnsforwardzone module allows the addition and removal of dns forwarders from the IPA DNS config.
It is desgined to follow the IPA api as closely as possible while ensuring ease of use.
Features
--------
* DNS zone management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipadnsforwardzone module.
Requirements
------------
**Controller**
* Ansible version: 2.8+
**Node**
* Supported FreeIPA version (see above)
Usage
=====
Example inventory file
```ini
[ipaserver]
ipaserver.test.local
```
Example playbook to ensure presence of a forwardzone to ipa DNS:
```yaml
---
- name: Playbook to handle add a forwarder
hosts: ipaserver
become: true
tasks:
- name: ensure presence of forwardzone for DNS requests for example.com to 8.8.8.8
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 8.8.8.8
forwardpolicy: first
skip_overlap_check: true
- name: ensure the forward zone is disabled
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: disabled
- name: ensure presence of multiple upstream DNS servers for example.com
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 8.8.8.8
- 4.4.4.4
- name: ensure presence of another forwarder to any existing ones for example.com
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 1.1.1.1
action: member
- name: ensure the forwarder for example.com does not exists (delete it if needed)
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: absent
```
Variables
=========
ipagroup
-------
Variable | Description | Required
-------- | ----------- | --------
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
`name` \| `cn` | Zone name (FQDN). | yes if `state` == `present`
`forwarders` \| `idnsforwarders` | Per-zone conditional forwarding policy. Possible values are `only`, `first`, `none`) | no
`forwardpolicy` \| `idnsforwardpolicy` | Per-zone conditional forwarding policy. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded. | no
`skip_overlap_check` | Force DNS zone creation even if it will overlap with an existing zone. Defaults to False. | no
`action` | Work on group or member level. It can be on of `member` or `dnsforwardzone` and defaults to `dnsforwardzone`. | no
`state` | The state to ensure. It can be one of `present`, `absent`, `enabled` or `disabled`, default: `present`. | yes
Authors
=======
Chris Procter

195
README-dnszone.md Normal file
View File

@@ -0,0 +1,195 @@
DNSZone Module
==============
Description
-----------
The dnszone module allows to configure zones in DNS server.
Features
--------
* Add, remove, modify, enable or disable DNS zones.
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by ipadnszone module.
Requirements
------------
**Controller**
* Ansible version: 2.8+
**Node**
* Supported FreeIPA version (see above)
Usage
-----
```ini
[ipaserver]
ipaserver.test.local
```
Example playbook to create a simple DNS zone:
```yaml
---
- name: dnszone present
hosts: ipaserver
become: true
tasks:
- name: Ensure zone is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: present
```
Example playbook to create a DNS zone with all currently supported variables:
```yaml
---
- name: dnszone present
hosts: ipaserver
become: true
tasks:
- name: Ensure zone is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_sync_ptr: true
dynamic_update: true
dnssec: true
allow_transfer:
- 1.1.1.1
- 2.2.2.2
allow_query:
- 1.1.1.1
- 2.2.2.2
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
port: 52
serial: 1234
refresh: 3600
retry: 900
expire: 1209600
minimum: 3600
ttl: 60
default_ttl: 90
name_server: ipaserver.test.local.
admin_email: admin.admin@example.com
nsec3param_rec: "1 7 100 0123456789abcdef"
skip_overlap_check: true
skip_nameserver_check: true
state: present
```
Example playbook to disable a zone:
```yaml
---
- name: Playbook to disable DNS zone
hosts: ipaserver
become: true
tasks:
- name: Disable zone.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: disabled
```
Example playbook to enable a zone:
```yaml
---
- name: Playbook to enable DNS zone
hosts: ipaserver
become: true
tasks:
- name: Enable zone.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: enabled
```
Example playbook to remove a zone:
```yaml
---
- name: Playbook to remove DNS zone
hosts: ipaserver
become: true
tasks:
- name: Remove zone.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: absent
```
Variables
=========
ipadnszone
----------
Variable | Description | Required
-------- | ----------- | --------
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
`name` \| `zone_name` | The zone name string. | yes
`forwarders` | The list of forwarders dicts. Each `forwarders` dict entry has:| no
&nbsp; | `ip_address` - The IPv4 or IPv6 address of the DNS server. | yes
&nbsp; | `port` - The custom port that should be used on this server. | no
`forward_policy` | The global forwarding policy. It can be one of `only`, `first`, or `none`. | no
`allow_sync_ptr` | Allow synchronization of forward (A, AAAA) and reverse (PTR) records (bool). | no
`state` | The state to ensure. It can be one of `present`, `enabled`, `disabled` or `absent`, default: `present`. | yes
`name_server`| Authoritative nameserver domain name | no
`admin_email`| Administrator e-mail address | no
`update_policy`| BIND update policy | no
`dynamic_update` \| `dynamicupdate` | Allow dynamic updates | no
`dnssec`| Allow inline DNSSEC signing of records in the zone | no
`allow_transfer`| List of IP addresses or networks which are allowed to transfer the zone | no
`allow_query`| List of IP addresses or networks which are allowed to issue queries | no
`serial`| SOA record serial number | no
`refresh`| SOA record refresh time | no
`retry`| SOA record retry time | no
`expire`| SOA record expire time | no
`minimum`| How long should negative responses be cached | no
`ttl`| Time to live for records at zone apex | no
`default_ttl`| Time to live for records without explicit TTL definition | no
`nsec3param_rec`| NSEC3PARAM record for zone in format: hash_algorithm flags iterations salt | no
`skip_overlap_check`| Force DNS zone creation even if it will overlap with an existing zone | no
`skip_nameserver_check` | Force DNS zone creation even if nameserver is not resolvable | no
Authors
=======
Sergio Oliveira Campos

View File

@@ -11,6 +11,8 @@ Features
* Cluster deployments: Server, replicas and clients in one playbook
* One-time-password (OTP) support for client installation
* Repair mode for clients
* Modules for dns forwarder management
* Modules for dns zone management
* Modules for group management
* Modules for hbacrule management
* Modules for hbacsvc management
@@ -408,6 +410,8 @@ Modules in plugin/modules
=========================
* [ipadnsconfig](README-dnsconfig.md)
* [ipadnsforwardzone](README-dnsforwardzone.md)
* [ipadnszone](README-dnszone.md)
* [ipagroup](README-group.md)
* [ipahbacrule](README-hbacrule.md)
* [ipahbacsvc](README-hbacsvc.md)
@@ -423,3 +427,5 @@ Modules in plugin/modules
* [ipatopologysuffix](README-topology.md)
* [ipauser](README-user.md)
* [ipavault](README-vault.md)
If you want to write a new module please read [writing a new module](plugins/modules/README.md).

View File

@@ -18,6 +18,7 @@ license_file: "COPYING"
dependencies:
tags:
- "system"
- "identity"
- "ipa"
- "freeipa"

View File

@@ -0,0 +1,11 @@
---
- name: Playbook to disable DNS zone forwarders
hosts: ipaserver
become: true
tasks:
- name: Disable zone forwarders.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forward_policy: none

View File

@@ -0,0 +1,11 @@
---
- name: Playbook to ensure DNS zone is absent
hosts: ipaserver
become: true
tasks:
- name: Remove zone.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: absent

View File

@@ -0,0 +1,35 @@
- name: dnszone present
hosts: ipaserver
become: true
tasks:
- name: Ensure zone is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_sync_ptr: true
dynamic_update: true
dnssec: true
allow_transfer:
- 1.1.1.1
- 2.2.2.2
allow_query:
- 1.1.1.1
- 2.2.2.2
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
port: 52
#serial: 1234
refresh: 3600
retry: 900
expire: 1209600
minimum: 3600
ttl: 60
default_ttl: 90
name_server: ipaserver.test.local.
admin_email: admin.admin@example.com
nsec3param_rec: "1 7 100 0123456789abcdef"
skip_overlap_check: true
skip_nameserver_check: true
state: present

View File

@@ -0,0 +1,11 @@
---
- name: Playbook to disable DNS zone
hosts: ipaserver
become: true
tasks:
- name: Disable zone.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: disabled

View File

@@ -0,0 +1,11 @@
---
- name: Playbook to enable DNS zone
hosts: ipaserver
become: true
tasks:
- name: Enable zone.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: enabled

View File

@@ -0,0 +1,10 @@
- name: dnszone present
hosts: ipaserver
become: true
tasks:
- name: Ensure zone is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: present

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
# Authors:
# Sergio Oliveira Campos <seocam@redhat.com>
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2019 Red Hat
@@ -27,10 +28,12 @@ import tempfile
import shutil
import gssapi
from datetime import datetime
from pprint import pformat
from ipalib import api
from ipalib import errors as ipalib_errors
from ipalib import errors as ipalib_errors # noqa
from ipalib.config import Env
from ipalib.constants import DEFAULT_CONFIG, LDAP_GENERALIZED_TIME_FORMAT
try:
from ipalib.install.kinit import kinit_password, kinit_keytab
except ImportError:
@@ -38,7 +41,9 @@ except ImportError:
from ipapython.ipautil import run
from ipaplatform.paths import paths
from ipalib.krb_utils import get_credentials_if_valid
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
try:
from ipalib.x509 import Encoding
except ImportError:
@@ -47,12 +52,17 @@ import socket
import base64
import six
try:
from collections.abc import Mapping # noqa
except ImportError:
from collections import Mapping # noqa
if six.PY3:
unicode = str
def valid_creds(module, principal):
def valid_creds(module, principal): # noqa
"""
Get valid credintials matching the princial, try GSSAPI first
"""
@@ -205,9 +215,24 @@ def date_format(value):
raise ValueError("Invalid date '%s'" % value)
def compare_args_ipa(module, args, ipa):
def compare_args_ipa(module, args, ipa): # noqa
"""Compare IPA obj attrs with the command args.
This function compares IPA objects attributes with the args the
module is intending to use to call a command. This is useful to know
if call to IPA server will be needed or not.
In other to compare we have to prepare the perform slight changes in
data formats.
Returns True if they are the same and False otherwise.
"""
base_debug_msg = "Ansible arguments and IPA commands differed. "
for key in args.keys():
if key not in ipa:
module.debug(
base_debug_msg + "Command key not present in IPA: %s" % key
)
return False
else:
arg = args[key]
@@ -220,25 +245,35 @@ def compare_args_ipa(module, args, ipa):
if isinstance(ipa_arg, list):
if not isinstance(arg, list):
arg = [arg]
if len(ipa_arg) != len(arg):
module.debug(
base_debug_msg
+ "List length doesn't match for key %s: %d %d"
% (key, len(arg), len(ipa_arg),)
)
return False
if isinstance(ipa_arg[0], str) and isinstance(arg[0], int):
arg = [to_text(_arg) for _arg in arg]
if isinstance(ipa_arg[0], unicode) and isinstance(arg[0], int):
arg = [to_text(_arg) for _arg in arg]
# module.warn("%s <=> %s" % (repr(arg), repr(ipa_arg)))
try:
arg_set = set(arg)
ipa_arg_set = set(ipa_arg)
except TypeError:
if arg != ipa_arg:
# module.warn("%s != %s" % (repr(arg), repr(ipa_arg)))
module.debug(
base_debug_msg
+ "Different values: %s %s" % (arg, ipa_arg)
)
return False
else:
if arg_set != ipa_arg_set:
# module.warn("%s != %s" % (repr(arg), repr(ipa_arg)))
module.debug(
base_debug_msg
+ "Different set content: %s %s"
% (arg_set, ipa_arg_set,)
)
return False
# module.warn("%s == %s" % (repr(arg), repr(ipa_arg)))
return True
@@ -289,6 +324,16 @@ def encode_certificate(cert):
return encoded
def is_valid_port(port):
if not isinstance(port, int):
return False
if 1 <= port <= 65535:
return True
return False
def is_ipv4_addr(ipaddr):
"""
Test if figen IP address is a valid IPv4 address
@@ -309,3 +354,303 @@ def is_ipv6_addr(ipaddr):
except socket.error:
return False
return True
class AnsibleFreeIPAParams(Mapping):
def __init__(self, ansible_module):
self.mapping = ansible_module.params
self.ansible_module = ansible_module
def __getitem__(self, key):
param = self.mapping[key]
if param is not None:
return _afm_convert(param)
def __iter__(self):
return iter(self.mapping)
def __len__(self):
return len(self.mapping)
@property
def names(self):
return self.name
def __getattr__(self, name):
return self.get(name)
class FreeIPABaseModule(AnsibleModule):
"""
Base class for FreeIPA Ansible modules.
Provides methods useful methods to be used by our modules.
This class should be overriten and instantiated for the module.
A basic implementation of an Ansible FreeIPA module expects its
class to:
1. Define a class attribute ``ipa_param_mapping``
2. Implement the method ``define_ipa_commands()``
3. Implement the method ``check_ipa_params()`` (optional)
After instantiating the class the method ``ipa_run()`` should be called.
Example (ansible-freeipa/plugins/modules/ipasomemodule.py):
class SomeIPAModule(FreeIPABaseModule):
ipa_param_mapping = {
"arg_to_be_passed_to_ipa_command": "module_param",
"another_arg": "get_another_module_param",
}
def get_another_module_param(self):
another_module_param = self.ipa_params.another_module_param
# Validate or modify another_module_param
# ...
return another_module_param
def check_ipa_params(self):
# Validate your params here
# Example:
if not self.ipa_params.module_param in VALID_OPTIONS:
self.fail_json(msg="Invalid value for argument module_param")
def define_ipa_commands(self):
args = self.get_ipa_command_args()
self.add_ipa_command(
"some_ipa_command",
name="obj-name",
args=args,
)
def main():
ipa_module = SomeIPAModule(argument_spec=dict(
module_param=dict(
type="str",
default=None,
required=False,
),
another_module_param=dict(
type="str",
default=None,
required=False,
),
))
ipa_module.ipa_run()
if __name__ == "__main__":
main()
"""
ipa_param_mapping = None
def __init__(self, *args, **kwargs):
super(FreeIPABaseModule, self).__init__(*args, **kwargs)
# Attributes to store kerberos credentials (if needed)
self.ccache_dir = None
self.ccache_name = None
# Status of an execution. Will be changed to True
# if something is actually peformed.
self.changed = False
# Status of the connection with the IPA server.
# We need to know if the connection was actually stablished
# before we start sending commands.
self.ipa_connected = False
# Commands to be executed
self.ipa_commands = []
# Module exit arguments.
self.exit_args = {}
# Wrapper around the AnsibleModule.params.
# Return the actual params but performing transformations
# when needed.
self.ipa_params = AnsibleFreeIPAParams(self)
def get_ipa_command_args(self):
"""
Return a dict to be passed to an IPA command.
The keys of ``ipa_param_mapping`` are also the keys of the return dict.
The values of ``ipa_param_mapping`` needs to be either:
* A str with the name of a defined method; or
* A key of ``AnsibleModule.param``.
In case of a method the return of the method will be set as value
for the return dict.
In case of a AnsibleModule.param the value of the param will be
set in the return dict. In addition to that boolean values will be
automaticaly converted to uppercase strings (as required by FreeIPA
server).
"""
args = {}
for ipa_param_name, param_name in self.ipa_param_mapping.items():
# Check if param_name is actually a param
if param_name in self.ipa_params:
value = self.ipa_params.get(param_name)
if isinstance(value, bool):
value = "TRUE" if value else "FALSE"
# Since param wasn't a param check if it's a method name
elif hasattr(self, param_name):
method = getattr(self, param_name)
if callable(method):
value = method()
# We don't have a way to guess the value so fail.
else:
self.fail_json(
msg=(
"Couldn't get a value for '%s'. Option '%s' is not "
"a module argument neither a defined method."
)
% (ipa_param_name, param_name)
)
if value is not None:
args[ipa_param_name] = value
return args
def check_ipa_params(self):
"""Validate ipa_params before command is called."""
pass
def define_ipa_commands(self):
"""Define commands that will be run in IPA server."""
raise NotImplementedError
def api_command(self, command, name=None, args=None):
"""Execute a single command in IPA server."""
if args is None:
args = {}
if name is None:
return api_command_no_name(self, command, args)
return api_command(self, command, name, args)
def __enter__(self):
"""
Connect to IPA server.
Check the there are working Kerberos credentials to connect to
IPA server. If there are not we perform a temporary kinit
that will be terminated when exiting the context.
If the connection fails ``ipa_connected`` attribute will be set
to False.
"""
principal = self.ipa_params.ipaadmin_principal
password = self.ipa_params.ipaadmin_password
try:
if not valid_creds(self, principal):
self.ccache_dir, self.ccache_name = temp_kinit(
principal, password,
)
api_connect()
except Exception as excpt:
self.fail_json(msg=str(excpt))
else:
self.ipa_connected = True
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""
Terminate a connection with the IPA server.
Deal with exceptions, destroy temporary kinit credentials and
exit the module with proper arguments.
"""
if exc_val:
self.fail_json(msg=str(exc_val))
# TODO: shouldn't we also disconnect from api backend?
temp_kdestroy(self.ccache_dir, self.ccache_name)
self.exit_json(changed=self.changed, user=self.exit_args)
def get_command_errors(self, command, result):
"""Look for erros into command results."""
# Get all errors
# All "already a member" and "not a member" failures in the
# result are ignored. All others are reported.
errors = []
for item in result.get("failed", tuple()):
failed_item = result["failed"][item]
for member_type in failed_item:
for member, failure in failed_item[member_type]:
if (
"already a member" in failure
or "not a member" in failure
):
continue
errors.append(
"%s: %s %s: %s"
% (command, member_type, member, failure)
)
if len(errors) > 0:
self.fail_json(", ".join("errors"))
def add_ipa_command(self, command, name=None, args=None):
"""Add a command to the list of commands to be executed."""
self.ipa_commands.append((name, command, args or {}))
def _run_ipa_commands(self):
"""Execute commands in self.ipa_commands."""
result = None
for name, command, args in self.ipa_commands:
try:
result = self.api_command(command, name, args)
except Exception as excpt:
self.fail_json(msg="%s: %s: %s" % (command, name, str(excpt)))
else:
if "completed" in result:
if result["completed"] > 0:
self.changed = True
else:
self.changed = True
self.get_command_errors(command, result)
def require_ipa_attrs_change(self, command_args, ipa_attrs):
"""
Compare given args with current object attributes.
Returns True in case current IPA object attributes differ from
args passed to the module.
"""
equal = compare_args_ipa(self, command_args, ipa_attrs)
return not equal
def pdebug(self, value):
"""Debug with pretty formatting."""
self.debug(pformat(value))
def ipa_run(self):
"""Execute module actions."""
with self:
if not self.ipa_connected:
return
self.check_ipa_params()
self.define_ipa_commands()
self._run_ipa_commands()

80
plugins/modules/README.md Normal file
View File

@@ -0,0 +1,80 @@
# Writing a new Ansible FreeIPA module
## Minimum requirements
A ansible-freeipa module should have:
* Code:
* A module file placed in `plugins/modules/<ipa_module_name>.py`
* Documentation:
* `README-<module_name>.md` file in the root directory and linked from the main README.md
* Example playbooks in `playbooks/<module_name>/` directory
* Tests:
* Test cases (also playbooks) defined in `tests/<module_name>/test_<something>.yml`. It's ok to have multiple files in this directory.
## Code
The module file have to start with the python shebang line, license header and definition of the constants `ANSIBLE_METADATA`, `DOCUMENTATION`, `EXAMPLES` and `RETURNS`. Those constants need to be defined before the code (even imports). See https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html#starting-a-new-module for more information.
Although it's use is not yet required, ansible-freeipa provides `FreeIPABaseModule` as a helper class for the implementation of new modules. See the example bellow:
```python
from ansible.module_utils.ansible_freeipa_module import FreeIPABaseModule
class SomeIPAModule(FreeIPABaseModule):
ipa_param_mapping = {
"arg_to_be_passed_to_ipa_command": "module_param",
"another_arg": "get_another_module_param",
}
def get_another_module_param(self):
another_module_param = self.ipa_params.another_module_param
# Validate or modify another_module_param ...
return another_module_param
def check_ipa_params(self):
# Validate your params here ...
# Example:
if not self.ipa_params.module_param in VALID_OPTIONS:
self.fail_json(msg="Invalid value for argument module_param")
def define_ipa_commands(self):
args = self.get_ipa_command_args()
self.add_ipa_command("some_ipa_command", name="obj-name", args=args)
def main():
ipa_module = SomeIPAModule(argument_spec=dict(
module_param=dict(type="str", default=None, required=False),
another_module_param=dict(type="str", default=None, required=False),
))
ipa_module.ipa_run()
if __name__ == "__main__":
main()
```
In the example above, the module will call the command `some_ipa_command`, using "obj-name" as name and, `arg_to_be_passed_to_ipa_command` and `another_arg` as arguments.
The values of the arguments will be determined by the class attribute `ipa_param_mapping`.
In the case of `arg_to_be_passed_to_ipa_command` the key (`module_param`) is defined in the module `argument_specs` so the value of the argument is actually used.
On the other hand, `another_arg` as mapped to something else: a callable method. In this case the method will be called and it's result used as value for `another_arg`.
**NOTE**: Keep mind that to take advantage of the parameters mapping defined in `ipa_param_mapping` you will have to call `args = self.get_ipa_command_args()` and use `args` in your command. There is no implicit call of this method.
## Disclaimer
The `FreeIPABaseModule` is new and might not be suitable to all cases and every module yet. In case you need to extend it's functionality for a new module please open an issue or PR and we'll be happy to discuss it.

View File

@@ -0,0 +1,316 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Chris Procter <cprocter@redhat.com>
#
# Copyright (C) 2019 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = '''
---
module: ipa_dnsforwardzone
author: chris procter
short_description: Manage FreeIPA DNS Forwarder Zones
description:
- Add and delete an IPA DNS Forwarder Zones using IPA API
options:
ipaadmin_principal:
description: The admin principal
default: admin
ipaadmin_password:
description: The admin password
required: false
name:
description:
- The DNS zone name which needs to be managed.
required: true
aliases: ["cn"]
state:
description: State to ensure
required: false
default: present
choices: ["present", "absent", "enabled", "disabled"]
forwarders:
description:
- List of the DNS servers to forward to
required: true
type: list
aliases: ["idnsforwarders"]
forwardpolicy:
description: Per-zone conditional forwarding policy
required: false
default: only
choices: ["only", "first", "none"]
aliases: ["idnsforwarders"]
skip_overlap_check:
description:
- Force DNS zone creation even if it will overlap with an existing zone.
required: false
default: false
'''
EXAMPLES = '''
# Ensure dns zone is present
- ipadnsforwardzone:
ipaadmin_password: MyPassword123
state: present
name: example.com
forwarders:
- 8.8.8.8
- 4.4.4.4
forwardpolicy: first
skip_overlap_check: true
# Ensure that dns zone is removed
- ipadnsforwardzone:
ipaadmin_password: MyPassword123
name: example.com
state: absent
'''
RETURN = '''
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
temp_kdestroy, valid_creds, api_connect, api_command, compare_args_ipa, \
module_params_get
def find_dnsforwardzone(module, name):
_args = {
"all": True,
"idnsname": name
}
_result = api_command(module, "dnsforwardzone_find", name, _args)
if len(_result["result"]) > 1:
module.fail_json(
msg="There is more than one dnsforwardzone '%s'" % (name))
elif len(_result["result"]) == 1:
return _result["result"][0]
else:
return None
def gen_args(forwarders, forwardpolicy, skip_overlap_check):
_args = {}
if forwarders is not None:
_args["idnsforwarders"] = forwarders
if forwardpolicy is not None:
_args["idnsforwardpolicy"] = forwardpolicy
if skip_overlap_check is not None:
_args["skip_overlap_check"] = skip_overlap_check
return _args
def main():
ansible_module = AnsibleModule(
argument_spec=dict(
# general
ipaadmin_principal=dict(type="str", default="admin"),
ipaadmin_password=dict(type="str", required=False, no_log=True),
name=dict(type="str", aliases=["cn"], default=None,
required=True),
forwarders=dict(type='list', aliases=["idnsforwarders"],
required=False),
forwardpolicy=dict(type='str', aliases=["idnsforwardpolicy"],
required=False,
choices=['only', 'first', 'none']),
skip_overlap_check=dict(type='bool', required=False),
action=dict(type="str", default="dnsforwardzone",
choices=["member", "dnsforwardzone"]),
# state
state=dict(type='str', default='present',
choices=['present', 'absent', 'enabled', 'disabled']),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
ipaadmin_principal = module_params_get(ansible_module,
"ipaadmin_principal")
ipaadmin_password = module_params_get(ansible_module,
"ipaadmin_password")
name = module_params_get(ansible_module, "name")
action = module_params_get(ansible_module, "action")
forwarders = module_params_get(ansible_module, "forwarders")
forwardpolicy = module_params_get(ansible_module, "forwardpolicy")
skip_overlap_check = module_params_get(ansible_module,
"skip_overlap_check")
state = module_params_get(ansible_module, "state")
# absent stae means delete if the action is NOT member but update if it is
# if action is member then update an exisiting resource
# and if action is not member then create a resource
if state == "absent" and action == "dnsforwardzone":
operation = "del"
elif action == "member":
operation = "update"
else:
operation = "add"
if state == "disabled":
wants_enable = False
else:
wants_enable = True
if operation == "del":
invalid = ["forwarders", "forwardpolicy", "skip_overlap_check"]
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with action "
"'%s'" % (x, action))
changed = False
exit_args = {}
args = {}
ccache_dir = None
ccache_name = None
is_enabled = "IGNORE"
try:
# we need to determine 3 variables
# args = the values we want to change/set
# command = the ipa api command to call del, add, or mod
# is_enabled = is the current resource enabled (True)
# disabled (False) and do we care (IGNORE)
if not valid_creds(ansible_module, ipaadmin_principal):
ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
ipaadmin_password)
api_connect()
# Make sure forwardzone exists
existing_resource = find_dnsforwardzone(ansible_module, name)
if existing_resource is None and operation == "update":
# does not exist and is updating
# trying to update something that doesn't exist, so error
ansible_module.fail_json(msg="""dnsforwardzone '%s' is not
valid""" % (name))
elif existing_resource is None and operation == "del":
# does not exists and should be absent
# set command
command = None
# enabled or disabled?
is_enabled = "IGNORE"
elif existing_resource is not None and operation == "del":
# exists but should be absent
# set command
command = "dnsforwardzone_del"
# enabled or disabled?
is_enabled = "IGNORE"
elif forwarders is None:
# forwarders are not defined its not a delete, update state?
# set command
command = None
# enabled or disabled?
if existing_resource is not None:
is_enabled = existing_resource["idnszoneactive"][0]
else:
is_enabled = "IGNORE"
elif existing_resource is not None and operation == "update":
# exists and is updating
# calculate the new forwarders and mod
# determine args
if state != "absent":
forwarders = list(set(existing_resource["idnsforwarders"]
+ forwarders))
else:
forwarders = list(set(existing_resource["idnsforwarders"])
- set(forwarders))
args = gen_args(forwarders, forwardpolicy,
skip_overlap_check)
if skip_overlap_check is not None:
del args['skip_overlap_check']
# command
if not compare_args_ipa(ansible_module, args, existing_resource):
command = "dnsforwardzone_mod"
else:
command = None
# enabled or disabled?
is_enabled = existing_resource["idnszoneactive"][0]
elif existing_resource is None and operation == "add":
# does not exist but should be present
# determine args
args = gen_args(forwarders, forwardpolicy,
skip_overlap_check)
# set command
command = "dnsforwardzone_add"
# enabled or disabled?
is_enabled = "TRUE"
elif existing_resource is not None and operation == "add":
# exists and should be present, has it changed?
# determine args
args = gen_args(forwarders, forwardpolicy, skip_overlap_check)
if skip_overlap_check is not None:
del args['skip_overlap_check']
# set command
if not compare_args_ipa(ansible_module, args, existing_resource):
command = "dnsforwardzone_mod"
else:
command = None
# enabled or disabled?
is_enabled = existing_resource["idnszoneactive"][0]
# if command is set then run it with the args
if command is not None:
api_command(ansible_module, command, name, args)
changed = True
# does the enabled state match what we want (if we care)
if is_enabled != "IGNORE":
if wants_enable and is_enabled != "TRUE":
api_command(ansible_module, "dnsforwardzone_enable",
name, {})
changed = True
elif not wants_enable and is_enabled != "FALSE":
api_command(ansible_module, "dnsforwardzone_disable",
name, {})
changed = True
except Exception as e:
ansible_module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)
# Done
ansible_module.exit_json(changed=changed, dnsforwardzone=exit_args)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,474 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Sergio Oliveira Campos <seocam@redhat.com>
#
# Copyright (C) 2020 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
module: ipadnszone
short description: Manage FreeIPA dnszone
description: Manage FreeIPA dnszone
options:
ipaadmin_principal:
description: The admin principal
default: admin
ipaadmin_password:
description: The admin password
required: false
name:
description: The zone name string.
required: true
type: str
alises: ["zone_name"]
forwarders:
description: The list of global DNS forwarders.
required: false
options:
ip_address:
description: The forwarder nameserver IP address list (IPv4 and IPv6).
required: true
port:
description: The port to forward requests to.
required: false
forward_policy:
description:
Global forwarding policy. Set to "none" to disable any configured
global forwarders.
required: false
choices: ['only', 'first', 'none']
allow_sync_ptr:
description:
Allow synchronization of forward (A, AAAA) and reverse (PTR) records.
required: false
type: bool
state:
description: State to ensure
default: present
choices: ["present", "absent", "enabled", "disabled"]
name_server:
description: Authoritative nameserver domain name
required: false
type: str
admin_email:
description: Administrator e-mail address
required: false
type: str
update_policy:
description: BIND update policy
required: false
type: str
dynamic_update:
description: Allow dynamic updates
required: false
type: bool
alises: ["dynamicupdate"]
dnssec:
description: Allow inline DNSSEC signing of records in the zone
required: false
type: bool
allow_transfer:
description: List of IP addresses or networks which are allowed to transfer the zone
required: false
type: bool
allow_query:
description: List of IP addresses or networks which are allowed to issue queries
required: false
type: bool
serial:
description: SOA record serial number
required: false
type: int
refresh:
description: SOA record refresh time
required: false
type: int
retry:
description: SOA record retry time
required: false
type: int
expire:
description: SOA record expire time
required: false
type: int
minimum:
description: How long should negative responses be cached
required: false
type: int
ttl:
description: Time to live for records at zone apex
required: false
type: int
default_ttl:
description: Time to live for records without explicit TTL definition
required: false
type: int
nsec3param_rec:
description: NSEC3PARAM record for zone in format: hash_algorithm flags iterations salt.
required: false
type: str
skip_overlap_check:
description: Force DNS zone creation even if it will overlap with an existing zone
required: false
type: bool
skip_nameserver_check:
description: Force DNS zone creation even if nameserver is not resolvable
required: false
type: bool
""" # noqa: E501
EXAMPLES = """
---
# Ensure the zone is present (very minimal)
- ipadnszone:
name: test.example.com
# Ensure the zone is present (all available arguments)
- ipadnszone:
name: test.example.com
ipaadmin_password: SomeADMINpassword
allow_sync_ptr: true
dynamic_update: true
dnssec: true
allow_transfer:
- 1.1.1.1
- 2.2.2.2
allow_query:
- 1.1.1.1
- 2.2.2.2
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
port: 52
serial: 1234
refresh: 3600
retry: 900
expire: 1209600
minimum: 3600
ttl: 60
default_ttl: 90
name_server: ipaserver.test.local.
admin_email: admin.admin@example.com
nsec3param_rec: "1 7 100 0123456789abcdef"
skip_overlap_check: true
skip_nameserver_check: true
state: present
# Ensure zone is present and disabled
- ipadnszone:
name: test.example.com
state: disabled
# Ensure zone is present and enabled
- ipadnszone:
name: test.example.com
state: enabled
"""
RETURN = """
"""
from ipapython.dnsutil import DNSName # noqa: E402
from ansible.module_utils.ansible_freeipa_module import (
FreeIPABaseModule,
is_ipv4_addr,
is_ipv6_addr,
is_valid_port,
) # noqa: E402
class DNSZoneModule(FreeIPABaseModule):
ipa_param_mapping = {
# Direct Mapping
"idnsforwardpolicy": "forward_policy",
"idnssoaserial": "serial",
"idnssoarefresh": "refresh",
"idnssoaretry": "retry",
"idnssoaexpire": "expire",
"idnssoaminimum": "minimum",
"dnsttl": "ttl",
"dnsdefaultttl": "default_ttl",
"idnsallowsyncptr": "allow_sync_ptr",
"idnsallowdynupdate": "dynamic_update",
"idnssecinlinesigning": "dnssec",
"idnsupdatepolicy": "update_policy",
# Mapping by method
"idnsforwarders": "get_ipa_idnsforwarders",
"idnsallowtransfer": "get_ipa_idnsallowtransfer",
"idnsallowquery": "get_ipa_idnsallowquery",
"idnssoamname": "get_ipa_idnssoamname",
"idnssoarname": "get_ipa_idnssoarname",
"skip_nameserver_check": "get_ipa_skip_nameserver_check",
"skip_overlap_check": "get_ipa_skip_overlap_check",
"nsec3paramrecord": "get_ipa_nsec3paramrecord",
}
def validate_ips(self, ips, error_msg):
invalid_ips = [
ip for ip in ips if not is_ipv4_addr(ip) or is_ipv6_addr(ip)
]
if any(invalid_ips):
self.fail_json(msg=error_msg % invalid_ips)
def is_valid_nsec3param_rec(self, nsec3param_rec):
try:
part1, part2, part3, part4 = nsec3param_rec.split(" ")
except ValueError:
return False
if not all([part1.isdigit(), part2.isdigit(), part3.isdigit()]):
return False
if not 0 <= int(part1) <= 255:
return False
if not 0 <= int(part2) <= 255:
return False
if not 0 <= int(part3) <= 65535:
return False
try:
int(part4, 16)
except ValueError:
is_hex = False
else:
is_hex = True
even_digits = len(part4) % 2 == 0
is_dash = part4 == "-"
# If not hex with even digits or dash then
# part4 is invalid
if not ((is_hex and even_digits) or is_dash):
return False
return True
def get_ipa_nsec3paramrecord(self):
nsec3param_rec = self.ipa_params.nsec3param_rec
if nsec3param_rec is not None:
error_msg = (
"Invalid nsec3param_rec: %s. "
"Expected format: <0-255> <0-255> <0-65535> "
"even-length_hexadecimal_digits_or_hyphen"
) % nsec3param_rec
if not self.is_valid_nsec3param_rec(nsec3param_rec):
self.fail_json(msg=error_msg)
return nsec3param_rec
def get_ipa_idnsforwarders(self):
if self.ipa_params.forwarders is not None:
forwarders = []
for forwarder in self.ipa_params.forwarders:
ip_address = forwarder.get("ip_address")
if not (is_ipv4_addr(ip_address) or is_ipv6_addr(ip_address)):
self.fail_json(
msg="Invalid IP for DNS forwarder: %s" % ip_address
)
port = forwarder.get("port", None)
if port and not is_valid_port(port):
self.fail_json(
msg="Invalid port number for DNS forwarder: %s %s"
% (ip_address, port)
)
formatted_forwarder = ip_address
port = forwarder.get("port")
if port:
formatted_forwarder += " port %d" % port
forwarders.append(formatted_forwarder)
return forwarders
def get_ipa_idnsallowtransfer(self):
if self.ipa_params.allow_transfer is not None:
error_msg = "Invalid ip_address for DNS allow_transfer: %s"
self.validate_ips(self.ipa_params.allow_transfer, error_msg)
return (";".join(self.ipa_params.allow_transfer) or "none") + ";"
def get_ipa_idnsallowquery(self):
if self.ipa_params.allow_query is not None:
error_msg = "Invalid ip_address for DNS allow_query: %s"
self.validate_ips(self.ipa_params.allow_query, error_msg)
return (";".join(self.ipa_params.allow_query) or "any") + ";"
@staticmethod
def _replace_at_symbol_in_rname(rname):
"""
See RFC 1035 for more information.
Section 8. MAIL SUPPORT
https://tools.ietf.org/html/rfc1035#section-8
"""
if "@" not in rname:
return rname
name, domain = rname.split("@")
name = name.replace(".", r"\.")
return ".".join((name, domain))
def get_ipa_idnssoarname(self):
if self.ipa_params.admin_email is not None:
return DNSName(
self._replace_at_symbol_in_rname(self.ipa_params.admin_email)
)
def get_ipa_idnssoamname(self):
if self.ipa_params.name_server is not None:
return DNSName(self.ipa_params.name_server)
def get_ipa_skip_overlap_check(self):
if not self.zone and self.ipa_params.skip_overlap_check is not None:
return self.ipa_params.skip_overlap_check
def get_ipa_skip_nameserver_check(self):
if not self.zone and self.ipa_params.skip_nameserver_check is not None:
return self.ipa_params.skip_nameserver_check
def get_zone(self, zone_name):
get_zone_args = {"idnsname": zone_name, "all": True}
response = self.api_command("dnszone_find", args=get_zone_args)
if response["count"] == 1:
self.zone = response["result"][0]
self.is_zone_active = self.zone.get("idnszoneactive") == ["TRUE"]
return self.zone
# Zone doesn't exist yet
self.zone = None
self.is_zone_active = False
@property
def zone_name(self):
return self.ipa_params.name
def define_ipa_commands(self):
# Look for existing zone in IPA
self.get_zone(self.zone_name)
args = self.get_ipa_command_args()
just_added = False
if self.ipa_params.state in ["present", "enabled", "disabled"]:
if not self.zone:
# Since the zone doesn't exist we just create it
# with given args
self.add_ipa_command("dnszone_add", self.zone_name, args)
self.is_zone_active = True
just_added = True
else:
# Zone already exist so we need to verify if given args
# matches the current config. If not we updated it.
if self.require_ipa_attrs_change(args, self.zone):
self.add_ipa_command("dnszone_mod", self.zone_name, args)
if self.ipa_params.state == "enabled" and not self.is_zone_active:
self.add_ipa_command("dnszone_enable", self.zone_name)
if self.ipa_params.state == "disabled" and self.is_zone_active:
self.add_ipa_command("dnszone_disable", self.zone_name)
if self.ipa_params.state == "absent":
if self.zone:
self.add_ipa_command("dnszone_del", self.zone_name)
# Due to a bug in FreeIPA dnszone-add won't set
# SOA Serial. The good news is that dnszone-mod does the job.
# See: https://pagure.io/freeipa/issue/8227
# Because of that, if the zone was just added with a given serial
# we run mod just after to workaround the bug
if just_added and self.ipa_params.serial is not None:
args = {
"idnssoaserial": self.ipa_params.serial,
}
self.add_ipa_command("dnszone_mod", self.zone_name, args)
def get_argument_spec():
forwarder_spec = dict(
ip_address=dict(type=str, required=True),
port=dict(type=int, required=False, default=None),
)
return dict(
state=dict(
type="str",
default="present",
choices=["present", "absent", "enabled", "disabled"],
),
ipaadmin_principal=dict(type="str", default="admin"),
ipaadmin_password=dict(type="str", required=False, no_log=True),
name=dict(
type="str", default=None, required=True, aliases=["zone_name"]
),
forwarders=dict(
type="list",
default=None,
required=False,
options=dict(**forwarder_spec),
),
forward_policy=dict(
type="str",
required=False,
default=None,
choices=["only", "first", "none"],
),
name_server=dict(type="str", required=False, default=None),
admin_email=dict(type="str", required=False, default=None),
allow_sync_ptr=dict(type="bool", required=False, default=None),
update_policy=dict(type="str", required=False, default=None),
dynamic_update=dict(
type="bool",
required=False,
default=None,
aliases=["dynamicupdate"],
),
dnssec=dict(type="bool", required=False, default=None),
allow_transfer=dict(type="list", required=False, default=None),
allow_query=dict(type="list", required=False, default=None),
serial=dict(type="int", required=False, default=None),
refresh=dict(type="int", required=False, default=None),
retry=dict(type="int", required=False, default=None),
expire=dict(type="int", required=False, default=None),
minimum=dict(type="int", required=False, default=None),
ttl=dict(type="int", required=False, default=None),
default_ttl=dict(type="int", required=False, default=None),
nsec3param_rec=dict(type="str", required=False, default=None),
skip_nameserver_check=dict(type="bool", required=False, default=None),
skip_overlap_check=dict(type="bool", required=False, default=None),
)
def main():
DNSZoneModule(argument_spec=get_argument_spec()).ipa_run()
if __name__ == "__main__":
main()

View File

@@ -76,6 +76,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
setup_logging,
paths, x509, NUM_VERSION, serialization, certdb, api,
delete_persistent_client_session_data, write_tmp_file,
ipa_generate_password, CalledProcessError, errors, disable_ra, DN,
@@ -95,6 +96,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
realm = module.params.get('realm')
hostname = module.params.get('hostname')
servers = module.params.get('servers')

View File

@@ -67,6 +67,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
setup_logging,
SECURE_PATH, paths, sysrestore, options, NUM_VERSION, get_ca_cert,
get_ca_certs, errors
)
@@ -83,6 +84,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
servers = module.params.get('servers')
realm = module.params.get('realm')
basedn = module.params.get('basedn')

View File

@@ -53,7 +53,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
paths, sysrestore
setup_logging, paths, sysrestore
)
@@ -65,6 +65,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
backup = module.params.get('backup')
fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)

View File

@@ -70,7 +70,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
paths, sysrestore, configure_ipa_conf
setup_logging, paths, sysrestore, configure_ipa_conf
)
@@ -87,6 +87,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
servers = module.params.get('servers')
domain = module.params.get('domain')
realm = module.params.get('realm')

View File

@@ -127,6 +127,7 @@ import tempfile
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
setup_logging,
SECURE_PATH, sysrestore, paths, options, configure_krb5_conf,
realm_to_suffix, kinit_keytab, GSSError, kinit_password, NUM_VERSION,
get_ca_cert, get_ca_certs, errors, run
@@ -155,6 +156,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
servers = module.params.get('servers')
domain = module.params.get('domain')
realm = module.params.get('realm')

View File

@@ -54,7 +54,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
sysrestore, paths, tasks
setup_logging, sysrestore, paths, tasks
)
@@ -67,6 +67,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
hostname = module.params.get('hostname')
fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)

View File

@@ -60,7 +60,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
options, configure_automount
setup_logging, options, configure_automount
)
@@ -77,6 +77,8 @@ def main():
# os.environ['KRB5CCNAME'] = paths.IPA_DNS_CCACHE
module._ansible_debug = True
setup_logging()
options.servers = module.params.get('servers')
options.server = options.servers
options.sssd = module.params.get('sssd')

View File

@@ -60,7 +60,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
sysrestore, paths, options, configure_firefox
setup_logging, sysrestore, paths, options, configure_firefox
)
@@ -74,6 +74,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
domain = module.params.get('domain')
options.firefox_dir = module.params.get('firefox_dir')

View File

@@ -81,7 +81,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
sysrestore, paths, configure_krb5_conf, logger
setup_logging, sysrestore, paths, configure_krb5_conf, logger
)
@@ -103,6 +103,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
servers = module.params.get('servers')
domain = module.params.get('domain')
realm = module.params.get('realm')

View File

@@ -58,7 +58,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
options, sysrestore, paths, configure_nisdomain
setup_logging, options, sysrestore, paths, configure_nisdomain
)
@@ -72,6 +72,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
domain = module.params.get('domain')
options.nisdomain = module.params.get('nisdomain')

View File

@@ -138,6 +138,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
setup_logging,
options, sysrestore, paths, ansible_module_get_parsed_ip_addresses,
api, errors, create_ipa_nssdb, ipautil, ScriptError, CLIENT_INSTALL_ERROR,
get_certs_from_ldap, DN, certstore, x509, logger, certdb,
@@ -179,6 +180,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
cli_server = module.params.get('servers')
cli_realm = module.params.get('realm')
hostname = module.params.get('hostname')

View File

@@ -67,6 +67,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
setup_logging,
options, sysrestore, paths, sync_time, logger, ipadiscovery,
timeconf
)
@@ -89,6 +90,8 @@ def main():
)
# module._ansible_debug = True
setup_logging()
options.ntp_servers = module.params.get('ntp_servers')
options.ntp_pool = module.params.get('ntp_pool')
options.no_ntp = module.params.get('no_ntp')

View File

@@ -68,6 +68,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
setup_logging,
options, sysrestore, paths, configure_ssh_config, configure_sshd_config
)
@@ -85,6 +86,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
options.servers = module.params.get('servers')
options.server = options.servers
options.no_ssh = module.params.get('no_ssh')

View File

@@ -101,7 +101,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
options, sysrestore, paths, configure_sssd_conf, logger
setup_logging, options, sysrestore, paths, configure_sssd_conf, logger
)
@@ -130,6 +130,8 @@ def main():
# options.set_logger(ansible_log)
module._ansible_debug = True
setup_logging()
cli_server = module.params.get('servers')
cli_domain = module.params.get('domain')
cli_realm = module.params.get('realm')

View File

@@ -199,6 +199,7 @@ except ImportError:
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
setup_logging,
paths, sysrestore, options, CheckedIPAddress, validate_domain_name,
logger, x509, normalize_hostname, installer, version, ScriptError,
CLIENT_INSTALL_ERROR, tasks, check_ldap_conf, timeconf, constants,
@@ -290,6 +291,8 @@ def main():
)
# module._ansible_debug = True
setup_logging()
options.domain_name = module.params.get('domain')
options.servers = module.params.get('servers')
options.realm_name = module.params.get('realm')

View File

@@ -103,6 +103,7 @@ import tempfile
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_client import (
setup_logging,
SECURE_PATH, paths, kinit_keytab, run, GSSError, configure_krb5_conf
)
@@ -121,6 +122,8 @@ def main():
)
module._ansible_debug = True
setup_logging()
servers = module.params.get('servers')
domain = module.params.get('domain')
realm = module.params.get('realm')

View File

@@ -259,9 +259,6 @@ if NUM_VERSION >= 40400:
sssd_enable_ifp = None
logger = logging.getLogger("ipa-client-install")
standard_logging_setup(
paths.IPACLIENT_INSTALL_LOG, verbose=False, debug=False,
filemode='a', console_format='%(message)s')
root_logger = logger
else:
@@ -270,6 +267,12 @@ else:
raise Exception("freeipa version '%s' is too old" % VERSION)
def setup_logging():
standard_logging_setup(
paths.IPACLIENT_INSTALL_LOG, verbose=False, debug=False,
filemode='a', console_format='%(message)s')
def ansible_module_get_parsed_ip_addresses(ansible_module,
param='ip_addresses'):
ip_addresses = ansible_module.params.get(param)

View File

@@ -191,7 +191,7 @@
# 5 - Principal name or realm not found in keytab
failed_when: result_ipa_rmkeytab.rc != 0 and
result_ipa_rmkeytab.rc != 3 and result_ipa_rmkeytab.rc != 5
when: ipaclient_use_otp | bool or ipaclient_force_join | bool
when: (ipaclient_use_otp | bool or ipaclient_force_join | bool) and not ipaclient_on_master | bool
- name: Install - Backup and set hostname
ipaclient_set_hostname:

View File

@@ -67,7 +67,7 @@ import six
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, paths,
AnsibleModuleLog, setup_logging, installer, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_remote_api, api
)
@@ -91,6 +91,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -137,7 +137,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
ansible_module_get_parsed_ip_addresses, sysrestore,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, create_ipa_conf
@@ -186,6 +186,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -99,7 +99,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, redirect_stdout, custodiainstance
)
@@ -131,6 +131,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -100,7 +100,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout,
replica_ds_init_info, dsinstance, upgradeinstance, installutils
@@ -133,6 +133,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -97,7 +97,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout,
replica_ds_init_info
@@ -129,6 +129,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -77,7 +77,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, service,
find_providing_servers, services
@@ -103,6 +103,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -137,7 +137,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
ansible_module_get_parsed_ip_addresses,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, ipaldap,
@@ -186,6 +186,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -86,7 +86,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths, sysrestore,
AnsibleModuleLog, setup_logging, installer, DN, paths, sysrestore,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, krbinstance, redirect_stdout
)
@@ -114,6 +114,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -53,7 +53,7 @@ password:
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
ipa_generate_password
setup_logging, ipa_generate_password
)
@@ -67,6 +67,7 @@ def main():
)
module._ansible_debug = True
setup_logging()
master_password = module.params.get('master_password')

File diff suppressed because it is too large Load Diff

View File

@@ -71,7 +71,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, redirect_stdout, promote_openldap_conf
)
@@ -94,6 +94,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -71,7 +71,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, redirect_stdout, promote_sssd
)
@@ -94,6 +94,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -83,7 +83,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths, sysrestore,
AnsibleModuleLog, setup_logging, installer, DN, paths, sysrestore,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, service,
krbinstance
@@ -111,6 +111,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -87,7 +87,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths, sysrestore,
AnsibleModuleLog, setup_logging, installer, DN, paths, sysrestore,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, adtrust
)
@@ -117,6 +117,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -113,7 +113,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
ansible_module_get_parsed_ip_addresses,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, ca,
@@ -153,6 +153,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -49,7 +49,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, redirect_stdout, configure_certmonger
AnsibleModuleLog, setup_logging, redirect_stdout, configure_certmonger
)
@@ -61,6 +61,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -95,7 +95,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, custodiainstance
)
@@ -126,6 +126,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -92,7 +92,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, dns,
ansible_module_get_parsed_ip_addresses
@@ -125,6 +125,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -152,7 +152,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths, sysrestore,
AnsibleModuleLog, setup_logging, installer, DN, paths, sysrestore,
ansible_module_get_parsed_ip_addresses,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, redirect_stdout, ipaldap,
@@ -205,6 +205,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -93,7 +93,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths, sysrestore,
AnsibleModuleLog, setup_logging, installer, DN, paths, sysrestore,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, create_ipa_conf,
install_http
@@ -123,6 +123,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -96,9 +96,6 @@ options:
config_master_host_name:
description: The config master_host_name setting
required: no
ccache:
description: The local ccache
required: no
installer_ccache:
description: The installer ccache setting
required: no
@@ -137,7 +134,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
ansible_module_get_parsed_ip_addresses,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, custodiainstance,
@@ -172,7 +169,6 @@ def main():
# additional
server=dict(required=True),
config_master_host_name=dict(required=True),
ccache=dict(required=True),
installer_ccache=dict(required=True),
_ca_enabled=dict(required=False, type='bool'),
_kra_enabled=dict(required=False, type='bool'),
@@ -186,6 +182,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #
@@ -231,8 +228,6 @@ def main():
# additional
options.server = ansible_module.params.get('server')
master_host_name = ansible_module.params.get('config_master_host_name')
ccache = ansible_module.params.get('ccache')
# os.environ['KRB5CCNAME'] = ccache
os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache')
installer._ccache = ansible_module.params.get('installer_ccache')
ca_enabled = ansible_module.params.get('_ca_enabled')
@@ -267,8 +262,6 @@ def main():
remote_api = gen_remote_api(master_host_name, paths.ETC_IPA)
installer._remote_api = remote_api
# ccache = os.environ['KRB5CCNAME']
with redirect_stdout(ansible_log):
ansible_log.debug("-- INSTALL KRA --")

View File

@@ -78,7 +78,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths, sysrestore,
AnsibleModuleLog, setup_logging, installer, DN, paths, sysrestore,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, api, redirect_stdout, install_krb
)
@@ -103,6 +103,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #
@@ -154,19 +155,19 @@ def main():
with redirect_stdout(ansible_log):
argspec = inspect.getargspec(install_krb)
if "promote" in argspec.args:
krb = install_krb(
install_krb(
config,
setup_pkinit=not options.no_pkinit,
pkcs12_info=pkinit_pkcs12_info,
promote=promote)
else:
if "fstore" not in argspec.args:
krb = install_krb(
install_krb(
config,
setup_pkinit=not options.no_pkinit,
pkcs12_info=pkinit_pkcs12_info)
else:
krb = install_krb(
install_krb(
config,
setup_pkinit=not options.no_pkinit,
pkcs12_info=pkinit_pkcs12_info,

View File

@@ -83,7 +83,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, installer, DN, paths,
AnsibleModuleLog, setup_logging, installer, DN, paths,
gen_env_boostrap_finalize_core, constants, api_bootstrap_finalize,
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, otpdinstance,
ipautil
@@ -111,6 +111,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -131,7 +131,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_replica import (
AnsibleModuleLog, options, installer, paths, sysrestore,
AnsibleModuleLog, setup_logging, options, installer, paths, sysrestore,
ansible_module_get_parsed_ip_addresses, service,
redirect_stdout, create_ipa_conf, ipautil,
x509, validate_domain_name, common_check,
@@ -179,6 +179,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# get parameters #

View File

@@ -140,10 +140,13 @@ else:
logger = logging.getLogger("ipa-server-install")
# logger.setLevel(logging.DEBUG)
standard_logging_setup(
paths.IPAREPLICA_INSTALL_LOG, verbose=False, debug=False,
filemode='a', console_format='%(message)s')
def setup_logging():
# logger.setLevel(logging.DEBUG)
standard_logging_setup(
paths.IPAREPLICA_INSTALL_LOG, verbose=False, debug=False,
filemode='a', console_format='%(message)s')
@contextlib_contextmanager

View File

@@ -606,7 +606,6 @@
server: "{{ result_ipareplica_test.server }}"
config_master_host_name:
"{{ result_ipareplica_prepare.config_master_host_name }}"
ccache: "{{ result_ipareplica_prepare.ccache }}"
installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}"
_ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
_kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}"

View File

@@ -57,7 +57,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, paths, api, sysrestore, tasks,
AnsibleModuleLog, setup_logging, options, paths, api, sysrestore, tasks,
service, bindinstance, redirect_stdout, services
)
@@ -72,6 +72,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values #############################################################

View File

@@ -53,7 +53,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
options, paths, read_cache
setup_logging, options, paths, read_cache
)
@@ -66,6 +66,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
# set values ############################################################

View File

@@ -58,7 +58,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
options, paths, read_cache, ipa_generate_password
setup_logging, options, paths, read_cache, ipa_generate_password
)
@@ -73,6 +73,7 @@ def main():
)
module._ansible_debug = True
setup_logging()
options.dm_password = module.params.get('dm_password')
options.master_password = module.params.get('master_password')

View File

@@ -157,7 +157,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, sysrestore, paths,
AnsibleModuleLog, setup_logging, options, sysrestore, paths,
ansible_module_get_parsed_ip_addresses,
redirect_stdout, adtrust, api, default_subject_base,
default_ca_subject_dn, ipautil, installutils, ca, kra, dns,
@@ -219,6 +219,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# initialize return values for flake ############################

View File

@@ -58,7 +58,7 @@ options:
description: The starting value for the IDs range (default random)
required: no
idmax:
description: The max value for the IDs range (default: idstart+199999)
description: The max value for the IDs range (default idstart+199999)
required: no
no_hbac_allow:
description: Don't install allow_all HBAC rule
@@ -107,7 +107,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
MAX_DOMAIN_LEVEL, AnsibleModuleLog, options, sysrestore, paths,
api_Backend_ldap2, ds_init_info, redirect_stdout
api_Backend_ldap2, ds_init_info, redirect_stdout, setup_logging
)
@@ -141,6 +141,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ####################################################

View File

@@ -73,7 +73,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, sysrestore, paths,
AnsibleModuleLog, setup_logging, options, sysrestore, paths,
api_Backend_ldap2, redirect_stdout, adtrust, api
)
@@ -96,6 +96,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ####################################################

View File

@@ -79,7 +79,7 @@ options:
description: The starting value for the IDs range (default random)
required: no
idmax:
description: The max value for the IDs range (default: idstart+199999)
description: The max value for the IDs range (default idstart+199999)
required: no
no_hbac_allow:
description: Don't install allow_all HBAC rule
@@ -160,7 +160,7 @@ import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, sysrestore, paths,
AnsibleModuleLog, setup_logging, options, sysrestore, paths,
ansible_module_get_parsed_ip_addresses,
api_Backend_ldap2, redirect_stdout, ca, installutils, ds_init_info,
custodiainstance, write_cache, x509
@@ -214,6 +214,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ############################################################

View File

@@ -57,7 +57,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options,
setup_logging, AnsibleModuleLog, options,
api_Backend_ldap2,
custodiainstance, redirect_stdout
)
@@ -74,6 +74,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ############################################################

View File

@@ -84,7 +84,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, paths, dns,
AnsibleModuleLog, setup_logging, options, paths, dns,
ansible_module_get_parsed_ip_addresses, sysrestore, api_Backend_ldap2,
redirect_stdout, bindinstance
)
@@ -114,6 +114,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ############################################################

View File

@@ -55,7 +55,7 @@ options:
description: The starting value for the IDs range (default random)
required: no
idmax:
description: The max value for the IDs range (default: idstart+199999)
description: The max value for the IDs range (default idstart+199999)
required: no
no_hbac_allow:
description: Don't install allow_all HBAC rule
@@ -103,7 +103,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, sysrestore, paths,
AnsibleModuleLog, setup_logging, options, sysrestore, paths,
api_Backend_ldap2, redirect_stdout, api, NUM_VERSION, tasks,
dsinstance, ntpinstance, IPAAPI_USER
)
@@ -138,6 +138,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ############################################################

View File

@@ -111,7 +111,7 @@ options:
description: The starting value for the IDs range (default random)
required: no
idmax:
description: The max value for the IDs range (default: idstart+199999)
description: The max value for the IDs range (default idstart+199999)
required: no
domainlevel:
description: The domain level
@@ -149,7 +149,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, sysrestore, paths,
AnsibleModuleLog, setup_logging, options, sysrestore, paths,
ansible_module_get_parsed_ip_addresses,
api_Backend_ldap2, redirect_stdout, ds_init_info,
krbinstance, httpinstance, ca, service, tasks
@@ -205,6 +205,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ############################################################

View File

@@ -66,7 +66,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options,
AnsibleModuleLog, setup_logging, options,
api_Backend_ldap2, redirect_stdout, api, custodiainstance, kra
)
@@ -85,6 +85,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ####################################################

View File

@@ -98,7 +98,7 @@ options:
description: The starting value for the IDs range (default random)
required: no
idmax:
description: The max value for the IDs range (default: idstart+199999)
description: The max value for the IDs range (default idstart+199999)
required: no
no_reverse:
description: Do not create new reverse DNS zone
@@ -121,7 +121,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, sysrestore, paths,
AnsibleModuleLog, setup_logging, options, sysrestore, paths,
ansible_module_get_parsed_ip_addresses,
api_Backend_ldap2, redirect_stdout, krbinstance
)
@@ -165,6 +165,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ############################################################

View File

@@ -56,7 +56,7 @@ import inspect
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, sysrestore, paths,
AnsibleModuleLog, setup_logging, options, sysrestore, paths,
redirect_stdout, time_service, sync_time, ntpinstance, timeconf
)
@@ -70,6 +70,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ############################################################

View File

@@ -57,7 +57,7 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options,
AnsibleModuleLog, setup_logging, options,
api_Backend_ldap2, redirect_stdout, otpdinstance, ipautil
)
@@ -73,6 +73,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ####################################################

View File

@@ -79,7 +79,7 @@ options:
description: The starting value for the IDs range (default random)
required: yes
idmax:
description: The max value for the IDs range (default: idstart+199999)
description: The max value for the IDs range (default idstart+199999)
required: yes
no_pkinit:
description: Disable pkinit setup steps
@@ -211,9 +211,10 @@ import inspect
import random
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.ansible_ipa_server import (
AnsibleModuleLog, options, adtrust_imported, kra_imported, PKIIniLoader,
MIN_DOMAIN_LEVEL, MAX_DOMAIN_LEVEL, check_zone_overlap,
AnsibleModuleLog, setup_logging, options, adtrust_imported, kra_imported,
PKIIniLoader, MIN_DOMAIN_LEVEL, MAX_DOMAIN_LEVEL, check_zone_overlap,
redirect_stdout, validate_dm_password, validate_admin_password,
NUM_VERSION, is_ipa_configured, sysrestore, paths, bindinstance,
read_cache, ca, tasks, check_ldap_conf, timeconf, httpinstance,
@@ -302,6 +303,7 @@ def main():
)
ansible_module._ansible_debug = True
setup_logging()
ansible_log = AnsibleModuleLog(ansible_module)
# set values ############################################################
@@ -583,7 +585,7 @@ def main():
"--auto-forwarders, or --no-forwarders options")
except RuntimeError as e:
ansible_module.fail_json(msg=e)
ansible_module.fail_json(msg=to_native(e))
# #######################################################################

View File

@@ -144,10 +144,13 @@ else:
logger = logging.getLogger("ipa-server-install")
# logger.setLevel(logging.DEBUG)
standard_logging_setup(
paths.IPASERVER_INSTALL_LOG, verbose=False, debug=False,
filemode='a', console_format='%(message)s')
def setup_logging():
# logger.setLevel(logging.DEBUG)
standard_logging_setup(
paths.IPASERVER_INSTALL_LOG, verbose=False, debug=False,
filemode='a', console_format='%(message)s')
@contextlib_contextmanager

View File

@@ -8,6 +8,7 @@
# Setup.
- name: Ensure forwarders are absent.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
@@ -20,6 +21,7 @@
- name: Set dnsconfig.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
@@ -32,6 +34,7 @@
- name: Set dnsconfig, with the same values.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
@@ -44,6 +47,7 @@
- name: Ensure forwarder is absent.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.8.8
state: absent
@@ -52,6 +56,7 @@
- name: Ensure forwarder is absent, again.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.8.8
state: absent
@@ -60,54 +65,63 @@
- name: Disable global forwarders.
ipadnsconfig:
forward_policy: none
ipaadmin_password: SomeADMINpassword
forward_policy: none
register: result
failed_when: not result.changed
- name: Disable global forwarders, again.
ipadnsconfig:
forward_policy: none
ipaadmin_password: SomeADMINpassword
forward_policy: none
register: result
failed_when: result.changed
- name: Re-enable global forwarders.
ipadnsconfig:
forward_policy: first
ipaadmin_password: SomeADMINpassword
forward_policy: first
register: result
failed_when: not result.changed
- name: Re-enable global forwarders, again.
ipadnsconfig:
forward_policy: first
ipaadmin_password: SomeADMINpassword
forward_policy: first
register: result
failed_when: result.changed
- name: Disable PTR record synchronization.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
allow_sync_ptr: no
register: result
failed_when: not result.changed
- name: Disable PTR record synchronization, again.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
allow_sync_ptr: no
register: result
failed_when: result.changed
- name: Re-enable PTR record synchronization.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
allow_sync_ptr: yes
register: result
failed_when: not result.changed
- name: Re-enable PTR record synchronization, again.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
allow_sync_ptr: yes
register: result
failed_when: result.changed
- name: Ensure all forwarders are absent.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
@@ -120,6 +134,7 @@
- name: Ensure all forwarders are absent, again.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
@@ -132,6 +147,7 @@
# Cleanup.
- name: Ensure forwarders are absent.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4

View File

@@ -0,0 +1,214 @@
---
- name: Test dnsforwardzone
hosts: ipaserver
become: true
gather_facts: false
tasks:
- name: ensure forwardzone example.com is absent - prep
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: absent
- name: ensure forwardzone example.com is created
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 8.8.8.8
forwardpolicy: first
skip_overlap_check: true
register: result
failed_when: not result.changed
- name: ensure forwardzone example.com is present again
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 8.8.8.8
forwardpolicy: first
skip_overlap_check: true
register: result
failed_when: result.changed
- name: ensure forwardzone example.com has two forwarders
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 8.8.8.8
- 4.4.4.4
forwardpolicy: first
skip_overlap_check: true
register: result
failed_when: not result.changed
- name: ensure forwardzone example.com has one forwarder again
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
forwarders:
- 8.8.8.8
forwardpolicy: first
skip_overlap_check: true
state: present
register: result
failed_when: not result.changed
- name: skip_overlap_check can only be set on creation so change nothing
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
forwarders:
- 8.8.8.8
forwardpolicy: first
skip_overlap_check: false
state: present
register: result
failed_when: result.changed
- name: change all the things at once
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 8.8.8.8
- 4.4.4.4
forwardpolicy: only
skip_overlap_check: false
register: result
failed_when: not result.changed
- name: ensure forwardzone example.com is absent for next testset
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: absent
- name: ensure forwardzone example.com is created with minimal args
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
skip_overlap_check: true
forwarders:
- 8.8.8.8
register: result
failed_when: not result.changed
- name: add a forwarder to any existing ones
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 4.4.4.4
action: member
register: result
failed_when: not result.changed
- name: check the list of forwarders is what we expect
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 4.4.4.4
- 8.8.8.8
action: member
register: result
failed_when: result.changed
- name: remove a single forwarder
ipadnsforwardzone:
ipaadmin_password: password01
state: absent
name: example.com
forwarders:
- 8.8.8.8
action: member
register: result
failed_when: not result.changed
- name: check the list of forwarders is what we expect now
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 4.4.4.4
action: member
register: result
failed_when: result.changed
- name: ensure forwardzone example.com is absent again
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: absent
- name: try to create a new forwarder with action=member
ipadnsforwardzone:
ipaadmin_password: password01
state: present
name: example.com
forwarders:
- 4.4.4.4
action: member
skip_overlap_check: true
register: result
failed_when: result.changed
- name: ensure forwardzone example.com is absent - tidy up
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: absent
- name: try to create a new forwarder is disabled state
ipadnsforwardzone:
ipaadmin_password: password01
state: disabled
name: example.com
forwarders:
- 4.4.4.4
skip_overlap_check: true
register: result
failed_when: not result.changed
- name: enable the forwarder
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: enabled
register: result
failed_when: not result.changed
- name: disable the forwarder again
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: disabled
action: member
register: result
failed_when: not result.changed
- name: ensure it stays disabled
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: disabled
register: result
failed_when: result.changed
- name: ensure forwardzone example.com is absent - tidy up
ipadnsforwardzone:
ipaadmin_password: password01
name: example.com
state: absent

View File

@@ -0,0 +1,151 @@
---
- name: Test dnszone
hosts: ipaserver
become: true
gather_facts: true
tasks:
# Setup
- name: Ensure zone is absent.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: absent
# Tests
- name: Ensure zone is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: present
register: result
failed_when: not result.changed
- name: Ensure zone is present, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: present
register: result
failed_when: result.changed
- name: Ensure zone is disabled.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: disabled
register: result
failed_when: not result.changed
- name: Ensure zone is disabled, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: disabled
register: result
failed_when: result.changed
- name: Ensure zone is enabled.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: enabled
register: result
failed_when: not result.changed
- name: Ensure zone is enabled, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: enabled
register: result
failed_when: result.changed
- name: Ensure forward_policy is none.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forward_policy: none
register: result
failed_when: not result.changed
- name: Ensure forward_policy is none, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forward_policy: none
register: result
failed_when: result.changed
- name: Ensure forward_policy is first.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forward_policy: first
register: result
failed_when: not result.changed
- name: Ensure forward_policy is first, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forward_policy: first
register: result
failed_when: result.changed
- name: Ensure first forwarder is set.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forwarders:
- ip_address: 8.8.8.8
port: 53
register: result
failed_when: not result.changed
- name: Ensure first and second forwarder are set.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forwarders:
- ip_address: 8.8.8.8
port: 53
- ip_address: 2001:4860:4860::8888
register: result
failed_when: not result.changed
- name: Ensure first and second forwarder are set, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forwarders:
- ip_address: 8.8.8.8
port: 53
- ip_address: 2001:4860:4860::8888
register: result
failed_when: result.changed
- name: Ensure only second forwarder is set.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forwarders:
- ip_address: 2001:4860:4860::8888
register: result
failed_when: not result.changed
- name: Nothing changes.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
register: result
failed_when: result.changed
- name: Ensure no forwarders are set.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
forwarders: []
register: result
failed_when: not result.changed

View File

@@ -0,0 +1,319 @@
---
- name: Test dnszone
hosts: ipaserver
become: true
gather_facts: true
tasks:
# Setup
- name: Ensure zone is absent.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
state: absent
# Tests
- name: Ensure zone is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_sync_ptr: true
dynamic_update: true
dnssec: true
allow_transfer:
- 1.1.1.1
- 2.2.2.2
allow_query:
- 1.1.1.1
- 2.2.2.2
serial: 1234
refresh: 3600
retry: 900
expire: 1209600
minimum: 3600
ttl: 60
default_ttl: 60
name_server: ipaserver.test.local.
skip_nameserver_check: true
admin_email: admin@example.com
nsec3param_rec: "1 7 100 abcd"
state: present
register: result
failed_when: not result.changed
- name: Set serial to 1234, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
serial: 1234
register: result
failed_when: result.changed
- name: Set different nsec3param_rec.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
nsec3param_rec: "2 8 200 abcd"
register: result
failed_when: not result.changed
- name: Set same nsec3param_rec.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
nsec3param_rec: "2 8 200 abcd"
register: result
failed_when: result.changed
- name: Set default_ttl to 1200
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
default_ttl: 1200
register: result
failed_when: not result.changed
- name: Set default_ttl to 1200, again
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
default_ttl: 1200
register: result
failed_when: result.changed
- name: Set ttl to 900
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
ttl: 900
register: result
failed_when: not result.changed
- name: Set ttl to 900, again
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
ttl: 900
register: result
failed_when: result.changed
- name: Set minimum to 1000
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
minimum: 1000
register: result
failed_when: not result.changed
- name: Set minimum to 1000, again
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
minimum: 1000
register: result
failed_when: result.changed
- name: Set expire to 1209601
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
expire: 1209601
register: result
failed_when: not result.changed
- name: Set expire to 1209601, again
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
expire: 1209601
register: result
failed_when: result.changed
- name: Set retry to 1200.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
retry: 1200
register: result
failed_when: not result.changed
- name: Set retry to 1200, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
retry: 1200
register: result
failed_when: result.changed
- name: Set refresh to 4000.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
refresh: 4000
register: result
failed_when: not result.changed
- name: Set refresh to 4000, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
refresh: 4000
register: result
failed_when: result.changed
- name: Set serial to 12345.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
serial: 12345
register: result
failed_when: not result.changed
- name: Set serial to 12345, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
serial: 12345
register: result
failed_when: result.changed
- name: Set dnssec to false.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
dnssec: false
register: result
failed_when: not result.changed
- name: Set dnssec to false, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
dnssec: false
register: result
failed_when: result.changed
- name: Set allow_sync_ptr to false.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_sync_ptr: false
register: result
failed_when: not result.changed
- name: Set allow_sync_ptr to false, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_sync_ptr: false
register: result
failed_when: result.changed
- name: Set dynamic_update to false.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
dynamic_update: false
register: result
failed_when: not result.changed
- name: Set dynamic_update to false, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
dynamic_update: false
register: result
failed_when: result.changed
- name: Update allow_transfer.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_transfer:
- 1.1.1.1
- 2.2.2.2
- 3.3.3.3
register: result
failed_when: not result.changed
- name: Update allow_transfer, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_transfer:
- 1.1.1.1
- 2.2.2.2
- 3.3.3.3
register: result
failed_when: result.changed
- name: Remove allow transfer.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_transfer: []
register: result
failed_when: not result.changed
- name: Remove allow transfer, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_transfer: []
register: result
failed_when: result.changed
- name: Update allow_query.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_query:
- 1.1.1.1
- 2.2.2.2
- 3.3.3.3
register: result
failed_when: not result.changed
- name: Update allow_query, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_query:
- 1.1.1.1
- 2.2.2.2
- 3.3.3.3
register: result
failed_when: result.changed
- name: Ensure allow query is empty.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_query: []
register: result
failed_when: not result.changed
- name: Ensure allow query is empty, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
allow_query: []
register: result
failed_when: result.changed
- name: Update admin email.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
admin_email: admin2@example.com
register: result
failed_when: not result.changed
- name: Update admin email, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
admin_email: admin2@example.com
register: result
failed_when: result.changed

View File

@@ -7,6 +7,38 @@
tasks:
# setup
- name: Ensure user is absent
ipauser:
ipaadmin_password: SomeADMINpassword
name: user01
state: absent
- name: Ensure group is absent
ipagroup:
ipaadmin_password: SomeADMINpassword
name: group01
state: absent
- name: Ensure user is present
ipauser:
ipaadmin_password: SomeADMINpassword
name: user01
first: user
last: zeroone
- name: Ensure group is present, with user01 on it.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: group01
user: user01
- name: Ensure sudocmdgroup is absent
ipasudocmdgroup:
ipaadmin_password: SomeADMINpassword
name: test_sudorule
state: absent
- name: Ensure hostgroup is present, with a host.
ipahostgroup:
ipaadmin_password: SomeADMINpassword
@@ -39,6 +71,8 @@
- allcommands
state: absent
# tests
- name: Ensure sudorule is present
ipasudorule:
ipaadmin_password: SomeADMINpassword
@@ -53,11 +87,87 @@
register: result
failed_when: result.changed
- name: Ensure sudorule is present, runAsUserCategory.
- name: Ensure user01 is on the list of users sudorule execute as.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
runAsUserCategory: all
runasuser:
- user01
action: member
register: result
failed_when: not result.changed
- name: Ensure user01 is on the list of users sudorule execute as, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
runasuser:
- user01
action: member
register: result
failed_when: result.changed
- name: Ensure user01 is not on the list of users sudorule execute as.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
runasuser:
- user01
action: member
state: absent
register: result
failed_when: not result.changed
- name: Ensure user01 is not on the list of users sudorule execute as, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
runasuser:
- user01
action: member
state: absent
register: result
failed_when: result.changed
- name: Ensure group01 is on the list of group sudorule execute as.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
runasgroup:
- group01
action: member
register: result
failed_when: not result.changed
- name: Ensure group01 is on the list of group sudorule execute as, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
runasgroup:
- group01
action: member
register: result
failed_when: result.changed
- name: Ensure group01 is not on the list of group sudorule execute as.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
runasgroup:
- group01
action: member
state: absent
register: result
failed_when: not result.changed
- name: Ensure group01 is not on the list of groups sudorule execute as, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
runasgroup:
- group01
action: member
state: absent
register: result
failed_when: result.changed
@@ -77,6 +187,78 @@
register: result
failed_when: result.changed
- name: Ensure sudorule is with usercategory 'all' is absent
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
state: absent
register: result
failed_when: not result.changed
- name: Ensure sudorule is present, with runasusercategory 'all'.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
runasusercategory: all
register: result
failed_when: not result.changed
- name: Ensure sudorule is present, with runasusercategory 'all', again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
runasusercategory: all
register: result
failed_when: result.changed
- name: Ensure sudorule is with runasusercategory 'all' is absent
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
state: absent
register: result
failed_when: not result.changed
- name: Ensure sudorule is present, with runasgroupcategory 'all'.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
runasgroupcategory: all
register: result
failed_when: not result.changed
- name: Ensure sudorule is present, with runasgroupcategory 'all', again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
runasgroupcategory: all
register: result
failed_when: result.changed
- name: Ensure sudorule is with runasgroupcategory 'all' is absent
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
state: absent
register: result
failed_when: not result.changed
- name: Ensure sudorule is present, with usercategory 'all'.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
usercategory: all
register: result
failed_when: not result.changed
- name: Ensure sudorule is present, with usercategory 'all', again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: allusers
usercategory: all
register: result
failed_when: result.changed
- name: Ensure sudorule is present, with hostategory 'all'
ipasudorule:
ipaadmin_password: SomeADMINpassword
@@ -123,6 +305,124 @@
register: result
failed_when: result.changed
- name: Ensure user is present in sudorule.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
user: user01
action: member
register: result
failed_when: not result.changed
- name: Ensure user is present in sudorule, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
user: user01
action: member
register: result
failed_when: result.changed
- name: Ensure user is absent from sudorule.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
user: user01
action: member
state: absent
register: result
failed_when: not result.changed
- name: Ensure user is absent from sudorule, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
user: user01
action: member
state: absent
register: result
failed_when: result.changed
- name: Ensure group is present in sudorule.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
group: group01
action: member
register: result
failed_when: not result.changed
- name: Ensure group is present in sudorule, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
group: group01
action: member
register: result
failed_when: result.changed
- name: Ensure group is absent from sudorule.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
group: group01
action: member
state: absent
register: result
failed_when: not result.changed
- name: Ensure group is absent from sudorule, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
group: group01
action: member
state: absent
register: result
failed_when: result.changed
- name: Ensure sudorule has a sudooption.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
sudooption: '!authenticate'
action: member
register: result
failed_when: not result.changed
- name: Ensure sudorule has a sudooption, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
sudooption: '!authenticate'
action: member
register: result
failed_when: result.changed
- name: Ensure sudorule has an order.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
order: 1
register: result
failed_when: not result.changed
- name: Ensure sudorule has an order, again.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
order: 1
register: result
failed_when: result.changed
- name: Ensure sudorule has another order.
ipasudorule:
ipaadmin_password: SomeADMINpassword
name: testrule1
order: 10
register: result
failed_when: not result.changed
- name: Ensure sudorule is present and some sudocmd are allowed.
ipasudorule:
ipaadmin_password: SomeADMINpassword
@@ -384,12 +684,6 @@
name: test_sudorule
state: absent
- name: Ensure hostgroup is absent.
ipahostgroup:
ipaadmin_password: SomeADMINpassword
name: cluster
state: absent
- name: Ensure sudocmds are absent
ipasudocmd:
ipaadmin_password: SomeADMINpassword
@@ -397,3 +691,19 @@
- /sbin/ifconfig
- /usr/bin/vim
state: absent
- name: Ensure sudorules are absent
ipasudorule:
ipaadmin_password: SomeADMINpassword
name:
- testrule1
- allusers
- allhosts
- allcommands
state: absent
- name: Ensure hostgroup is absent.
ipahostgroup:
ipaadmin_password: SomeADMINpassword
name: cluster
state: absent

View File

@@ -1,36 +1,40 @@
#!/bin/bash
namespace="freeipa"
collection="ansible_freeipa"
collection_prefix="${namespace}.${collection}"
galaxy_version=$(git describe --tags | sed -e "s/^v//")
echo $galaxy_version | grep "-" -q || galaxy_version="${galaxy_version}-1"
echo $galaxy_version | grep "-" -q || galaxy_version="${galaxy_version}"
sed -i -e "s/version: .*/version: \"$galaxy_version\"/" galaxy.yml
find . -name "*~" -exec rm {} \;
sed -i -e "s/ansible.module_utils.ansible_freeipa_module/ansible_collections.freeipa.ansible_freeipa.plugins.module_utils.ansible_freeipa_module/" plugins/modules/*.py
sed -i -e "s/ansible.module_utils.ansible_freeipa_module/ansible_collections.${collection_prefix}.plugins.module_utils.ansible_freeipa_module/" plugins/modules/*.py
cd plugins/module_utils && {
ln -s ../../roles/ipa*/module_utils/*.py .
ln -s ../../roles/*/module_utils/*.py .
cd ../..
}
cd plugins/modules && {
sed -i -e "s/ansible.module_utils.ansible_ipa_/ansible_collections.freeipa.ansible_freeipa.plugins.module_utils.ansible_ipa_/" ../../roles/ipa*/library/*.py
ln -s ../../roles/ipa*/library/*.py .
sed -i -e "s/ansible.module_utils.ansible_ipa_/ansible_collections.${collection_prefix}.plugins.module_utils.ansible_ipa_/" ../../roles/*/library/*.py
ln -s ../../roles/*/library/*.py .
cd ../..
}
[ ! -x plugins/action_plugins ] && mkdir plugins/action_plugins
cd plugins/action_plugins && {
ln -s ../../roles/ipa*/action_plugins/*.py .
ln -s ../../roles/*/action_plugins/*.py .
cd ../..
}
for x in roles/ipa*/tasks/*.yml; do
python utils/galaxyify-playbook.py "$x"
for x in roles/*/tasks/*.yml; do
python utils/galaxyfy-playbook.py "$x" "ipa" "$collection_prefix"
done
for x in $(find playbooks -name "*.yml" -print); do
python utils/galaxyify-playbook.py "$x"
python utils/galaxyfy-playbook.py "$x" "ipa" "$collection_prefix"
done
#git diff
@@ -43,4 +47,3 @@ rm plugins/modules/ipareplica_*
rm plugins/modules/ipaclient_*
rm plugins/action_plugins/ipaclient_*
git reset --hard

View File

@@ -2,11 +2,14 @@ import sys
import re
def galaxify_playbook(playbook_in):
p1 = re.compile('(ipa.*:)$')
p2 = re.compile('(.*:) (ipa.*)$')
def galaxify_playbook(playbook_in, project_prefix, collection_prefix):
p1 = re.compile('(%s.*:)$' % project_prefix)
p2 = re.compile('(.*:) (%s.*)$' % project_prefix)
lines = []
pattern1 = r'%s.\1' % collection_prefix
pattern2 = r'\1 %s.\2' % collection_prefix
with open(playbook_in) as in_f:
changed = False
changeable = False
@@ -22,14 +25,13 @@ def galaxify_playbook(playbook_in):
elif stripped.startswith("include_role:"):
include_role = True
elif include_role and stripped.startswith("name:"):
line = p2.sub(r'\1 freeipa.ansible_freeipa.\2', line)
line = p2.sub(pattern2, line)
changed = True
elif changeable and stripped.startswith("- role:"):
line = p2.sub(r'\1 freeipa.ansible_freeipa.\2', line)
line = p2.sub(pattern2, line)
changed = True
elif changeable and not stripped.startswith(
"freeipa.ansible_freeipa."):
line = p1.sub(r'freeipa.ansible_freeipa.\1', line)
elif changeable and not stripped.startswith(collection_prefix):
line = p1.sub(pattern1, line)
changed = True
lines.append(line)
@@ -40,4 +42,4 @@ def galaxify_playbook(playbook_in):
out_f.write(line)
galaxify_playbook(sys.argv[1])
galaxify_playbook(sys.argv[1], sys.argv[2], sys.argv[3])

View File

@@ -120,7 +120,7 @@ param_docs = {
"allow_zone_overlap": "Create DNS zone even if it already exists",
"skip_conncheck": "Skip connection check to remote master",
"idstart": "The starting value for the IDs range (default random)",
"idmax": "The max value for the IDs range (default: idstart+199999)",
"idmax": "The max value for the IDs range (default idstart+199999)",
"no_hbac_allow": "Don't install allow_all HBAC rule",
"domainlevel": "The domain level",
"external_ca_type": "Type of the external CA",