Secondary migration from google3 into AOSP.

The 2nd revival of AOSP acloud is upon us!

The cl revision the acloud g3 code was pulled from is 195930083.

Things I did:
- Added AOSP copyright for new files and updated g3 imports to be relative.
- Merged in changes into existing files (easier to see changes here and
  for future cls).
- Scrubbed default.config of project and build info.
- Merge acloud.py (from g3) into acloud_main.py (entry point for AOSP
  acloud).
- Regenerated internal_config_pb2.py and user_config_pb2.py.
- Removed add_mock from gcomputer_client_test and added TODO in file
  where to replace it and updated parameterized to import from
  absl.testing.
- Updated references to gce_x86 to aosp_cf_x86_phone and updated branch
  references to 'aosp-master'.

Thing to note:
- New files fail pylint (in order to make it easy to check history on new files,
  formatting will be done using yapf in another cl).
- pip install acloud.zip seg faults so investigation and fix for that
  will happen in another cl.
- User needs to 'pip install absl-py' for parameterized lib in unittests.

Bug: 79684654
Test: ./run_tests.sh
Change-Id: I060641227d7c9162a45557e732686f22b83895e9
diff --git a/internal/lib/goldfish_compute_client.py b/internal/lib/goldfish_compute_client.py
new file mode 100644
index 0000000..01278fc
--- /dev/null
+++ b/internal/lib/goldfish_compute_client.py
@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+#
+# Copyright 2018 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""A client that manages Goldfish Virtual Device on compute engine.
+
+** GoldfishComputeClient **
+
+GoldfishComputeClient derives from AndroidComputeClient. It manges a google
+compute engine project that is setup for running Goldfish Virtual Devices.
+It knows how to create a host instance from a Goldfish Stable Host Image, fetch
+Android build, an emulator build, and start Android within the host instance.
+
+** Class hierarchy **
+
+  base_cloud_client.BaseCloudApiClient
+                ^
+                |
+       gcompute_client.ComputeClient
+                ^
+                |
+       android_compute_client.AndroidComputeClient
+                ^
+                |
+       goldfish_compute_client.GoldfishComputeClient
+
+
+TODO(jansen): This class should likely be merged with CvdComputeClient
+"""
+
+import getpass
+import logging
+import os
+
+from acloud.internal.lib import android_compute_client
+from acloud.internal.lib import gcompute_client
+from acloud.public import errors
+
+logger = logging.getLogger(__name__)
+
+
+class GoldfishComputeClient(android_compute_client.AndroidComputeClient):
+  """Client that manages Goldfish based Android Virtual Device."""
+
+  # To determine if the boot failed
+  BOOT_FAILED_MSG = "VIRTUAL_DEVICE_FAILED"
+
+  # To determine the failure reason
+  # If the emulator build is not available
+  EMULATOR_FETCH_FAILED_MSG = "EMULATOR_FETCH_FAILED"
+  # If the system image build is not available
+  ANDROID_FETCH_FAILED_MSG = "ANDROID_FETCH_FAILED"
+  # If the emulator could not boot in time
+  BOOT_TIMEOUT_MSG = "VIRTUAL_DEVICE_BOOT_FAILED"
+
+  def __init__(self, acloud_config, oauth2_credentials):
+    """Initialize.
+
+    Args:
+      acloud_config: An AcloudConfig object.
+      oauth2_credentials: An oauth2client.OAuth2Credentials instance.
+    """
+    super(GoldfishComputeClient, self).__init__(acloud_config,
+                                                oauth2_credentials)
+
+  def _GetDiskArgs(self, disk_name, image_name, image_project, disk_size_gb):
+    """Helper to generate disk args that is used to create an instance.
+
+    Args:
+      disk_name: A string
+      image_name: A string
+      image_project: A string
+      disk_size_gb: An integer
+
+    Returns:
+      A dictionary representing disk args.
+    """
+    return [{
+        "type": "PERSISTENT",
+        "boot": True,
+        "mode": "READ_WRITE",
+        "autoDelete": True,
+        "initializeParams": {
+            "diskName":
+                disk_name,
+            "sourceImage":
+                self.GetImage(image_name, image_project)["selfLink"],
+            "diskSizeGb":
+                disk_size_gb
+        },
+    }]
+
+  def CheckBootFailure(self, serial_out, instance):
+    """Overriding method from the parent class.
+
+    Args:
+      serial_out: A string
+      instance: A string
+
+    Raises:
+      Raises an errors.DeviceBootError exception if a failure is detected.
+    """
+    if self.BOOT_FAILED_MSG in serial_out:
+      if self.EMULATOR_FETCH_FAILED_MSG in serial_out:
+        raise errors.DeviceBootError(
+            "Failed to download emulator build. Re-run with a newer build.")
+      if self.ANDROID_FETCH_FAILED_MSG in serial_out:
+        raise errors.DeviceBootError(
+            "Failed to download system image build. Re-run with a newer build.")
+      if self.BOOT_TIMEOUT_MSG in serial_out:
+        raise errors.DeviceBootError(
+            "Emulator timed out while booting.")
+
+  def CreateInstance(self,
+                     instance,
+                     image_name,
+                     image_project,
+                     build_target,
+                     branch,
+                     build_id,
+                     emulator_branch=None,
+                     emulator_build_id=None,
+                     blank_data_disk_size_gb=None,
+                     gpu=None):
+    """Create a goldfish instance given a stable host image and a build id.
+
+    Args:
+      instance: instance name.
+      image_name: A string, the name of the system image.
+      image_project: A string, name of the project where the image belongs.
+                     Assume the default project if None.
+      build_target: Target name, e.g. "sdk_phone_x86_64-sdk"
+      branch: Branch name, e.g. "git_pi-dev"
+      build_id: Build id, a string, e.g. "2263051", "P2804227"
+      emulator_branch: emulator branch name, e.g.
+        "aosp-emu-master-dev"
+      emulator_build_id: emulator build id, a string, e.g. "2263051", "P2804227"
+      blank_data_disk_size_gb: Size of the blank data disk in GB.
+      gpu: GPU that should be attached to the instance, or None of no
+        acceleration is needed. e.g. "nvidia-tesla-k80"
+    """
+    self._CheckMachineSize()
+
+    # Add space for possible data partition.
+    boot_disk_size_gb = (
+        int(self.GetImage(image_name, image_project)["diskSizeGb"]) +
+        blank_data_disk_size_gb)
+    disk_args = self._GetDiskArgs(instance, image_name, image_project,
+                                  boot_disk_size_gb)
+
+    # Goldfish instances are metadata compatible with cuttlefish devices.
+    # See details goto/goldfish-deployment
+    metadata = self._metadata.copy()
+    resolution = self._resolution.split("x")
+
+    # Note that we use the same metadata naming conventions as cuttlefish
+    metadata["cvd_01_dpi"] = resolution[3]
+    metadata["cvd_01_fetch_android_build_target"] = build_target
+    metadata["cvd_01_fetch_android_bid"] = "{branch}/{build_id}".format(
+        branch=branch, build_id=build_id)
+    if emulator_branch and emulator_build_id:
+      metadata["cvd_01_fetch_emulator_bid"] = "{branch}/{build_id}".format(
+          branch=emulator_branch, build_id=emulator_build_id)
+    metadata["cvd_01_launch"] = "1"
+    metadata["cvd_01_x_res"] = resolution[0]
+    metadata["cvd_01_y_res"] = resolution[1]
+
+    # Add per-instance ssh key
+    if self._ssh_public_key_path:
+      rsa = self._LoadSshPublicKey(self._ssh_public_key_path)
+      logger.info("ssh_public_key_path is specified in config: %s, "
+                  "will add the key to the instance.",
+                  self._ssh_public_key_path)
+      metadata["sshKeys"] = "%s:%s" % (getpass.getuser(), rsa)
+    else:
+      logger.warning("ssh_public_key_path is not specified in config, "
+                     "only project-wide key will be effective.")
+
+    gcompute_client.ComputeClient.CreateInstance(
+        self,
+        instance=instance,
+        image_name=image_name,
+        image_project=image_project,
+        disk_args=disk_args,
+        metadata=metadata,
+        machine_type=self._machine_type,
+        network=self._network,
+        zone=self._zone,
+        gpu=gpu)