forked from ansible/ansible
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lineinfile
executable file
·184 lines (167 loc) · 5.66 KB
/
lineinfile
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
87
88
89
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2012, Daniel Hokka Zakrisson <[email protected]>
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 Ansible. If not, see <http://www.gnu.org/licenses/>.
import re
import os
DOCUMENTATION = '''
---
module: lineinfile
author: Daniel Hokka Zakrisson
short_description: Ensure a particular line is in a file
description:
- This module will search a file for a line, and ensure that it is present or absent.
- This is primarily useful when you want to change a single line in a
file only. For other cases, see the M(copy) or M(template) modules.
version_added: "0.7"
options:
dest:
required: true
aliases: [ name, destfile ]
description:
- The file to modify
regexp:
required: true
description:
- The regular expression to look for in the file. For C(state=present),
the pattern to replace. For C(state=absent), the pattern of the line
to remove.
state:
required: false
choices: [ present, absent ]
default: "present"
aliases: []
description:
- Whether the line should be there or not.
line:
required: false
description:
- Required for C(state=present). The line to insert/replace into the
file. Must match the value given to C(regexp).
insertafter:
required: false
default: EOF
description:
- Used with C(state=present). If specified, the line will be inserted
after the specified regular expression. Two special values are
available; C(BOF) for inserting the line at the beginning of the
file, and C(EOF) for inserting the line at the end of the file.
choices: [ BOF, EOF ]
default: EOF
backup:
required: false
default: no
description:
- Create a backup file including the timestamp information so you can
get the original file back if you somehow clobbered it incorrectly.
examples:
- code: lineinfile dest=/etc/selinux/config regexp=^SELINUX= line=SELINUX=disabled
- code: lineinfile dest=/etc/sudoers state=absent regexp="^%wheel"
'''
def present(module, dest, regexp, line, insertafter, backup):
f = open(dest, 'rb')
lines = f.readlines()
f.close()
mre = re.compile(regexp)
if not mre.search(line):
module.fail_json(msg="usage error: line= doesn't match regexp (%s)" % regexp)
if insertafter in ('BOF', 'EOF'):
iare = None
else:
iare = re.compile(insertafter)
index = [-1, -1]
for lineno in range(0, len(lines)):
if mre.search(lines[lineno]):
index[0] = lineno
elif iare is not None and iare.search(lines[lineno]):
# + 1 for the next line
index[1] = lineno + 1
# Regexp matched a line in the file
if index[0] != -1:
if lines[index[0]] == line + os.linesep:
msg = ''
changed = False
else:
lines[index[0]] = line + os.linesep
msg = 'line replaced'
changed = True
# Add it to the beginning of the file
elif insertafter == 'BOF':
lines.insert(0, line + os.linesep)
msg = 'line added'
changed = True
# Add it to the end of the file if requested or if insertafter= didn't match
elif insertafter == 'EOF' or index[1] == -1:
lines.append(line + os.linesep)
msg = 'line added'
changed = True
# insertafter= matched
else:
lines.insert(index[1], line + os.linesep)
msg = 'line added'
changed = True
if changed:
if backup:
module.backup_local(dest)
f = open(dest, 'wb')
f.writelines(lines)
f.close()
module.exit_json(changed=changed, msg=msg)
def absent(module, dest, regexp, backup):
f = open(dest, 'rb')
lines = f.readlines()
f.close()
cre = re.compile(regexp)
found = []
def matcher(line):
if cre.search(line):
found.append(line)
return False
else:
return True
lines = filter(matcher, lines)
changed = len(found) > 0
if changed:
if backup:
module.backup_local(dest)
f = open(dest, 'wb')
f.writelines(lines)
f.close()
module.exit_json(changed=changed, found=len(found))
def main():
module = AnsibleModule(
argument_spec = dict(
dest=dict(required=True, aliases=['name', 'destfile']),
state=dict(default='present', choices=['absent', 'present']),
regexp=dict(required=True),
line=dict(aliases=['value']),
insertafter=dict(default='EOF'),
backup=dict(default=False, choices=BOOLEANS),
),
)
params = module.params
backup = module.boolean(module.params.get('backup', False))
if params['state'] == 'present':
if 'line' not in params:
module.fail_json(msg='line= is required with state=present')
present(module, params['dest'], params['regexp'], params['line'],
params['insertafter'], backup)
else:
absent(module, params['dest'], params['regexp'], backup)
# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()