Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/python
# Copyright: (c) 2019, Nicolas Karolak <nicolas.karolak@ubicast.eu>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
module: source_file
short_description: Source remote bash/dotenv file
description:
- This module is used to register host variables from a remote bash/dotenv-like file.
- It handles boolean value (`MY_VAR=1`) and has a basic handling of list (`MY_VAR=one,two,three`) and dictionnary (`MY_VAR=a=1;b=2;c=3`).
version_added: "2.8"
author: "Nicolas Karolak (@nikaro)"
options:
path:
description:
- Path to the file to source.
required: true
type: path
prefix:
description:
- Prefix to add to the registred variable name.
required: false
default: ""
type: str
lower:
description:
- Wether to lower or not the variable name.
required: false
default: false
type: bool
notes:
- The `check_mode` is supported.
"""
EXAMPLES = """
- name: source envsetup file
source_file:
prefix: envsetup_
path: /root/envsetup/conf.sh
lower: true
"""
RETURN = """
ansible_facts:
description: Registred vairales.
returned: on success
type: dict
sample:
key: value
"""
import os
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.parsing.convert_bool import BOOLEANS, boolean
from ansible.module_utils.six import string_types
def run_module():
module_args = {
"path": {"type": "path", "required": True},
"prefix": {"type": "str", "required": False, "default": ""},
"lower": {"type": "bool", "required": False, "default": False},
}
result = {"changed": False}
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
path = module.params["path"]
prefix = module.params["prefix"]
lower = boolean(module.params["lower"])
variables = {}
regex_valid_name = re.compile(r"^[a-zA-Z][a-zA-Z0-9_-]*$")
r"^(?!#)(?P<key>[a-zA-Z][a-zA-Z0-9_-]*)=(?:[\'\"])?(?P<value>(?:[^\'\"\n])*)(?:[\'\"])?$",
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
re.MULTILINE
)
if not os.path.isfile(path):
module.fail_json(msg="'%s' does not exist or is not a file" % path, **result)
if prefix and not regex_valid_name.match(prefix):
module.fail_json(
msg="'%s' is not a valid prefix it must starts with a letter or underscore"
" character, and contains only letters, numbers and underscores" % prefix,
**result
)
with open(path) as path_fh:
# load file content and get all "key=value"
content = path_fh.read()
content_match = regex_key_value.findall(content)
for key, value in content_match:
# merge prefix + key
if prefix:
key = "%s%s" % (prefix, key)
# lower key
if lower:
key = key.lower()
# check key validity
if not regex_valid_name.match(key):
module.fail_json(
msg="'%s' is not a valid variable name it must starts with a letter or "
"underscore character, and contains only letters, numbers and underscores"
% key,
**result
)
# handle list value
if "," in value:
value = re.split("[,\n]", value)
# handle dict value
if ";" in value and "=" in value:
value = {i.split("=")[0]: i.split("=")[1] for i in value.split(";")}
# handle bool value
if isinstance(value, string_types) and value.lower() in BOOLEANS:
value = boolean(value)
# build variables dict
variables[key] = value
result["changed"] = True
if not module.check_mode:
result["ansible_facts"] = variables
module.exit_json(**result)
def main():
run_module()
if __name__ == "__main__":
main()