-
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.
RFC: Ansible INI promise module wrapper
Signed-off-by: Ole Petter <[email protected]>
- Loading branch information
1 parent
9718a0b
commit f287922
Showing
4 changed files
with
215 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Ansible INI promise type | ||
|
||
## Synopsis | ||
|
||
* *Name*: `Ansible INI - Custom Promise Module` | ||
* *Version*: `0.0.1` | ||
* *Description*: Manage TOML configuration files through the Ansible INI module in CFEngine. | ||
|
||
## Requirements | ||
|
||
* TODO - TBD | ||
|
||
## 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.toml" | ||
section => "foo", | ||
option => "fav", | ||
value => "lemonade"; | ||
} | ||
``` |
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)/inputs/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,79 @@ | ||
promise agent ini | ||
# @brief Define ini promise type | ||
{ | ||
path => "$(sys.workdir)/inputs/modules/promises/ini.py"; | ||
interpreter => "/usr/bin/python3"; | ||
} | ||
|
||
body common control { | ||
bundlesequence => {"dependencies", "main"}; | ||
} | ||
|
||
body perms m_rxdirs( mode, rxdirs ) | ||
{ | ||
mode => "$(mode)"; | ||
rxdirs => "$(rxdirs)"; | ||
} | ||
|
||
bundle agent dependencies { | ||
vars: | ||
|
||
"options_str" string => ' | ||
{ | ||
"url.max_content": 1048576, | ||
"url.verbose": 0 | ||
}'; | ||
|
||
"options" data => parsejson($(options_str)); | ||
|
||
"url" string => "https://raw.githubusercontent.com/ansible-collections/community.general/9946f758af5fe0fe41f1cf7584d670ca1d6c2d52/plugins/modules/ini_file.py"; | ||
|
||
"ansible_ini_file" data => url_get($(url), options); | ||
|
||
|
||
classes: | ||
"got_ini_file" expression => "$(ansible_ini_file[success])"; | ||
|
||
|
||
files: | ||
got_ini_file:: | ||
"/tmp/cfe/ini_file.py" | ||
content => "$(ansible_ini_file[content])"; | ||
|
||
|
||
got_ini_file:: | ||
"/tmp/cfe/ini_file.py" | ||
perms => m_rxdirs( "0555", "true" ); | ||
|
||
# TODO - How to make sure that Python is installed | ||
# packages: | ||
# "python" | ||
# policy => "present", | ||
# package_module => generic, | ||
# comment => "Install python"; | ||
|
||
reports: | ||
|
||
got_ini_file:: | ||
"$(this.bundle): Successfully retrieved the Ansible INI policy file"; | ||
|
||
!got_ini_file:: | ||
"$(this.bundle): failed to get the Ansible INI policy file $(ansible_ini_file[error_message])"; | ||
|
||
} | ||
|
||
bundle agent main | ||
{ | ||
|
||
meta: | ||
"tags" slist => { "autorun" }; | ||
"bundle_version" string => "0.0.1"; | ||
"promise_type" string => "ini"; | ||
|
||
ini: | ||
"/home/olepor/cfengine/modules/promise-types/ini/test.toml" | ||
module_path => "/tmp/cfe/ini_file.py", | ||
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,102 @@ | ||
"""The ultimate CFEngine custom promise module""" | ||
|
||
import glob | ||
import json | ||
import os | ||
import shutil | ||
import subprocess | ||
import sys | ||
import tempfile | ||
|
||
from cfengine import PromiseModule, ValidationError, Result | ||
|
||
|
||
class AnsiballINIModule(PromiseModule): | ||
def __init__(self): | ||
super().__init__("ansible_ini_promise_module", "0.0.1") | ||
|
||
# AnsiballINIModule specific (the path from the policy) | ||
self.add_attribute("module_path", str, default="/tmp/cfe/ini_file.py") | ||
|
||
self.add_attribute("path", str, default_to_promiser=True) | ||
self.add_attribute("allow_no_value", bool, default=False) | ||
self.add_attribute("attributes", str) | ||
self.add_attribute("backup", bool, default=False) | ||
self.add_attribute("create", str, default="yes") | ||
self.add_attribute("group", str) | ||
self.add_attribute("mode", str) | ||
self.add_attribute("no_extra_spaces", str, default="yes") | ||
self.add_attribute("option", str) | ||
self.add_attribute("owner", str) | ||
self.add_attribute("section", str, required=True) | ||
# TODO - Add seLinux attrs | ||
# self.add_attribute("selevel", str, default="sO") | ||
# self.add_attribute("serole") | ||
|
||
self.add_attribute("state", str, default="present") | ||
self.add_attribute("unsafe_writes", bool, default=False) | ||
self.add_attribute("value", str) | ||
|
||
def validate_promise(self, promiser: str, attributes: dict, meta: dict) -> None: | ||
self.log_debug( | ||
"Validating the ansible ini promise: %s %s %s" | ||
% (promiser, attributes, meta) | ||
) | ||
|
||
if not meta.get("promise_type"): | ||
raise ValidationError("Promise type not specified") | ||
|
||
# Not an Ansible attribute | ||
if not attributes.get("module_path"): | ||
self.log_error("'module_path' is a required promise attribute") | ||
return (result.NOT_KEPT, []) | ||
|
||
def evaluate_promise(self, promiser: str, attributes: dict, meta: dict): | ||
self.log_debug( | ||
"Evaluating the ansible ini promise %s, %s, %s" | ||
% (promiser, attributes, meta) | ||
) | ||
|
||
# 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) | ||
|
||
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: %s" % proc.stdout) | ||
self.log_error("Ansible INI module returned: %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) | ||
return ( | ||
Result.KEPT, | ||
[], | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
AnsiballINIModule().start() |