devserver: Add locking around metadata read and write.

A race condition between reading and writing to the
metadata file is causing update failures in the CQ.

Use a file lock to protect both reads and writes.

BUG=chromium:554773

Change-Id: I4db224412ae3f5dfb045d99d90662a7c420cbcdb
Reviewed-on: https://chromium-review.googlesource.com/316913
Commit-Ready: Matthew Sartori <msartori@chromium.org>
Tested-by: Matthew Sartori <msartori@chromium.org>
Reviewed-by: Dan Shi <dshi@google.com>
diff --git a/autoupdate.py b/autoupdate.py
index a2a293f..5156268 100644
--- a/autoupdate.py
+++ b/autoupdate.py
@@ -6,6 +6,7 @@
 
 import base64
 import collections
+import fcntl
 import json
 import os
 import struct
@@ -226,8 +227,11 @@
     """Returns metadata object from the metadata_file in the payload_dir"""
     metadata_file = os.path.join(payload_dir, constants.METADATA_FILE)
     if os.path.exists(metadata_file):
-      with open(metadata_file, 'r') as metadata_stream:
-        return Autoupdate._ReadMetadataFromStream(metadata_stream)
+      metadata_stream = open(metadata_file, 'r')
+      fcntl.lockf(metadata_stream.fileno(), fcntl.LOCK_SH)
+      metadata = Autoupdate._ReadMetadataFromStream(metadata_stream)
+      fcntl.lockf(metadata_stream.fileno(), fcntl.LOCK_UN)
+      return metadata
 
   @classmethod
   def _StoreMetadataToFile(cls, payload_dir, metadata_obj):
@@ -239,8 +243,10 @@
                  cls.METADATA_SIZE_ATTR: metadata_obj.metadata_size,
                  cls.METADATA_HASH_ATTR: metadata_obj.metadata_hash}
     metadata_file = os.path.join(payload_dir, constants.METADATA_FILE)
-    with open(metadata_file, 'w') as file_handle:
-      json.dump(file_dict, file_handle)
+    file_handle = open(metadata_file, 'w')
+    fcntl.lockf(file_handle.fileno(), fcntl.LOCK_EX)
+    json.dump(file_dict, file_handle)
+    fcntl.lockf(file_handle.fileno(), fcntl.LOCK_UN)
 
   @staticmethod
   def _GetVersionFromDir(image_dir):