state file.line with mode=insert doesn't seem to work for this use-case. I just get No changes needed to be made
I can use mode=ensure, but that ends up only allowing me to manage a single line and subsequent file.line states with mode=ensure replace the previous line that was managed.
I attempted escaping the various "special" characters in the match strings for insert_line_one and insert_line_six but that didn't help.
If I switch after to '.*' for insert_line_one and insert_line_six then the lines will be inserted but not where I wanted them.
I think it has something to do with a check that is trying to match a line in the similar location to where I'm attempting to insert <testing type="some">onetwothree</testing> and returning a false positive which leads to it skipping the insert. If I remove <testing type="that">threefourfive</testing> from between <one> and </one> lines then insert_line_one will work, but insert_line_six will still say No changes needed to be made because now its getting another false positive match and skipping the insert.
insert_line_simple and insert_line_simple_again show that it has no problem inserting a line without the xml attribute type="xxxx" in the content or match
I'm at a loss to submit a PR for this, it's preventing me from using file.line, so I've resorted to a hacky workaround with file.replace as it's less hastle than attempting a fix.
Any clues @isbm ?
/root/testfile:
<test>
<one>
<testing type="that">threefourfive</testing>
</one>
</test>
sls:
insert_line_one:
file.line:
- name : /root/testfile
- content: <testing type="some">onetwothree</testing>
- mode : insert
- after : <one>
- match : '<testing type="some">.*</testing>'
- indent : True
insert_line_six:
file.line:
- name : /root/testfile
- content: <testing type="thing">sixseveneight</testing>
- mode : insert
- after : <one>
- match : '<testing type="thing">.*</testing>'
- indent : True
insert_line_simple:
file.line:
- name : /root/testfile
- content: <testing>simple</testing>
- mode : insert
- before : <one>
- match : '<testing>.*</testing>'
- indent : True
insert_line_simple_again:
file.line:
- name : /root/testfile
- content: <testing>simple</testing>
- mode : insert
- after : <one>
- match : '<testing>.*</testing>'
- indent : True
<test>
<testing>simple</testing>
<one>
<testing>simple again</testing>
<testing type="thing">sixseveneight</testing>
<testing type="some">onetwothree</testing>
<testing type="that">threefourfive</testing>
</one>
</test>
<test>
<testing>simple</testing>
<one>
<testing>simple again</testing>
<testing type="that">threefourfive</testing>
</one>
</test>
local:
----------
ID: insert_line_one
Function: file.line
Name: /root/testfile
Result: True
Comment: No changes needed to be made
Started: 16:58:29.081017
Duration: 4.982 ms
Changes:
----------
ID: insert_line_six
Function: file.line
Name: /root/testfile
Result: True
Comment: No changes needed to be made
Started: 16:58:29.086139
Duration: 0.722 ms
Changes:
----------
ID: insert_line_simple
Function: file.line
Name: /root/testfile
Result: True
Comment: Changes were made
Started: 16:58:29.086999
Duration: 1.157 ms
Changes:
----------
diff:
---
+++
@@ -1,4 +1,5 @@
<test>+ <testing>simple</testing> <one> <testing type="that">threefourfive</testing> </one>
----------
ID: insert_line_simple_again
Function: file.line
Name: /root/testfile
Result: True
Comment: Changes were made
Started: 16:58:29.088301
Duration: 0.87 ms
Changes:
----------
diff:
---
+++
@@ -1,6 +1,7 @@
<test> <testing>simple</testing> <one>+ <testing>simple</testing> <testing type="that">threefourfive</testing> </one> </test>
Summary for local
------------
Succeeded: 4 (changed=2)
Failed: 0
------------
Total states run: 4
Total run time: 7.731 ms
md5-b24903365653ade67c148d700dc26c64
Salt Version:
Salt: 2016.11.1
Dependency Versions:
cffi: 1.9.1
cherrypy: Not Installed
dateutil: Not Installed
gitdb: Not Installed
gitpython: Not Installed
ioflo: Not Installed
Jinja2: 2.7.2
libgit2: Not Installed
libnacl: Not Installed
M2Crypto: Not Installed
Mako: Not Installed
msgpack-pure: Not Installed
msgpack-python: 0.4.8
mysql-python: Not Installed
pycparser: 2.17
pycrypto: 2.6.1
pygit2: Not Installed
Python: 2.7.5 (default, Nov 6 2016, 00:28:07)
python-gnupg: Not Installed
PyYAML: 3.10
PyZMQ: 15.3.0
RAET: Not Installed
smmap: Not Installed
timelib: Not Installed
Tornado: 4.2.1
ZMQ: 4.1.4
System Versions:
dist: centos 7.3.1611 Core
machine: x86_64
release: 3.10.0-514.2.2.el7.x86_64
system: Linux
version: CentOS Linux 7.3.1611 Core
Yeah, I wrote that few years ago with no unit tests. My bad.
Any help would be appreciated if you've got time to look deeper. Cheers :beers:
Looks like i'm able to replicate this behavior.
Here is a docker container for anyone that wants to quickly replicate this issue:
docker run -it -v /home/ch3ll/git/salt/:/testing/ ch3ll/issues:38670salt-call --local state.sls test -ldebugcat /root/testfileWe will need to get this fixed up thanks
I met the same issue. The cause is that file.line does not change the line if it finds the original line before/after the matched line has the common prefix of your content.
# modules/file.py line 1722
elif after and not before:
_assert_occurrence(body, after, 'after')
out = []
lines = body.split(os.linesep)
for idx in range(len(lines)):
_line = lines[idx]
out.append(_line)
cnd = _get_line_indent(_line, content, indent)
if _line.find(after) > -1:
# No dupes or append, if "after" is the last line
if (idx < len(lines) and _starts_till(lines[idx + 1], cnd) < 0) or idx + 1 == len(lines):
out.append(cnd)
body = os.linesep.join(out)
The problem is the function _starts_till. I'm not sure whether it is a feature, it is obscure and undocumented, I did some test and here is the result:
print(_starts_till('one', 'one')) #=> 0
print(_starts_till('one two', 'one two2')) #=> 0
print(_starts_till('one two three', 'one two2 three3')) #=> 1
print(_starts_till('one two three four', 'one two2 three3 four4')) #=> 2
A minimum test case to reproduce the issue:
create /tmp/test.txt:
file.managed:
- name: /tmp/test.txt
- contents: |
pr foo
pr bar
insert a to /tmp/test.txt:
file.line:
- name: /tmp/test.txt
- mode: insert
- after: 'pr foo'
- content: 'pr test'
- require:
- file: create /tmp/test.txt
The line "pr test" is not inserted since it is considered the same with "pr bar"
A workaround is using file.replace
create /tmp/test.txt:
file.managed:
- name: /tmp/test.txt
- contents: |
pr foo
pr bar
insert a to /tmp/test.txt:
file.replace:
- name: /tmp/test.txt
- pattern: 'pr foo'
- repl: '\g<0>\npr test'
- require:
- file: create /tmp/test.txt
The workaround from @doitian is very useful. One clarification: if you want it to work just like mode=insert, make sure that pattern matches the entire line before the content that you want to insert. \g<0> inserts the text that was matched, so if pattern matches part of a line, only the partial match will be inserted before the new content. Here is an example of inserting a new line in a configuration file after a commented-out example:
- pattern: '#mynetworks = hash.*'
- repl: '\g<0>\nmynetworks = {{ pillar['networks'] }}'
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
If this issue is closed prematurely, please leave a comment and we will gladly reopen the issue.
Hi,
Is this still a known issue or am I doing something wrong? It _seems_ as though if the start of "content" matches for more than 1 character then the entire line is seen to have matched and nothing happens.
"content" matching first character only: (works as expected)
cat /home/alex/file
ABC
cat test.sls
allow-access-1.1.1.1:
file.line:
- name: /home/alex/file
- mode: ensure
- after: ABC
- content: a 1.1.1.1;
allow-access-2.2.2.2:
file.line:
- name: /home/alex/file
- mode: ensure
- after: ABC
- content: a 2.2.2.2;
md5-1e9be9b170bcacca91354c8bed42d9c8
sudo salt-call --local state.apply
local:
----------
ID: allow-access-1.1.1.1
Function: file.line
Name: /home/alex/file
Result: True
Comment: Changes were made
Started: 04:48:24.017955
Duration: 7.287 ms
Changes:
----------
diff:
---
+++
@@ -1 +1,2 @@
ABC
+a 1.1.1.1;
----------
ID: allow-access-2.2.2.2
Function: file.line
Name: /home/alex/file
Result: True
Comment: Changes were made
Started: 04:48:24.025399
Duration: 1.187 ms
Changes:
----------
diff:
---
+++
@@ -1,2 +1,3 @@
ABC
+a 2.2.2.2;
a 1.1.1.1;
Summary for local
------------
Succeeded: 2 (changed=2)
Failed: 0
------------
Total states run: 2
Total run time: 8.474 ms
md5-1e9be9b170bcacca91354c8bed42d9c8
cat /home/alex/file
ABC
a 2.2.2.2;
a 1.1.1.1;
md5-e37f0f70b99da3ca2becd76f3f554968
cat test.sls
allow-access-1.1.1.1:
file.line:
- name: /home/alex/file
- mode: ensure
- after: ABC
- content: aa 1.1.1.1;
allow-access-2.2.2.2:
file.line:
- name: /home/alex/file
- mode: ensure
- after: ABC
- content: aa 2.2.2.2;
md5-1e9be9b170bcacca91354c8bed42d9c8
sudo salt-call --local state.apply
local:
----------
ID: allow-access-1.1.1.1
Function: file.line
Name: /home/alex/file
Result: True
Comment: Changes were made
Started: 06:23:44.059359
Duration: 6.691 ms
Changes:
----------
diff:
---
+++
@@ -1 +1,2 @@
ABC
+aa 1.1.1.1;
----------
ID: allow-access-2.2.2.2
Function: file.line
Name: /home/alex/file
Result: True
Comment: No changes needed to be made
Started: 06:23:44.066178
Duration: 0.785 ms
Changes:
Summary for local
------------
Succeeded: 2 (changed=1)
Failed: 0
------------
Total states run: 2
Total run time: 7.476 ms
md5-1e9be9b170bcacca91354c8bed42d9c8
cat /home/alex/file
ABC
aa 1.1.1.1;
md5-1e9be9b170bcacca91354c8bed42d9c8
salt-call --version
salt-call 2019.2.0 (Fluorine)
Happy to provide more information if what I'm seeing can't be easily reproduced.
I think this new PR https://github.com/saltstack/salt/pull/52333 might help in this use case
It seems to only match the first word instead of the whole line. And file.replace work-around is not a clean solution because you have to stop it changing the line every time Salt is run. I added a grep on the file to make this stop.
insert a to /tmp/test.txt:
file.replace:
- name: /tmp/test.txt
- pattern: 'pr foo'
- repl: '\g<0>\npr test'
- unless:
- grep "pr test" /tmp/test.txt
- require:
- file: create /tmp/test.txt
bump @waynew i know you were originally working on that PR which has now been moved to https://github.com/saltstack/salt/pull/53888
can you respond to @jsaathof 's concern "It seems to only match the first word instead of the whole line." surrounding the PR.
Hi,
it seems that this issue still persists in Salt 3000? Any updates on this?
Best regards
margau
bump @waynew see above ^
@margau looks like the PR was not merged yet but is labeled for sodium, but looks like it might not solve @jsaathof 's use case so pinging @waynew to get his comments here
Most helpful comment
A workaround is using
file.replace