This commit is contained in:
parent
b84f50ed71
commit
660afb5392
2
.flake8
2
.flake8
@ -1,5 +1,5 @@
|
|||||||
[flake8]
|
[flake8]
|
||||||
ignore = D101, D102, D103, D107, D202, E402, W503
|
ignore = D101, D102, D103, D105, D107, D202, E402, W503
|
||||||
max-line-length = 99
|
max-line-length = 99
|
||||||
inline-quotes = double
|
inline-quotes = double
|
||||||
exclude =
|
exclude =
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"""Dynamic inventory plugin for Proxmox VE."""
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2014, Mathieu GAUTHIER-LAFAYE <gauthierl@lapth.cnrs.fr>
|
# Copyright (c) 2014, Mathieu GAUTHIER-LAFAYE <gauthierl@lapth.cnrs.fr>
|
||||||
# Copyright (c) 2016, Matt Harris <matthaeus.harris@gmail.com>
|
# Copyright (c) 2016, Matt Harris <matthaeus.harris@gmail.com>
|
||||||
# Copyright (c) 2020, Robert Kaussow <mail@thegeeklab.de>
|
# Copyright (c) 2020, Robert Kaussow <mail@thegeeklab.de>
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
"""Dynamic inventory plugin for Proxmox VE."""
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
256
plugins/modules/corenetworks_dns.py
Normal file
256
plugins/modules/corenetworks_dns.py
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Module to control corenetworks DNS API."""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"}
|
||||||
|
|
||||||
|
DOCUMENTATION = r"""
|
||||||
|
---
|
||||||
|
module: corenetworks_dns
|
||||||
|
short_description: Interface with the DNS API of core-networks.de
|
||||||
|
description:
|
||||||
|
- "Manages DNS zones and records via the core networks API, see the docs: U(https://beta.api.core-networks.de/doc/)."
|
||||||
|
options:
|
||||||
|
api_user:
|
||||||
|
description:
|
||||||
|
- Account API username. If omitted, the environment variables C(CN_API_USER) and C(CN_API_PASSWORD) will be looked for.
|
||||||
|
- You should prefere to use `api_token` or the `corenetworks_token` module to create one to prevent running into rate limits.
|
||||||
|
type: str
|
||||||
|
api_password:
|
||||||
|
description:
|
||||||
|
- Account API password.
|
||||||
|
type: str
|
||||||
|
api_token:
|
||||||
|
description:
|
||||||
|
- Account API token.
|
||||||
|
type: str
|
||||||
|
zone:
|
||||||
|
description:
|
||||||
|
- The name of the Zone to work with (e.g. "example.com").
|
||||||
|
- The Zone must already exist.
|
||||||
|
zone:
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
aliases: [ domain ]
|
||||||
|
record:
|
||||||
|
description:
|
||||||
|
- Used record relative to the given zone.
|
||||||
|
- Default is C(@) (e.g. the zone name).
|
||||||
|
type: str
|
||||||
|
default: "@"
|
||||||
|
aliases: [ name ]
|
||||||
|
type:
|
||||||
|
description:
|
||||||
|
- The type of DNS record to create.
|
||||||
|
choices: [ "A", "ALIAS", "CNAME", "MX", "SPF", "URL", "TXT", "NS", "SRV", "NAPTR", "PTR", "AAAA", "SSHFP", "HINFO", "POOL" ]
|
||||||
|
type: str
|
||||||
|
ttl:
|
||||||
|
description:
|
||||||
|
- The TTL to give the new record in seconds.
|
||||||
|
default: 3600
|
||||||
|
type: int
|
||||||
|
value:
|
||||||
|
description:
|
||||||
|
- Record value.
|
||||||
|
- Must be specified when trying to ensure a record exists.
|
||||||
|
type: str
|
||||||
|
solo:
|
||||||
|
description:
|
||||||
|
- Whether the record should be the only one for that record type and record name.
|
||||||
|
- Only use with C(state=present).
|
||||||
|
- This will delete all other records with the same record name and type.
|
||||||
|
type: bool
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- whether the record should exist or not
|
||||||
|
choices: [ "present", "absent" ]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "corenetworks >= 0.1.4"
|
||||||
|
author: "Robert Kaussow (@xoxys)"
|
||||||
|
""" # noqa
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Create a test.my.com A record to point to 127.0.0.1
|
||||||
|
corenetworks_dns:
|
||||||
|
zone: my.com
|
||||||
|
record: test
|
||||||
|
type: A
|
||||||
|
value: 127.0.0.1
|
||||||
|
delegate_to: localhost
|
||||||
|
register: record
|
||||||
|
|
||||||
|
- name: Create a my.com CNAME record to example.com
|
||||||
|
corenetworks_dns:
|
||||||
|
zone: my.com
|
||||||
|
type: CNAME
|
||||||
|
value: example.com
|
||||||
|
state: present
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Change TTL value for a record
|
||||||
|
corenetworks_dns:
|
||||||
|
zone: my.com
|
||||||
|
type: CNAME
|
||||||
|
value: example.com
|
||||||
|
ttl: 600
|
||||||
|
state: present
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Delete the record
|
||||||
|
corenetworks_dns:
|
||||||
|
zone: my.com
|
||||||
|
type: CNAME
|
||||||
|
value: example.com
|
||||||
|
state: absent
|
||||||
|
delegate_to: localhost
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = r"""# """
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
CORENETWORKS_IMP_ERR = None
|
||||||
|
try:
|
||||||
|
from corenetworks import CoreNetworks
|
||||||
|
from corenetworks.exceptions import CoreNetworksException
|
||||||
|
HAS_CORENETWORKS = True
|
||||||
|
except ImportError:
|
||||||
|
CORENETWORKS_IMP_ERR = traceback.format_exc()
|
||||||
|
HAS_CORENETWORKS = False
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
|
|
||||||
|
|
||||||
|
def delete_records(client, module, zone, params, is_solo=False):
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
search = copy.deepcopy(params)
|
||||||
|
if is_solo:
|
||||||
|
search.pop("data", None)
|
||||||
|
search.pop("ttl", None)
|
||||||
|
|
||||||
|
records = client.records(zone, params=search)
|
||||||
|
|
||||||
|
for r in records:
|
||||||
|
r["ttl"] = int(r["ttl"])
|
||||||
|
|
||||||
|
if is_solo:
|
||||||
|
if not (r["data"] == params["data"] and r["ttl"] == params["ttl"]):
|
||||||
|
changed = True
|
||||||
|
if not module.check_mode:
|
||||||
|
client.delete_record(zone, r)
|
||||||
|
else:
|
||||||
|
changed = True
|
||||||
|
if not module.check_mode:
|
||||||
|
client.delete_record(zone, r)
|
||||||
|
|
||||||
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
def add_record(client, module, zone, params):
|
||||||
|
changed = False
|
||||||
|
result = []
|
||||||
|
records = client.records(zone, params=params)
|
||||||
|
|
||||||
|
if len(records) > 1:
|
||||||
|
module.fail_json(
|
||||||
|
msg="More than one record already exists for the given attributes. "
|
||||||
|
"That should be impossible, please open an issue!"
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(records) == 0:
|
||||||
|
changed = True
|
||||||
|
if not module.check_mode:
|
||||||
|
result = client.add_record(zone, params=params)
|
||||||
|
|
||||||
|
return result, changed
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
api_user=dict(type="str"),
|
||||||
|
api_password=dict(type="str", no_log=True),
|
||||||
|
api_token=dict(type="str", no_log=True),
|
||||||
|
zone=dict(type="str", required=True, aliases=["domain"]),
|
||||||
|
record=dict(type="str", default="@", aliases=["name"]),
|
||||||
|
type=dict(
|
||||||
|
type="str",
|
||||||
|
choices=[
|
||||||
|
"A", "ALIAS", "CNAME", "MX", "SPF", "URL", "TXT", "NS", "SRV", "NAPTR", "PTR",
|
||||||
|
"AAAA", "SSHFP", "HINFO", "POOL"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
ttl=dict(type="int", default=3600),
|
||||||
|
value=dict(type="str"),
|
||||||
|
solo=dict(type="bool", default=False),
|
||||||
|
state=dict(type="str", choices=["present", "absent"], default="present"),
|
||||||
|
),
|
||||||
|
required_together=[["record", "value"]],
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not HAS_CORENETWORKS:
|
||||||
|
module.fail_json(msg=missing_required_lib("corenetworks"), exception=CORENETWORKS_IMP_ERR)
|
||||||
|
|
||||||
|
api_user = module.params.get("api_user")
|
||||||
|
api_password = module.params.get("api_password")
|
||||||
|
api_token = module.params.get("api_token")
|
||||||
|
zone = module.params.get("zone")
|
||||||
|
record = module.params.get("record")
|
||||||
|
record_type = module.params.get("type")
|
||||||
|
ttl = module.params.get("ttl")
|
||||||
|
value = module.params.get("value")
|
||||||
|
state = module.params.get("state")
|
||||||
|
is_solo = module.params.get("solo")
|
||||||
|
params = {"name": record, "ttl": ttl}
|
||||||
|
|
||||||
|
# sanity checks
|
||||||
|
if not record_type:
|
||||||
|
if state == "present":
|
||||||
|
module.fail_json(msg="Missing the record type")
|
||||||
|
else:
|
||||||
|
params["type"] = record_type
|
||||||
|
|
||||||
|
if not value:
|
||||||
|
if state == "present":
|
||||||
|
module.fail_json(msg="Missing the record value")
|
||||||
|
else:
|
||||||
|
params["data"] = value
|
||||||
|
|
||||||
|
if is_solo and state == "absent":
|
||||||
|
module.fail_json(msg="solo=true can only be used with state=present")
|
||||||
|
|
||||||
|
# perform actions
|
||||||
|
try:
|
||||||
|
# request throtteling to workaround the current rate limit
|
||||||
|
changed = False
|
||||||
|
if api_token:
|
||||||
|
client = CoreNetworks(api_token=api_token, auto_commit=True)
|
||||||
|
else:
|
||||||
|
client = CoreNetworks(user=api_user, password=api_password, auto_commit=True)
|
||||||
|
|
||||||
|
if state == "present":
|
||||||
|
changed_solo = False
|
||||||
|
if is_solo:
|
||||||
|
changed_solo = delete_records(client, module, zone, params, is_solo=True)
|
||||||
|
result, changed = add_record(client, module, zone, params)
|
||||||
|
|
||||||
|
module.exit_json(changed=changed_solo + changed, result=result)
|
||||||
|
# state is absent
|
||||||
|
else:
|
||||||
|
changed = delete_records(client, module, zone, params)
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except CoreNetworksException as e:
|
||||||
|
module.fail_json(msg="Failure in core networks API communication: {}".format(str(e)))
|
||||||
|
|
||||||
|
module.fail_json(msg="Unknown what you wanted me to do")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
112
plugins/modules/corenetworks_token.py
Normal file
112
plugins/modules/corenetworks_token.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Module to control corenetworks DNS API."""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"}
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: corenetworks_dns
|
||||||
|
short_description: Interface with the DNS API of core-networks.de
|
||||||
|
description:
|
||||||
|
- "Manages DNS zones and records via the core networks API, see the docs: U(https://beta.api.core-networks.de/doc/)."
|
||||||
|
options:
|
||||||
|
api_user:
|
||||||
|
description:
|
||||||
|
- Account API username. If omitted, the environment variables C(CN_API_USER) and C(CN_API_PASSWORD) will be looked for.
|
||||||
|
type: str
|
||||||
|
api_password:
|
||||||
|
description:
|
||||||
|
- Account API password.
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- whether the record should exist or not
|
||||||
|
choices: [ "present" ]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "corenetworks >= 0.1.3"
|
||||||
|
author: "Robert Kaussow (@xoxys)"
|
||||||
|
""" # noqa
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Obtain an API token using env variables
|
||||||
|
corenetworks_token:
|
||||||
|
delegate_to: localhost
|
||||||
|
register: my_token
|
||||||
|
|
||||||
|
- name: Obtain an API token using username and password attribute
|
||||||
|
corenetworks_token:
|
||||||
|
api_user: testuser
|
||||||
|
api_password: secure
|
||||||
|
delegate_to: localhost
|
||||||
|
register: my_token
|
||||||
|
|
||||||
|
- debug:
|
||||||
|
msg: "{{ my_token }}"
|
||||||
|
|
||||||
|
- name: Use the token
|
||||||
|
corenetworks_dns:
|
||||||
|
api_token: "{{ my_token.session.token }}"
|
||||||
|
zone: my.com
|
||||||
|
type: CNAME
|
||||||
|
value: example.com
|
||||||
|
state: present
|
||||||
|
delegate_to: localhost
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = r"""# """
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
CORENETWORKS_IMP_ERR = None
|
||||||
|
try:
|
||||||
|
from corenetworks import CoreNetworks
|
||||||
|
from corenetworks.exceptions import CoreNetworksException
|
||||||
|
HAS_CORENETWORKS = True
|
||||||
|
except ImportError:
|
||||||
|
CORENETWORKS_IMP_ERR = traceback.format_exc()
|
||||||
|
HAS_CORENETWORKS = False
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
api_user=dict(type="str"),
|
||||||
|
api_password=dict(type="str", no_log=True),
|
||||||
|
state=dict(type="str", choices=["present"], default="present"),
|
||||||
|
),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not HAS_CORENETWORKS:
|
||||||
|
module.fail_json(msg=missing_required_lib("corenetworks"), exception=CORENETWORKS_IMP_ERR)
|
||||||
|
|
||||||
|
api_user = module.params.get("api_user")
|
||||||
|
api_password = module.params.get("api_password")
|
||||||
|
|
||||||
|
# perform actions
|
||||||
|
try:
|
||||||
|
# request throtteling to workaround the current rate limit
|
||||||
|
changed = False
|
||||||
|
client = CoreNetworks(user=api_user, password=api_password, auto_commit=True)
|
||||||
|
|
||||||
|
session = {"token": client._auth.token}
|
||||||
|
|
||||||
|
if hasattr(client._auth, "expires"):
|
||||||
|
session["expires"] = client._auth.expires.strftime("%Y-%m-%d, %H:%M:%S")
|
||||||
|
|
||||||
|
module.exit_json(changed=changed, session=session)
|
||||||
|
|
||||||
|
except CoreNetworksException as e:
|
||||||
|
module.fail_json(msg="Failure in core networks API communication: {}".format(str(e)))
|
||||||
|
|
||||||
|
module.fail_json(msg="Unknown what you wanted me to do")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
1070
plugins/modules/iptables_raw.py
Normal file
1070
plugins/modules/iptables_raw.py
Normal file
File diff suppressed because it is too large
Load Diff
415
plugins/modules/openssl_pkcs12.py
Normal file
415
plugins/modules/openssl_pkcs12.py
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""OpenSSL PKCS12 module."""
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {"metadata_version": "1.0", "status": ["preview"], "supported_by": "community"}
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: openssl_pkcs12
|
||||||
|
author: "Guillaume Delpierre (@gdelpierre)"
|
||||||
|
version_added: "2.4"
|
||||||
|
short_description: Generate OpenSSL pkcs12 archive.
|
||||||
|
description:
|
||||||
|
- "This module allows one to (re-)generate PKCS#12."
|
||||||
|
requirements:
|
||||||
|
- "python-pyOpenSSL"
|
||||||
|
options:
|
||||||
|
ca_certificates:
|
||||||
|
required: False
|
||||||
|
description:
|
||||||
|
- List of CA certificate to include.
|
||||||
|
cert_path:
|
||||||
|
required: False
|
||||||
|
description:
|
||||||
|
- The path to read certificates and private keys from.
|
||||||
|
Must be in PEM format.
|
||||||
|
action:
|
||||||
|
required: False
|
||||||
|
default: "export"
|
||||||
|
choices: ["parse", "export"]
|
||||||
|
description:
|
||||||
|
- Create (export) or parse a PKCS#12.
|
||||||
|
src:
|
||||||
|
required: False
|
||||||
|
description:
|
||||||
|
- PKCS#12 file path to parse.
|
||||||
|
path:
|
||||||
|
required: True
|
||||||
|
default: null
|
||||||
|
description:
|
||||||
|
- Filename to write the PKCS#12 file to.
|
||||||
|
force:
|
||||||
|
required: False
|
||||||
|
default: False
|
||||||
|
description:
|
||||||
|
- Should the file be regenerated even it it already exists.
|
||||||
|
friendly_name:
|
||||||
|
required: False
|
||||||
|
default: null
|
||||||
|
aliases: "name"
|
||||||
|
description:
|
||||||
|
- Specifies the friendly name for the certificate and private key.
|
||||||
|
iter_size:
|
||||||
|
required: False
|
||||||
|
default: 2048
|
||||||
|
description:
|
||||||
|
- Number of times to repeat the encryption step.
|
||||||
|
maciter_size:
|
||||||
|
required: False
|
||||||
|
default: 1
|
||||||
|
description:
|
||||||
|
- Number of times to repeat the MAC step.
|
||||||
|
mode:
|
||||||
|
required: False
|
||||||
|
default: 0400
|
||||||
|
description:
|
||||||
|
- Default mode for the generated PKCS#12 file.
|
||||||
|
passphrase:
|
||||||
|
required: False
|
||||||
|
default: null
|
||||||
|
description:
|
||||||
|
- The PKCS#12 password.
|
||||||
|
privatekey_path:
|
||||||
|
required: False
|
||||||
|
description:
|
||||||
|
- File to read private key from.
|
||||||
|
privatekey_passphrase:
|
||||||
|
required: False
|
||||||
|
default: null
|
||||||
|
description:
|
||||||
|
- Passphrase source to decrypt any input private keys with.
|
||||||
|
state:
|
||||||
|
required: False
|
||||||
|
default: "present"
|
||||||
|
choices: ["present", "absent"]
|
||||||
|
description:
|
||||||
|
- Whether the file should exist or not.
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: "Generate PKCS#12 file"
|
||||||
|
openssl_pkcs12:
|
||||||
|
path: "/opt/certs/ansible.p12"
|
||||||
|
friendly_name: "raclette"
|
||||||
|
privatekey_path: "/opt/certs/keys/key.pem"
|
||||||
|
cert_path: "/opt/certs/cert.pem"
|
||||||
|
ca_certificates: "/opt/certs/ca.pem"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: "Change PKCS#12 file permission"
|
||||||
|
openssl_pkcs12:
|
||||||
|
path: "/opt/certs/ansible.p12"
|
||||||
|
friendly_name: "raclette"
|
||||||
|
privatekey_path: "/opt/certs/keys/key.pem"
|
||||||
|
cert_path: "/opt/certs/cert.pem"
|
||||||
|
ca_certificates: "/opt/certs/ca.pem"
|
||||||
|
state: present
|
||||||
|
mode: 0600
|
||||||
|
|
||||||
|
- name: "Regen PKCS#12 file"
|
||||||
|
openssl_pkcs12:
|
||||||
|
path: "/opt/certs/ansible.p12"
|
||||||
|
friendly_name: "raclette"
|
||||||
|
privatekey_path: "/opt/certs/keys/key.pem"
|
||||||
|
cert_path: "/opt/certs/cert.pem"
|
||||||
|
ca_certificates: "/opt/certs/ca.pem"
|
||||||
|
state: present
|
||||||
|
mode: 0600
|
||||||
|
force: True
|
||||||
|
|
||||||
|
- name: "Dump/Parse PKCS#12 file"
|
||||||
|
openssl_pkcs12:
|
||||||
|
src: "/opt/certs/ansible.p12"
|
||||||
|
path: "/opt/certs/ansible.pem"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: "Remove PKCS#12 file"
|
||||||
|
openssl_pkcs12:
|
||||||
|
path: "/opt/certs/ansible.p12"
|
||||||
|
state: absent
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
filename:
|
||||||
|
description: Path to the generate PKCS#12 file.
|
||||||
|
returned: changed or success
|
||||||
|
type: string
|
||||||
|
sample: /opt/certs/ansible.p12
|
||||||
|
"""
|
||||||
|
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
|
|
||||||
|
from ansible.module_utils._text import to_native
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
try:
|
||||||
|
from OpenSSL import crypto
|
||||||
|
except ImportError:
|
||||||
|
pyopenssl_found = False
|
||||||
|
else:
|
||||||
|
pyopenssl_found = True
|
||||||
|
|
||||||
|
|
||||||
|
class PkcsError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Pkcs(object):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
self.path = module.params["path"]
|
||||||
|
self.force = module.params["force"]
|
||||||
|
self.state = module.params["state"]
|
||||||
|
self.action = module.params["action"]
|
||||||
|
self.check_mode = module.check_mode
|
||||||
|
self.iter_size = module.params["iter_size"]
|
||||||
|
self.maciter_size = module.params["maciter_size"]
|
||||||
|
self.pkcs12 = None
|
||||||
|
self.src = module.params["src"]
|
||||||
|
self.privatekey_path = module.params["privatekey_path"]
|
||||||
|
self.privatekey_passphrase = module.params["privatekey_passphrase"]
|
||||||
|
self.cert_path = module.params["cert_path"]
|
||||||
|
self.ca_certificates = module.params["ca_certificates"]
|
||||||
|
self.friendly_name = module.params["friendly_name"]
|
||||||
|
self.passphrase = module.params["passphrase"]
|
||||||
|
self.mode = module.params["mode"]
|
||||||
|
self.changed = False
|
||||||
|
if not self.mode:
|
||||||
|
self.mode = int("0400", 8)
|
||||||
|
|
||||||
|
def load_privatekey(self, path, passphrase=None):
|
||||||
|
"""Load the specified OpenSSL private key."""
|
||||||
|
try:
|
||||||
|
if passphrase:
|
||||||
|
privatekey = crypto.load_privatekey(
|
||||||
|
crypto.FILETYPE_PEM,
|
||||||
|
open(path, "rb").read(), passphrase
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
privatekey = crypto.load_privatekey(crypto.FILETYPE_PEM, open(path, "rb").read())
|
||||||
|
|
||||||
|
return privatekey
|
||||||
|
except (IOError, OSError) as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
def load_certificate(self, path):
|
||||||
|
"""Load the specified certificate."""
|
||||||
|
try:
|
||||||
|
cert_content = open(path, "rb").read()
|
||||||
|
cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_content)
|
||||||
|
return cert
|
||||||
|
except (IOError, OSError) as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
def load_pkcs12(self, path, passphrase=None):
|
||||||
|
"""Load pkcs12 file."""
|
||||||
|
try:
|
||||||
|
if passphrase:
|
||||||
|
return crypto.load_pkcs12(open(path, "rb").read(), passphrase)
|
||||||
|
else:
|
||||||
|
return crypto.load_pkcs12(open(path, "rb").read())
|
||||||
|
except (IOError, OSError) as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
def dump_privatekey(self, path):
|
||||||
|
"""Dump the specified OpenSSL private key."""
|
||||||
|
try:
|
||||||
|
return crypto.dump_privatekey(
|
||||||
|
crypto.FILETYPE_PEM,
|
||||||
|
self.load_pkcs12(path).get_privatekey()
|
||||||
|
)
|
||||||
|
except (IOError, OSError) as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
def dump_certificate(self, path):
|
||||||
|
"""Dump the specified certificate."""
|
||||||
|
try:
|
||||||
|
return crypto.dump_certificate(
|
||||||
|
crypto.FILETYPE_PEM,
|
||||||
|
self.load_pkcs12(path).get_certificate()
|
||||||
|
)
|
||||||
|
except (IOError, OSError) as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
def generate(self, module):
|
||||||
|
"""Generate PKCS#12 file archive."""
|
||||||
|
if not os.path.exists(self.path) or self.force:
|
||||||
|
self.pkcs12 = crypto.PKCS12()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.remove()
|
||||||
|
except PkcsError as exc:
|
||||||
|
module.fail_json(msg=to_native(exc))
|
||||||
|
|
||||||
|
if self.ca_certificates:
|
||||||
|
ca_certs = [self.load_certificate(ca_cert) for ca_cert in self.ca_certificates]
|
||||||
|
self.pkcs12.set_ca_certificates(ca_certs)
|
||||||
|
|
||||||
|
if self.cert_path:
|
||||||
|
self.pkcs12.set_certificate(self.load_certificate(self.cert_path))
|
||||||
|
|
||||||
|
if self.friendly_name:
|
||||||
|
self.pkcs12.set_friendlyname(self.friendly_name)
|
||||||
|
|
||||||
|
if self.privatekey_path:
|
||||||
|
self.pkcs12.set_privatekey(
|
||||||
|
self.load_privatekey(self.privatekey_path, self.privatekey_passphrase)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.path, "wb", self.mode) as archive:
|
||||||
|
archive.write(
|
||||||
|
self.pkcs12.export(self.passphrase, self.iter_size, self.maciter_size)
|
||||||
|
)
|
||||||
|
module.set_mode_if_different(self.path, self.mode, False)
|
||||||
|
self.changed = True
|
||||||
|
except (IOError, OSError) as exc:
|
||||||
|
self.remove()
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
file_args = module.load_file_common_arguments(module.params)
|
||||||
|
if module.set_fs_attributes_if_different(file_args, False):
|
||||||
|
module.set_mode_if_different(self.path, self.mode, False)
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
def parse(self, module):
|
||||||
|
"""Read PKCS#12 file."""
|
||||||
|
if not os.path.exists(self.path) or self.force:
|
||||||
|
try:
|
||||||
|
self.remove()
|
||||||
|
|
||||||
|
with open(self.path, "wb") as content:
|
||||||
|
content.write(
|
||||||
|
"{0}{1}".format(
|
||||||
|
self.dump_privatekey(self.src), self.dump_certificate(self.src)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
module.set_mode_if_different(self.path, self.mode, False)
|
||||||
|
self.changed = True
|
||||||
|
except IOError as exc:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
|
||||||
|
file_args = module.load_file_common_arguments(module.params)
|
||||||
|
if module.set_fs_attributes_if_different(file_args, False):
|
||||||
|
module.set_mode_if_different(self.path, self.mode, False)
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
def remove(self):
|
||||||
|
"""Remove the PKCS#12 file archive from the filesystem."""
|
||||||
|
try:
|
||||||
|
os.remove(self.path)
|
||||||
|
self.changed = True
|
||||||
|
except OSError as exc:
|
||||||
|
if exc.errno != errno.ENOENT:
|
||||||
|
raise PkcsError(exc)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check(self, module, perms_required=True):
|
||||||
|
|
||||||
|
def _check_pkey_passphrase():
|
||||||
|
if self.privatekey_passphrase:
|
||||||
|
try:
|
||||||
|
self.load_privatekey(self.path, self.privatekey_passphrase)
|
||||||
|
return True
|
||||||
|
except crypto.Error:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not os.path.exists(self.path):
|
||||||
|
return os.path.exists(self.path)
|
||||||
|
|
||||||
|
return _check_pkey_passphrase
|
||||||
|
|
||||||
|
def dump(self):
|
||||||
|
"""Serialize the object into a dictionary."""
|
||||||
|
result = {
|
||||||
|
"changed": self.changed,
|
||||||
|
"filename": self.path,
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.privatekey_path:
|
||||||
|
result["privatekey_path"] = self.privatekey_path
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = dict(
|
||||||
|
action=dict(default="export", choices=["parse", "export"], type="str"),
|
||||||
|
ca_certificates=dict(type="list"),
|
||||||
|
cert_path=dict(type="path"),
|
||||||
|
force=dict(default=False, type="bool"),
|
||||||
|
friendly_name=dict(type="str", aliases=["name"]),
|
||||||
|
iter_size=dict(default=2048, type="int"),
|
||||||
|
maciter_size=dict(default=1, type="int"),
|
||||||
|
passphrase=dict(type="str", no_log=True),
|
||||||
|
path=dict(required=True, type="path"),
|
||||||
|
privatekey_path=dict(type="path"),
|
||||||
|
privatekey_passphrase=dict(type="str", no_log=True),
|
||||||
|
state=dict(default="present", choices=["present", "absent"], type="str"),
|
||||||
|
src=dict(type="path"),
|
||||||
|
)
|
||||||
|
|
||||||
|
required_if = [
|
||||||
|
["action", "export", ["friendly_name"]],
|
||||||
|
["action", "parse", ["src"]],
|
||||||
|
]
|
||||||
|
|
||||||
|
required_together = [
|
||||||
|
["privatekey_path", "friendly_name"],
|
||||||
|
]
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
add_file_common_args=True,
|
||||||
|
required_if=required_if,
|
||||||
|
required_together=required_together,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not pyopenssl_found:
|
||||||
|
module.fail_json(msg="The python pyOpenSSL library is required")
|
||||||
|
|
||||||
|
base_dir = os.path.dirname(module.params["path"])
|
||||||
|
if not os.path.isdir(base_dir):
|
||||||
|
module.fail_json(
|
||||||
|
name=base_dir,
|
||||||
|
msg="The directory {0} does not exist or "
|
||||||
|
"the file is not a directory".format(base_dir)
|
||||||
|
)
|
||||||
|
|
||||||
|
pkcs12 = Pkcs(module)
|
||||||
|
|
||||||
|
if module.params["state"] == "present":
|
||||||
|
if module.check_mode:
|
||||||
|
result = pkcs12.dump()
|
||||||
|
result["changed"] = module.params["force"] or not pkcs12.check(module)
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if module.params["action"] == "export":
|
||||||
|
pkcs12.generate(module)
|
||||||
|
else:
|
||||||
|
pkcs12.parse(module)
|
||||||
|
except PkcsError as exc:
|
||||||
|
module.fail_json(msg=to_native(exc))
|
||||||
|
else:
|
||||||
|
if module.check_mode:
|
||||||
|
result = pkcs12.dump()
|
||||||
|
result["changed"] = os.path.exists(module.params["path"])
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
try:
|
||||||
|
pkcs12.remove()
|
||||||
|
except PkcsError as exc:
|
||||||
|
module.fail_json(msg=to_native(exc))
|
||||||
|
|
||||||
|
result = pkcs12.dump()
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
1335
plugins/modules/proxmox_kvm.py
Normal file
1335
plugins/modules/proxmox_kvm.py
Normal file
File diff suppressed because it is too large
Load Diff
116
plugins/modules/ucr.py
Normal file
116
plugins/modules/ucr.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Module to control Univention Corporate Registry."""
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"}
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: ucr
|
||||||
|
short_description: Manage variables in univention configuration registry.
|
||||||
|
version_added: "2.6"
|
||||||
|
description:
|
||||||
|
- "This module allows to manage variables inside the univention configuration registry
|
||||||
|
on a univention corporate server (UCS)."
|
||||||
|
options:
|
||||||
|
path:
|
||||||
|
description:
|
||||||
|
- Path for the variable
|
||||||
|
required: True
|
||||||
|
default: null
|
||||||
|
value:
|
||||||
|
description:
|
||||||
|
- New value of the variable
|
||||||
|
required: False
|
||||||
|
state:
|
||||||
|
required: False
|
||||||
|
default: "present"
|
||||||
|
choices: ["present", "absent"]
|
||||||
|
description:
|
||||||
|
- Whether the variable should be exist or not.
|
||||||
|
author:
|
||||||
|
- Robert Kaussow (@xoxys)
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
# Set variable to force https in ucs frontend
|
||||||
|
- name: Force https
|
||||||
|
ucr:
|
||||||
|
path: apache2/force_https
|
||||||
|
value: yes
|
||||||
|
|
||||||
|
# Allow another user as root to login as ssh
|
||||||
|
- name: Add ssh user
|
||||||
|
ucr:
|
||||||
|
path: auth/sshd/user/myuser
|
||||||
|
value: yes
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
original_message:
|
||||||
|
description: The original name param that was passed in
|
||||||
|
type: str
|
||||||
|
message:
|
||||||
|
description: The output message that the sample module generates
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from univention.config_registry import ConfigRegistry # noqa
|
||||||
|
from univention.config_registry.frontend import ucr_update # noqa
|
||||||
|
|
||||||
|
|
||||||
|
def get_variable(ucr, path):
|
||||||
|
ucr.load()
|
||||||
|
if path in ucr:
|
||||||
|
value = ucr.get(path)
|
||||||
|
else:
|
||||||
|
value = None
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def set_variable(ucr, path, value, result):
|
||||||
|
org_value = get_variable(ucr, path)
|
||||||
|
ucr_update(ucr, {path: value})
|
||||||
|
new_value = get_variable(ucr, path)
|
||||||
|
return not org_value == new_value
|
||||||
|
|
||||||
|
|
||||||
|
def dry_variable(ucr, path, value, result):
|
||||||
|
org_value = get_variable(ucr, path)
|
||||||
|
return not org_value == value
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ucr = ConfigRegistry()
|
||||||
|
|
||||||
|
module_args = dict(
|
||||||
|
path=dict(type="str", required=True, aliases=["name"]),
|
||||||
|
value=dict(type="str", required=False, default=""),
|
||||||
|
state=dict(default="present", choices=["present", "absent"], type="str")
|
||||||
|
)
|
||||||
|
|
||||||
|
required_if = [["state", "present", ["value"]]]
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=module_args, supports_check_mode=True, required_if=required_if
|
||||||
|
)
|
||||||
|
|
||||||
|
result = dict(changed=False, original_message="", message="")
|
||||||
|
|
||||||
|
path = module.params["path"]
|
||||||
|
value = module.params["value"]
|
||||||
|
if module.params["state"] == "present":
|
||||||
|
if value is None or value == "None":
|
||||||
|
value = ""
|
||||||
|
elif module.params["state"] == "absent":
|
||||||
|
value = None
|
||||||
|
|
||||||
|
if not module.check_mode:
|
||||||
|
result["changed"] = set_variable(ucr, path, value, result)
|
||||||
|
else:
|
||||||
|
result["changed"] = dry_variable(ucr, path, value, result)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -4,7 +4,7 @@ known_first_party = ansiblelater
|
|||||||
sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
|
sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
|
||||||
force_single_line = true
|
force_single_line = true
|
||||||
line_length = 99
|
line_length = 99
|
||||||
skip_glob = **/.env*,**/env/*,**/docs/*,**/inventory/*
|
skip_glob = **/.env*,**/env/*,**/docs/*,**/inventory/*,**/modules/*
|
||||||
|
|
||||||
[yapf]
|
[yapf]
|
||||||
based_on_style = google
|
based_on_style = google
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
ansible
|
ansible
|
||||||
|
|
||||||
# requirement for the proxmox module
|
# requirement for the proxmox modules
|
||||||
proxmoxer
|
proxmoxer
|
||||||
requests
|
requests
|
||||||
|
|
||||||
|
# requirement for the corenetworks modules
|
||||||
|
corenetworks
|
||||||
|
|
||||||
|
# requirement for the openssl_pkcs12 module
|
||||||
|
pyOpenSSL
|
||||||
|
Loading…
Reference in New Issue
Block a user