sailesh1993 / rpms / cloud-init

Forked from rpms/cloud-init a year ago
Clone
f6265e
From 2428320b2157a0fcc0f35bea12584286ebd02aab Mon Sep 17 00:00:00 2001
f6265e
From: Eduardo Otubo <otubo@redhat.com>
f6265e
Date: Wed, 15 May 2019 12:15:25 +0200
f6265e
Subject: [PATCH 1/5] Azure: Ensure platform random_seed is always serializable
f6265e
 as JSON.
f6265e
f6265e
RH-Author: Eduardo Otubo <otubo@redhat.com>
f6265e
Message-id: <20190515121529.11191-2-otubo@redhat.com>
f6265e
Patchwork-id: 87881
f6265e
O-Subject: [rhel-7 cloud-init PATCHv2 1/5] Azure: Ensure platform random_seed is always serializable as JSON.
f6265e
Bugzilla: 1687565
f6265e
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
f6265e
RH-Acked-by: Mohammed Gamal <mgamal@redhat.com>
f6265e
f6265e
From: "Jason Zions (MSFT)" <jasonzio@microsoft.com>
f6265e
f6265e
BZ: 1687565
f6265e
BRANCH: rhel7/master-18.5
f6265e
UPSTREAM: 0dc3a77f
f6265e
BREW: 21696239
f6265e
f6265e
commit 0dc3a77f41f4544e4cb5a41637af7693410d4cdf
f6265e
Author: Jason Zions (MSFT) <jasonzio@microsoft.com>
f6265e
Date:   Tue Mar 26 18:53:50 2019 +0000
f6265e
f6265e
    Azure: Ensure platform random_seed is always serializable as JSON.
f6265e
f6265e
    The Azure platform surfaces random bytes into /sys via Hyper-V.
f6265e
    Python 2.7 json.dump() raises an exception if asked to convert
f6265e
    a str with non-character content, and python 3.0 json.dump()
f6265e
    won't serialize a "bytes" value. As a result, c-i instance
f6265e
    data is often not written by Azure, making reboots slower (c-i
f6265e
    has to repeat work).
f6265e
f6265e
    The random data is base64-encoded and then decoded into a string
f6265e
    (str or unicode depending on the version of Python in use). The
f6265e
    base64 string has just as many bits of entropy, so we're not
f6265e
    throwing away useful "information", but we can be certain
f6265e
    json.dump() will correctly serialize the bits.
f6265e
f6265e
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
f6265e
f6265e
Conflicts:
f6265e
    tests/unittests/test_datasource/test_azure.py
f6265e
    Skipped the commit edf052c as it removes support for python-2.6
f6265e
f6265e
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
f6265e
---
f6265e
 cloudinit/sources/DataSourceAzure.py          | 24 +++++++++++++++++++-----
f6265e
 tests/data/azure/non_unicode_random_string    |  1 +
f6265e
 tests/unittests/test_datasource/test_azure.py | 24 ++++++++++++++++++++++--
f6265e
 3 files changed, 42 insertions(+), 7 deletions(-)
f6265e
 create mode 100644 tests/data/azure/non_unicode_random_string
f6265e
f6265e
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
f6265e
index 2062ca5..a768b2c 100644
f6265e
--- a/cloudinit/sources/DataSourceAzure.py
f6265e
+++ b/cloudinit/sources/DataSourceAzure.py
f6265e
@@ -54,6 +54,7 @@ REPROVISION_MARKER_FILE = "/var/lib/cloud/data/poll_imds"
f6265e
 REPORTED_READY_MARKER_FILE = "/var/lib/cloud/data/reported_ready"
f6265e
 AGENT_SEED_DIR = '/var/lib/waagent'
f6265e
 IMDS_URL = "http://169.254.169.254/metadata/"
f6265e
+PLATFORM_ENTROPY_SOURCE = "/sys/firmware/acpi/tables/OEM0"
f6265e
 
f6265e
 # List of static scripts and network config artifacts created by
f6265e
 # stock ubuntu suported images.
f6265e
@@ -195,6 +196,8 @@ if util.is_FreeBSD():
f6265e
         RESOURCE_DISK_PATH = "/dev/" + res_disk
f6265e
     else:
f6265e
         LOG.debug("resource disk is None")
f6265e
+    # TODO Find where platform entropy data is surfaced
f6265e
+    PLATFORM_ENTROPY_SOURCE = None
f6265e
 
f6265e
 BUILTIN_DS_CONFIG = {
f6265e
     'agent_command': AGENT_START_BUILTIN,
f6265e
@@ -1100,16 +1103,27 @@ def _check_freebsd_cdrom(cdrom_dev):
f6265e
     return False
f6265e
 
f6265e
 
f6265e
-def _get_random_seed():
f6265e
+def _get_random_seed(source=PLATFORM_ENTROPY_SOURCE):
f6265e
     """Return content random seed file if available, otherwise,
f6265e
        return None."""
f6265e
     # azure / hyper-v provides random data here
f6265e
-    # TODO. find the seed on FreeBSD platform
f6265e
     # now update ds_cfg to reflect contents pass in config
f6265e
-    if util.is_FreeBSD():
f6265e
+    if source is None:
f6265e
         return None
f6265e
-    return util.load_file("/sys/firmware/acpi/tables/OEM0",
f6265e
-                          quiet=True, decode=False)
f6265e
+    seed = util.load_file(source, quiet=True, decode=False)
f6265e
+
f6265e
+    # The seed generally contains non-Unicode characters. load_file puts
f6265e
+    # them into a str (in python 2) or bytes (in python 3). In python 2,
f6265e
+    # bad octets in a str cause util.json_dumps() to throw an exception. In
f6265e
+    # python 3, bytes is a non-serializable type, and the handler load_file
f6265e
+    # uses applies b64 encoding *again* to handle it. The simplest solution
f6265e
+    # is to just b64encode the data and then decode it to a serializable
f6265e
+    # string. Same number of bits of entropy, just with 25% more zeroes.
f6265e
+    # There's no need to undo this base64-encoding when the random seed is
f6265e
+    # actually used in cc_seed_random.py.
f6265e
+    seed = base64.b64encode(seed).decode()
f6265e
+
f6265e
+    return seed
f6265e
 
f6265e
 
f6265e
 def list_possible_azure_ds_devs():
f6265e
diff --git a/tests/data/azure/non_unicode_random_string b/tests/data/azure/non_unicode_random_string
f6265e
new file mode 100644
f6265e
index 0000000..b9ecefb
f6265e
--- /dev/null
f6265e
+++ b/tests/data/azure/non_unicode_random_string
f6265e
@@ -0,0 +1 @@
f6265e
+OEM0d\x00\x00\x00\x01\x80VRTUALMICROSFT\x02\x17\x00\x06MSFT\x97\x00\x00\x00C\xb4{V\xf4X%\x061x\x90\x1c\xfen\x86\xbf~\xf5\x8c\x94&\x88\xed\x84\xf9B\xbd\xd3\xf1\xdb\xee:\xd9\x0fc\x0e\x83(\xbd\xe3'\xfc\x85,\xdf\xf4\x13\x99N\xc5\xf3Y\x1e\xe3\x0b\xa4H\x08J\xb9\xdcdb$
f6265e
\ No newline at end of file
f6265e
diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py
f6265e
index 417d86a..eacf225 100644
f6265e
--- a/tests/unittests/test_datasource/test_azure.py
f6265e
+++ b/tests/unittests/test_datasource/test_azure.py
f6265e
@@ -7,11 +7,11 @@ from cloudinit.sources import (
f6265e
     UNSET, DataSourceAzure as dsaz, InvalidMetaDataException)
f6265e
 from cloudinit.util import (b64e, decode_binary, load_file, write_file,
f6265e
                             find_freebsd_part, get_path_dev_freebsd,
f6265e
-                            MountFailedError)
f6265e
+                            MountFailedError, json_dumps, load_json)
f6265e
 from cloudinit.version import version_string as vs
f6265e
 from cloudinit.tests.helpers import (
f6265e
     HttprettyTestCase, CiTestCase, populate_dir, mock, wrap_and_call,
f6265e
-    ExitStack, PY26, SkipTest)
f6265e
+    ExitStack, PY26, SkipTest, resourceLocation)
f6265e
 
f6265e
 import crypt
f6265e
 import httpretty
f6265e
@@ -1924,4 +1924,24 @@ class TestWBIsPlatformViable(CiTestCase):
f6265e
             self.logs.getvalue())
f6265e
 
f6265e
 
f6265e
+class TestRandomSeed(CiTestCase):
f6265e
+    """Test proper handling of random_seed"""
f6265e
+
f6265e
+    def test_non_ascii_seed_is_serializable(self):
f6265e
+        """Pass if a random string from the Azure infrastructure which
f6265e
+        contains at least one non-Unicode character can be converted to/from
f6265e
+        JSON without alteration and without throwing an exception.
f6265e
+        """
f6265e
+        path = resourceLocation("azure/non_unicode_random_string")
f6265e
+        result = dsaz._get_random_seed(path)
f6265e
+
f6265e
+        obj = {'seed': result}
f6265e
+        try:
f6265e
+            serialized = json_dumps(obj)
f6265e
+            deserialized = load_json(serialized)
f6265e
+        except UnicodeDecodeError:
f6265e
+            self.fail("Non-serializable random seed returned")
f6265e
+
f6265e
+        self.assertEqual(deserialized['seed'], result)
f6265e
+
f6265e
 # vi: ts=4 expandtab
f6265e
-- 
f6265e
1.8.3.1
f6265e