-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ansible INI custom promise module wrapper
This adds a custom promise module for wrapping the existing Ansible INI module. The module simply passes on values from the custom 'ini' promise type, to the Ansible module. With the example follows an example policy for downloading the required Ansible INI module. Signed-off-by: Ole Petter <[email protected]>
- Loading branch information
1 parent
9718a0b
commit c43285f
Showing
5 changed files
with
170 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Ansible INI promise type | ||
|
||
## Synopsis | ||
|
||
* *Name*: `Ansible INI - Custom Promise Module` | ||
* *Version*: `0.0.1` | ||
* *Description*: Manage configuration files through the Ansible INI module in CFEngine. | ||
|
||
## Requirements | ||
|
||
* Python installed on the system | ||
* `ansible` pip package | ||
* Correct path to the `ini_file.py` in the custom promise module | ||
|
||
## Attributes | ||
|
||
See [anible_ini module](https://docs.ansible.com/ansible/latest/collections/community/general/ini_file_module.html). | ||
|
||
## Example | ||
|
||
```cfengine3 | ||
bundle agent main | ||
{ | ||
ini: | ||
"/path/to/file.ini" | ||
section => "foo", | ||
option => "bar", | ||
value => "baz"; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
promise agent ini | ||
# @brief Define ini promise type | ||
{ | ||
path => "$(sys.workdir)/modules/promises/ini.py"; | ||
interpreter => "/usr/bin/python3"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
promise agent ini | ||
# @brief Define ini promise type | ||
{ | ||
path => "$(sys.workdir)/modules/promises/ini.py"; | ||
interpreter => "/usr/bin/python3"; | ||
} | ||
|
||
bundle agent main | ||
{ | ||
|
||
meta: | ||
"bundle_version" string => "0.0.1"; | ||
"promise_type" string => "ini"; | ||
|
||
ini: | ||
"/tmp/ini/test.ini" | ||
section => "foo", | ||
option => "bar", | ||
value => "baz"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
"""A CFEngine custom promise module for INI files""" | ||
|
||
import json | ||
import subprocess | ||
import sys | ||
|
||
from cfengine import PromiseModule, ValidationError, Result | ||
|
||
|
||
class AnsiballINIModule(PromiseModule): | ||
def __init__(self): | ||
super().__init__("ansible_ini_promise_module", "0.0.1") | ||
|
||
self.add_attribute("path", str, default_to_promiser=True) | ||
|
||
def validate_attributes(self, promiser, attributes, meta): | ||
# Just pass the attributes on transparently to Ansible INI The Ansible | ||
# module will report if the missing parameters are not in Ansible attributes | ||
|
||
return True | ||
|
||
def validate_promise(self, promiser: str, attributes: dict, meta: dict) -> None: | ||
self.log_error( | ||
"Validating the ansible ini promise: %s %s %s" | ||
% (promiser, attributes, meta) | ||
) | ||
if not meta.get("promise_type"): | ||
raise ValidationError("Promise type not specified") | ||
|
||
assert meta.get("promise_type") == "ini" | ||
|
||
def evaluate_promise(self, promiser: str, attributes: dict, meta: dict): | ||
self.log_error( | ||
"Evaluating the ansible ini promise %s, %s, %s" | ||
% (promiser, attributes, meta) | ||
) | ||
|
||
if "module_path" not in attributes: | ||
attributes.setdefault( | ||
"module_path", | ||
"/tmp/ini_file.py", | ||
) | ||
|
||
# NOTE: INI module specific - should not be passed on to Ansible | ||
module_path = attributes["module_path"] | ||
del attributes["module_path"] | ||
|
||
# NOTE - needed because 'default_to_promiser' is not respected | ||
attributes.setdefault("path", promiser) | ||
|
||
self.log_error( | ||
"Evaluating the ansible ini promise %s, %s, %s" | ||
% (promiser, attributes, meta) | ||
) | ||
|
||
proc = subprocess.run( | ||
[ | ||
"python", | ||
module_path, | ||
], | ||
input=json.dumps({"ANSIBLE_MODULE_ARGS": attributes}).encode("utf-8"), | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
) | ||
|
||
if not proc: | ||
self.log_error("Failed to run the ansible module") | ||
return ( | ||
Result.NOT_KEPT, | ||
[], | ||
) | ||
|
||
if proc.returncode != 0: | ||
self.log_error("Failed to run the ansible module") | ||
self.log_error("Ansible INI module returned(stdout): %s" % proc.stdout) | ||
self.log_error("Ansible INI module returned(stderr): %s" % proc.stderr) | ||
return ( | ||
Result.NOT_KEPT, | ||
[], | ||
) | ||
|
||
self.log_debug("Received output: %s (stdout)" % proc.stdout) | ||
self.log_debug("Received output: (stderr): %s" % proc.stderr) | ||
|
||
try: | ||
d = json.loads(proc.stdout.decode("UTF-8").strip()) | ||
if d.get("changed", False): | ||
self.log_info( | ||
"Edited content of '%s' (%s)" % (promiser, d.get("msg", "")) | ||
) | ||
except Exception as e: | ||
self.log_error( | ||
"Failed to decode the JSON returned from the Ansible INI module. Error: %s" | ||
% e | ||
) | ||
return (Result.NOT_KEPT, []) | ||
|
||
return ( | ||
Result.KEPT, | ||
[], | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
AnsiballINIModule().start() |