|
|
ef3f20 |
From 29ed6e1c54a6ffbc3017660af5e2a81850e46b43 Mon Sep 17 00:00:00 2001
|
|
|
ef3f20 |
From: Lars Kellogg-Stedman <lars@redhat.com>
|
|
|
ef3f20 |
Date: Mon, 10 Apr 2017 15:52:37 -0400
|
|
|
ef3f20 |
Subject: [PATCH] util: teach write_file about copy_mode option
|
|
|
ef3f20 |
|
|
|
ef3f20 |
On centos/fedora/rhel/derivatives, /etc/ssh/sshd_config has mode 0600,
|
|
|
ef3f20 |
but cloud-init unilaterally sets file modes to 0644 when no explicit
|
|
|
ef3f20 |
mode is passed to util.write_file. On ubuntu/debian, this file has
|
|
|
ef3f20 |
mode 0644. With this patch, write_file learns about the copy_mode
|
|
|
ef3f20 |
option, which will cause it to use the mode of the existing file by
|
|
|
ef3f20 |
default, falling back to the explicit mode parameter if the file does
|
|
|
ef3f20 |
not exist.
|
|
|
ef3f20 |
|
|
|
ef3f20 |
LP: #1644064
|
|
|
ef3f20 |
Resolves: rhbz#1295984
|
|
|
ef3f20 |
(cherry picked from commit 721348a622a660b65acfdf7fdf53203b47f80748)
|
|
|
ef3f20 |
---
|
|
|
ef3f20 |
cloudinit/atomic_helper.py | 12 +++++++++++-
|
|
|
ef3f20 |
cloudinit/config/cc_set_passwords.py | 3 ++-
|
|
|
ef3f20 |
cloudinit/util.py | 10 +++++++++-
|
|
|
ef3f20 |
tests/unittests/test_util.py | 33 +++++++++++++++++++++++++++++++--
|
|
|
ef3f20 |
4 files changed, 53 insertions(+), 5 deletions(-)
|
|
|
ef3f20 |
|
|
|
ef3f20 |
diff --git a/cloudinit/atomic_helper.py b/cloudinit/atomic_helper.py
|
|
|
ef3f20 |
index fb2df8d..587b994 100644
|
|
|
ef3f20 |
--- a/cloudinit/atomic_helper.py
|
|
|
ef3f20 |
+++ b/cloudinit/atomic_helper.py
|
|
|
ef3f20 |
@@ -2,13 +2,23 @@
|
|
|
ef3f20 |
|
|
|
ef3f20 |
import json
|
|
|
ef3f20 |
import os
|
|
|
ef3f20 |
+import stat
|
|
|
ef3f20 |
import tempfile
|
|
|
ef3f20 |
|
|
|
ef3f20 |
_DEF_PERMS = 0o644
|
|
|
ef3f20 |
|
|
|
ef3f20 |
|
|
|
ef3f20 |
-def write_file(filename, content, mode=_DEF_PERMS, omode="wb"):
|
|
|
ef3f20 |
+def write_file(filename, content, mode=_DEF_PERMS,
|
|
|
ef3f20 |
+ omode="wb", copy_mode=False):
|
|
|
ef3f20 |
# open filename in mode 'omode', write content, set permissions to 'mode'
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
+ if copy_mode:
|
|
|
ef3f20 |
+ try:
|
|
|
ef3f20 |
+ file_stat = os.stat(filename)
|
|
|
ef3f20 |
+ mode = stat.S_IMODE(file_stat.st_mode)
|
|
|
ef3f20 |
+ except OSError:
|
|
|
ef3f20 |
+ pass
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
tf = None
|
|
|
ef3f20 |
try:
|
|
|
ef3f20 |
tf = tempfile.NamedTemporaryFile(dir=os.path.dirname(filename),
|
|
|
ef3f20 |
diff --git a/cloudinit/config/cc_set_passwords.py b/cloudinit/config/cc_set_passwords.py
|
|
|
ef3f20 |
index cf1f59e..2745df8 100755
|
|
|
ef3f20 |
--- a/cloudinit/config/cc_set_passwords.py
|
|
|
ef3f20 |
+++ b/cloudinit/config/cc_set_passwords.py
|
|
|
ef3f20 |
@@ -174,7 +174,8 @@ def handle(_name, cfg, cloud, log, args):
|
|
|
ef3f20 |
pw_auth))
|
|
|
ef3f20 |
|
|
|
ef3f20 |
lines = [str(l) for l in new_lines]
|
|
|
ef3f20 |
- util.write_file(ssh_util.DEF_SSHD_CFG, "\n".join(lines))
|
|
|
ef3f20 |
+ util.write_file(ssh_util.DEF_SSHD_CFG, "\n".join(lines),
|
|
|
ef3f20 |
+ copy_mode=True)
|
|
|
ef3f20 |
|
|
|
ef3f20 |
try:
|
|
|
ef3f20 |
cmd = cloud.distro.init_cmd # Default service
|
|
|
ef3f20 |
diff --git a/cloudinit/util.py b/cloudinit/util.py
|
|
|
ef3f20 |
index 5725129..f90653d 100644
|
|
|
ef3f20 |
--- a/cloudinit/util.py
|
|
|
ef3f20 |
+++ b/cloudinit/util.py
|
|
|
ef3f20 |
@@ -1732,7 +1732,7 @@ def chmod(path, mode):
|
|
|
ef3f20 |
os.chmod(path, real_mode)
|
|
|
ef3f20 |
|
|
|
ef3f20 |
|
|
|
ef3f20 |
-def write_file(filename, content, mode=0o644, omode="wb"):
|
|
|
ef3f20 |
+def write_file(filename, content, mode=0o644, omode="wb", copy_mode=False):
|
|
|
ef3f20 |
"""
|
|
|
ef3f20 |
Writes a file with the given content and sets the file mode as specified.
|
|
|
ef3f20 |
Resotres the SELinux context if possible.
|
|
|
ef3f20 |
@@ -1742,6 +1742,14 @@ def write_file(filename, content, mode=0o644, omode="wb"):
|
|
|
ef3f20 |
@param mode: The filesystem mode to set on the file.
|
|
|
ef3f20 |
@param omode: The open mode used when opening the file (w, wb, a, etc.)
|
|
|
ef3f20 |
"""
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
+ if copy_mode:
|
|
|
ef3f20 |
+ try:
|
|
|
ef3f20 |
+ file_stat = os.stat(filename)
|
|
|
ef3f20 |
+ mode = stat.S_IMODE(file_stat.st_mode)
|
|
|
ef3f20 |
+ except OSError:
|
|
|
ef3f20 |
+ pass
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
ensure_dir(os.path.dirname(filename))
|
|
|
ef3f20 |
if 'b' in omode.lower():
|
|
|
ef3f20 |
content = encode_text(content)
|
|
|
ef3f20 |
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
|
|
|
ef3f20 |
index ab74311..5d21b4b 100644
|
|
|
ef3f20 |
--- a/tests/unittests/test_util.py
|
|
|
ef3f20 |
+++ b/tests/unittests/test_util.py
|
|
|
ef3f20 |
@@ -103,8 +103,8 @@ class TestWriteFile(helpers.TestCase):
|
|
|
ef3f20 |
self.assertTrue(os.path.isdir(dirname))
|
|
|
ef3f20 |
self.assertTrue(os.path.isfile(path))
|
|
|
ef3f20 |
|
|
|
ef3f20 |
- def test_custom_mode(self):
|
|
|
ef3f20 |
- """Verify custom mode works properly."""
|
|
|
ef3f20 |
+ def test_explicit_mode(self):
|
|
|
ef3f20 |
+ """Verify explicit file mode works properly."""
|
|
|
ef3f20 |
path = os.path.join(self.tmp, "NewFile.txt")
|
|
|
ef3f20 |
contents = "Hey there"
|
|
|
ef3f20 |
|
|
|
ef3f20 |
@@ -115,6 +115,35 @@ class TestWriteFile(helpers.TestCase):
|
|
|
ef3f20 |
file_stat = os.stat(path)
|
|
|
ef3f20 |
self.assertEqual(0o666, stat.S_IMODE(file_stat.st_mode))
|
|
|
ef3f20 |
|
|
|
ef3f20 |
+ def test_copy_mode_no_existing(self):
|
|
|
ef3f20 |
+ """Verify that file is created with mode 0o644 if copy_mode
|
|
|
ef3f20 |
+ is true and there is no prior existing file."""
|
|
|
ef3f20 |
+ path = os.path.join(self.tmp, "NewFile.txt")
|
|
|
ef3f20 |
+ contents = "Hey there"
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
+ util.write_file(path, contents, copy_mode=True)
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
+ self.assertTrue(os.path.exists(path))
|
|
|
ef3f20 |
+ self.assertTrue(os.path.isfile(path))
|
|
|
ef3f20 |
+ file_stat = os.stat(path)
|
|
|
ef3f20 |
+ self.assertEqual(0o644, stat.S_IMODE(file_stat.st_mode))
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
+ def test_copy_mode_with_existing(self):
|
|
|
ef3f20 |
+ """Verify that file is created using mode of existing file
|
|
|
ef3f20 |
+ if copy_mode is true."""
|
|
|
ef3f20 |
+ path = os.path.join(self.tmp, "NewFile.txt")
|
|
|
ef3f20 |
+ contents = "Hey there"
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
+ open(path, 'w').close()
|
|
|
ef3f20 |
+ os.chmod(path, 0o666)
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
+ util.write_file(path, contents, copy_mode=True)
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
+ self.assertTrue(os.path.exists(path))
|
|
|
ef3f20 |
+ self.assertTrue(os.path.isfile(path))
|
|
|
ef3f20 |
+ file_stat = os.stat(path)
|
|
|
ef3f20 |
+ self.assertEqual(0o666, stat.S_IMODE(file_stat.st_mode))
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
def test_custom_omode(self):
|
|
|
ef3f20 |
"""Verify custom omode works properly."""
|
|
|
ef3f20 |
path = os.path.join(self.tmp, "NewFile.txt")
|