← Back to team overview

cloud-init-dev team mailing list archive

[Merge] lp:~harlowja/cloud-init/cloud-jsonpatch into lp:cloud-init

 

Joshua Harlow has proposed merging lp:~harlowja/cloud-init/cloud-jsonpatch into lp:cloud-init.

Requested reviews:
  cloud init development team (cloud-init-dev)
Related bugs:
  Bug #1200476 in cloud-init: "Allow for merging with json-patch"
  https://bugs.launchpad.net/cloud-init/+bug/1200476

For more details, see:
https://code.launchpad.net/~harlowja/cloud-init/cloud-jsonpatch/+merge/175964

Need to add some tests...
-- 
https://code.launchpad.net/~harlowja/cloud-init/cloud-jsonpatch/+merge/175964
Your team cloud init development team is requested to review the proposed merge of lp:~harlowja/cloud-init/cloud-jsonpatch into lp:cloud-init.
=== modified file 'Requires'
--- Requires	2013-03-19 22:53:16 +0000
+++ Requires	2013-07-19 23:37:27 +0000
@@ -27,3 +27,6 @@
 
 # Boto for ec2
 boto
+
+# For patching pieces of cloud-config together
+jsonpatch

=== modified file 'cloudinit/handlers/cloud_config.py'
--- cloudinit/handlers/cloud_config.py	2013-05-10 05:47:14 +0000
+++ cloudinit/handlers/cloud_config.py	2013-07-19 23:37:27 +0000
@@ -20,6 +20,8 @@
 #    You should have received a copy of the GNU General Public License
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import jsonpatch
+
 from cloudinit import handlers
 from cloudinit import log as logging
 from cloudinit import mergers
@@ -50,6 +52,9 @@
 # This gets loaded into yaml with final result {'a': 22}
 DEF_MERGERS = mergers.string_extract_mergers('dict(replace)+list()+str()')
 
+# See: https://tools.ietf.org/html/rfc6902
+JSON_PATCH_CTYPE = 'application/json-patch+json'
+
 
 class CloudConfigPartHandler(handlers.Handler):
     def __init__(self, paths, **_kwargs):
@@ -59,9 +64,11 @@
         self.file_names = []
 
     def list_types(self):
-        return [
+        ctypes_handled = [
             handlers.type_from_starts_with("#cloud-config"),
+            JSON_PATCH_CTYPE,
         ]
+        return ctypes_handled
 
     def _write_cloud_config(self):
         if not self.cloud_fn:
@@ -107,13 +114,15 @@
             all_mergers = DEF_MERGERS
         return (payload_yaml, all_mergers)
 
+    def _merge_patch(self, payload):
+        patch = jsonpatch.JsonPatch.from_string(payload)
+        LOG.debug("Merging by applying json patch %s", patch)
+        self.cloud_buf = patch.apply(self.cloud_buf, in_place=False)
+
     def _merge_part(self, payload, headers):
         (payload_yaml, my_mergers) = self._extract_mergers(payload, headers)
         LOG.debug("Merging by applying %s", my_mergers)
         merger = mergers.construct(my_mergers)
-        if self.cloud_buf is None:
-            # First time through, merge with an empty dict...
-            self.cloud_buf = {}
         self.cloud_buf = merger.merge(self.cloud_buf, payload_yaml)
 
     def _reset(self):
@@ -130,7 +139,13 @@
             self._reset()
             return
         try:
-            self._merge_part(payload, headers)
+            # First time through, merge with an empty dict...
+            if self.cloud_buf is None or not self.file_names:
+                self.cloud_buf = {}
+            if ctype == JSON_PATCH_CTYPE:
+                self._merge_patch(payload)
+            else:
+                self._merge_part(payload, headers)
             # Ensure filename is ok to store
             for i in ("\n", "\r", "\t"):
                 filename = filename.replace(i, " ")


Follow ups