Reland "PrepareBinhostUploads: Write the package index file with sudo"

This is a reland of b2a979c0b7bb03851a79839c90c294259a91f7a0

Fixed the package index writing issue, added some path fixes in the
API, and added a read/write test for lib/binpkg to avoid this problem
again in the future.

Original change's description:
> PrepareBinhostUploads: Write the package index file with sudo
>
> BUG=chromium:950959
> TEST=run_tests
>
> Change-Id: I6fce69bb1a4af4beccb880dad40c430c66e9d0dd
> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1615610
> Tested-by: Alex Klein <saklein@chromium.org>
> Reviewed-by: Evan Hernandez <evanhernandez@chromium.org>
> Commit-Queue: Alex Klein <saklein@chromium.org>

BUG=chromium:950959
TEST=run_tests

Change-Id: Idd6609b27eded278872f82d99a39e79978757cd2
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1618600
Tested-by: Alex Klein <saklein@chromium.org>
Reviewed-by: Evan Hernandez <evanhernandez@chromium.org>
Commit-Queue: Alex Klein <saklein@chromium.org>
diff --git a/api/controller/binhost.py b/api/controller/binhost.py
index ca464d4..2ba5ad0 100644
--- a/api/controller/binhost.py
+++ b/api/controller/binhost.py
@@ -34,13 +34,14 @@
 
   parsed_uri = urlparse.urlparse(uri)
   upload_uri = gs.GetGsURL(parsed_uri.netloc)
-  upload_path = parsed_uri.path
+  upload_path = parsed_uri.path.lstrip('/')
 
   # Read all packages and update the index. The index must be uploaded to the
   # binhost for Portage to use it, so include it in upload_targets.
   uploads_dir = binhost.GetPrebuiltsRoot(target)
   upload_targets = binhost.GetPrebuiltsFiles(uploads_dir)
-  index_path = binhost.UpdatePackageIndex(uploads_dir, upload_uri, upload_path)
+  index_path = binhost.UpdatePackageIndex(uploads_dir, upload_uri, upload_path,
+                                          sudo=True)
   assert index_path.startswith(uploads_dir), (
       'expected index_path to start with uploads_dir')
   upload_targets.append(index_path[len(uploads_dir):])