Merge "To support goldfish type AVD in acloud create command."
diff --git a/Android.bp b/Android.bp
index 41c2390..65b7b79 100644
--- a/Android.bp
+++ b/Android.bp
@@ -29,6 +29,8 @@
python_binary_host {
name: "acloud",
+ // Make acloud's built name to acloud-dev
+ stem: "acloud-dev",
defaults: ["acloud_default"],
main: "public/acloud_main.py",
srcs: [
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..135fa2d
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,47 @@
+# Copyright (C) 2019 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# Discard the original naming "acloud", which is going to be replaced with "acloud-dev".
+$(call add-clean-step, rm -f $(HOST_OUT_EXECUTABLES)/acloud)
+$(call add-clean-step, rm -f $(SOONG_HOST_OUT_EXECUTABLES)/acloud)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 136a761..e5c5e28 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -2,4 +2,4 @@
pylint = true
[Hook Scripts]
-acloud_unittests = ${REPO_ROOT}/prebuilts/asuite/atest/${BUILD_OS}/atest acloud_test
+acloud_unittests = ${REPO_ROOT}/prebuilts/asuite/atest/${BUILD_OS}/atest acloud_test --host
diff --git a/internal/constants.py b/internal/constants.py
index aaec56a..8a896cc 100755
--- a/internal/constants.py
+++ b/internal/constants.py
@@ -91,7 +91,7 @@
USER_ANSWER_YES = {"y", "yes", "Y"}
# Cuttlefish groups
-LIST_CF_USER_GROUPS = ["kvm", "libvirt", "cvdnetwork"]
+LIST_CF_USER_GROUPS = ["kvm", "cvdnetwork"]
#For the cuttlefish remote instances: adb port is 6520 and vnc is 6444.
CF_TARGET_ADB_PORT = 6520
CF_TARGET_VNC_PORT = 6444
diff --git a/internal/lib/cheeps_compute_client.py b/internal/lib/cheeps_compute_client.py
index ffa62a3..5ef344a 100644
--- a/internal/lib/cheeps_compute_client.py
+++ b/internal/lib/cheeps_compute_client.py
@@ -37,6 +37,7 @@
import getpass
import logging
+from acloud import errors
from acloud.internal.lib import android_compute_client
from acloud.internal.lib import gcompute_client
@@ -49,7 +50,15 @@
"""
# This is the timeout for betty to start.
BOOT_TIMEOUT_SECS = 10*60
+ # This is printed by betty.sh.
BOOT_COMPLETED_MSG = "VM successfully started"
+ # systemd prints this if betty.sh returns nonzero status code.
+ BOOT_FAILED_MSG = "betty.service: Failed with result 'exit-code'"
+
+ def CheckBootFailure(self, serial_out, instance):
+ """Overrides superclass. Determines if there's a boot failure."""
+ if self.BOOT_FAILED_MSG in serial_out:
+ raise errors.DeviceBootError("Betty failed to start")
# pylint: disable=too-many-locals,arguments-differ
def CreateInstance(self, instance, image_name, image_project,
diff --git a/internal/lib/gcompute_client.py b/internal/lib/gcompute_client.py
index 1f44de0..f70a5ea 100755
--- a/internal/lib/gcompute_client.py
+++ b/internal/lib/gcompute_client.py
@@ -39,6 +39,11 @@
logger = logging.getLogger(__name__)
_MAX_RETRIES_ON_FINGERPRINT_CONFLICT = 10
+_METADATA_KEY = "key"
+_METADATA_KEY_VALUE = "value"
+_SSH_KEYS_NAME = "sshKeys"
+_ITEMS = "items"
+_METADATA = "metadata"
BASE_DISK_ARGS = {
"type": "PERSISTENT",
@@ -1127,10 +1132,10 @@
body["scheduling"] = {"onHostMaintenance": "terminate"}
if metadata:
metadata_list = [{
- "key": key,
- "value": val
+ _METADATA_KEY: key,
+ _METADATA_KEY_VALUE: val
} for key, val in metadata.iteritems()]
- body["metadata"] = {"items": metadata_list}
+ body[_METADATA] = {_ITEMS: metadata_list}
logger.info("Creating instance: project %s, zone %s, body:%s",
self._project, zone, body)
api = self.service.instances().insert(
@@ -1364,63 +1369,53 @@
external_ip = instance["networkInterfaces"][0]["accessConfigs"][0]["natIP"]
return IP(internal=internal_ip, external=external_ip)
- def SetCommonInstanceMetadata(self, body):
- """Set project-wide metadata.
+ @utils.TimeExecute(function_description="Updating instance metadata: ")
+ def SetInstanceMetadata(self, zone, instance, body):
+ """Set instance metadata.
Args:
- body: Metadata body.
+ zone: String, name of zone.
+ instance: String, representing instance name.
+ body: Dict, Metadata body.
metdata is in the following format.
{
"kind": "compute#metadata",
"fingerprint": "a-23icsyx4E=",
"items": [
{
- "key": "google-compute-default-region",
- "value": "us-central1"
+ "key": "sshKeys",
+ "value": "key"
}, ...
]
}
"""
- api = self.service.projects().setCommonInstanceMetadata(
- project=self._project, body=body)
+ api = self.service.instances().setMetadata(
+ project=self._project, zone=zone, instance=instance, body=body)
operation = self.Execute(api)
- self.WaitOnOperation(operation, operation_scope=OperationScope.GLOBAL)
+ self.WaitOnOperation(
+ operation, operation_scope=OperationScope.ZONE, scope_name=zone)
- def AddSshRsa(self, user, ssh_rsa_path):
- """Add the public rsa key to the project's metadata.
+ def AddSshRsaInstanceMetadata(self, zone, user, ssh_rsa_path, instance):
+ """Add the public rsa key to the instance's metadata.
- Compute engine instances that are created after will
- by default contain the key.
+ Confirm that the instance has this public key in the instance's
+ metadata, if not we will add this public key.
Args:
- user: the name of the user which the key belongs to.
- ssh_rsa_path: The absolute path to public rsa key.
+ zone: String, name of zone.
+ user: String, name of the user which the key belongs to.
+ ssh_rsa_path: String, The absolute path to public rsa key.
+ instance: String, representing instance name.
"""
- if not os.path.exists(ssh_rsa_path):
- raise errors.DriverError(
- "RSA file %s does not exist." % ssh_rsa_path)
-
- logger.info("Adding ssh rsa key from %s to project %s for user: %s",
- ssh_rsa_path, self._project, user)
- project = self.GetProject()
- with open(ssh_rsa_path) as f:
- rsa = f.read()
- rsa = rsa.strip() if rsa else rsa
- utils.VerifyRsaPubKey(rsa)
- metadata = project["commonInstanceMetadata"]
- for item in metadata.setdefault("items", []):
- if item["key"] == "sshKeys":
- sshkey_item = item
- break
- else:
- sshkey_item = {"key": "sshKeys", "value": ""}
- metadata["items"].append(sshkey_item)
-
+ ssh_rsa_path = os.path.expanduser(ssh_rsa_path)
+ rsa = GetRsaKey(ssh_rsa_path)
entry = "%s:%s" % (user, rsa)
logger.debug("New RSA entry: %s", entry)
- sshkey_item["value"] = "\n".join([sshkey_item["value"].strip(),
- entry]).strip()
- self.SetCommonInstanceMetadata(metadata)
+
+ gce_instance = self.GetInstance(instance, zone)
+ metadata = gce_instance.get(_METADATA)
+ if RsaNotInMetadata(metadata, entry):
+ self.UpdateRsaInMetadata(zone, instance, metadata, entry)
def CheckAccess(self):
"""Check if the user has read access to the cloud project.
@@ -1443,3 +1438,88 @@
return False
raise
return True
+
+ def UpdateRsaInMetadata(self, zone, instance, metadata, entry):
+ """Update ssh public key to sshKeys's value in this metadata.
+
+ Args:
+ zone: String, name of zone.
+ instance: String, representing instance name.
+ metadata: Dict, maps a metadata name to its value.
+ entry: String, ssh public key.
+ """
+ ssh_key_item = GetSshKeyFromMetadata(metadata)
+ if ssh_key_item:
+ # The ssh key exists in the metadata so update the reference to it
+ # in the metadata. There may not be an actual ssh key value so
+ # that's why we filter for None to avoid an empty line in front.
+ ssh_key_item[_METADATA_KEY_VALUE] = "\n".join(
+ filter(None, [ssh_key_item[_METADATA_KEY_VALUE], entry]))
+ else:
+ # Since there is no ssh key item in the metadata, we need to add it in.
+ ssh_key_item = {_METADATA_KEY: _SSH_KEYS_NAME,
+ _METADATA_KEY_VALUE: entry}
+ metadata[_ITEMS].append(ssh_key_item)
+ utils.PrintColorString(
+ "Ssh public key doesn't exist in the instance(%s), adding it."
+ % instance, utils.TextColors.WARNING)
+ self.SetInstanceMetadata(zone, instance, metadata)
+
+
+def RsaNotInMetadata(metadata, entry):
+ """Check ssh public key exist in sshKeys's value.
+
+ Args:
+ metadata: Dict, maps a metadata name to its value.
+ entry: String, ssh public key.
+
+ Returns:
+ Boolean. True if ssh public key doesn't exist in metadata.
+ """
+ for item in metadata.setdefault(_ITEMS, []):
+ if item[_METADATA_KEY] == _SSH_KEYS_NAME:
+ if entry in item[_METADATA_KEY_VALUE]:
+ return False
+ return True
+
+
+def GetSshKeyFromMetadata(metadata):
+ """Get ssh key item from metadata.
+
+ Args:
+ metadata: Dict, maps a metadata name to its value.
+
+ Returns:
+ Dict of ssk_key_item in metadata, None if can't find the ssh key item
+ in metadata.
+ """
+ for item in metadata.setdefault(_ITEMS, []):
+ if item.get(_METADATA_KEY, '') == _SSH_KEYS_NAME:
+ return item
+ return None
+
+
+def GetRsaKey(ssh_rsa_path):
+ """Get rsa key from rsa path.
+
+ Args:
+ ssh_rsa_path: String, The absolute path to public rsa key.
+
+ Returns:
+ String, rsa key.
+
+ Raises:
+ errors.DriverError: RSA file does not exist.
+ """
+ ssh_rsa_path = os.path.expanduser(ssh_rsa_path)
+ if not os.path.exists(ssh_rsa_path):
+ raise errors.DriverError(
+ "RSA file %s does not exist." % ssh_rsa_path)
+
+ with open(ssh_rsa_path) as f:
+ rsa = f.read()
+ # The space must be removed here for string processing,
+ # if it is not string, it doesn't have a strip function.
+ rsa = rsa.strip() if rsa else rsa
+ utils.VerifyRsaPubKey(rsa)
+ return rsa
diff --git a/internal/lib/gcompute_client_test.py b/internal/lib/gcompute_client_test.py
index a34bfa2..f9ed0c7 100644
--- a/internal/lib/gcompute_client_test.py
+++ b/internal/lib/gcompute_client_test.py
@@ -57,6 +57,14 @@
OPERATION_NAME = "fake-op"
IMAGE_FINGERPRINT = "L_NWHuz7wTY="
GPU = "fancy-graphics"
+ SSHKEY = (
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
+ "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
+ "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
+ "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
+ "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
+ "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
+ "ApiihqNL1111 test@test1.org")
def setUp(self):
"""Set up test."""
@@ -1026,25 +1034,192 @@
self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
"172.22.22.23": None})
- def testAddSshRsa(self):
- """Test AddSshRsa.."""
+ def testRsaNotInMetadata(self):
+ """Test rsa not in metadata."""
fake_user = "fake_user"
- sshkey = (
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
- "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
- "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
- "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
- "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
- "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
- "ApiihqNL1111 test@test1.org")
- project = {
- "commonInstanceMetadata": {
+ fake_ssh_key = "fake_ssh"
+ metadata = {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ "key": "sshKeys",
+ "value": "%s:%s" % (fake_user, self.SSHKEY)
+ }
+ ]
+ }
+ # Test rsa doesn't exist in metadata.
+ new_entry = "%s:%s" % (fake_user, fake_ssh_key)
+ self.assertEqual(True, gcompute_client.RsaNotInMetadata(metadata, new_entry))
+
+ # Test rsa exists in metadata.
+ exist_entry = "%s:%s" %(fake_user, self.SSHKEY)
+ self.assertEqual(False, gcompute_client.RsaNotInMetadata(metadata, exist_entry))
+
+ def testGetSshKeyFromMetadata(self):
+ """Test get ssh key from metadata."""
+ fake_user = "fake_user"
+ metadata_key_exist_value_is_empty = {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ "key": "sshKeys",
+ "value": ""
+ }
+ ]
+ }
+ metadata_key_exist = {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ "key": "sshKeys",
+ "value": "%s:%s" % (fake_user, self.SSHKEY)
+ }
+ ]
+ }
+ metadata_key_not_exist = {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ }
+ ]
+ }
+ expected_key_exist_value_is_empty = {
+ "key": "sshKeys",
+ "value": ""
+ }
+ expected_key_exist = {
+ "key": "sshKeys",
+ "value": "%s:%s" % (fake_user, self.SSHKEY)
+ }
+ self.assertEqual(expected_key_exist_value_is_empty,
+ gcompute_client.GetSshKeyFromMetadata(metadata_key_exist_value_is_empty))
+ self.assertEqual(expected_key_exist,
+ gcompute_client.GetSshKeyFromMetadata(metadata_key_exist))
+ self.assertEqual(None,
+ gcompute_client.GetSshKeyFromMetadata(metadata_key_not_exist))
+
+
+ def testGetRsaKeyPathExistsFalse(self):
+ """Test the rsa key path not exists."""
+ fake_ssh_rsa_path = "/path/to/test_rsa.pub"
+ self.Patch(os.path, "exists", return_value=False)
+ self.assertRaisesRegexp(errors.DriverError,
+ "RSA file %s does not exist." % fake_ssh_rsa_path,
+ gcompute_client.GetRsaKey,
+ ssh_rsa_path=fake_ssh_rsa_path)
+
+ def testGetRsaKey(self):
+ """Test get the rsa key."""
+ fake_ssh_rsa_path = "/path/to/test_rsa.pub"
+ self.Patch(os.path, "exists", return_value=True)
+ m = mock.mock_open(read_data=self.SSHKEY)
+ with mock.patch("__builtin__.open", m):
+ result = gcompute_client.GetRsaKey(fake_ssh_rsa_path)
+ self.assertEqual(self.SSHKEY, result)
+
+ def testUpdateRsaInMetadata(self):
+ """Test update rsa in metadata."""
+ fake_ssh_key = "fake_ssh"
+ fake_metadata_sshkeys_not_exist = {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ "key": "not_sshKeys",
+ "value": ""
+ }
+ ]
+ }
+ new_entry = "new_user:%s" % fake_ssh_key
+ expected = {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ "key": "not_sshKeys",
+ "value": ""
+ },
+ {
+ "key": "sshKeys",
+ "value": new_entry
+ }
+ ]
+ }
+ self.Patch(os.path, "exists", return_value=True)
+ self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
+ resource_mock = mock.MagicMock()
+ self.compute_client.SetInstanceMetadata = mock.MagicMock(
+ return_value=resource_mock)
+ # Test the key item not exists in the metadata.
+ self.compute_client.UpdateRsaInMetadata(
+ "fake_zone",
+ "fake_instance",
+ fake_metadata_sshkeys_not_exist,
+ new_entry)
+ self.compute_client.SetInstanceMetadata.assert_called_with(
+ "fake_zone",
+ "fake_instance",
+ expected)
+
+ # Test the key item exists in the metadata.
+ fake_metadata_ssh_keys_exists = {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ "key": "sshKeys",
+ "value": "old_user:%s" % self.SSHKEY
+ }
+ ]
+ }
+ expected_ssh_keys_exists = {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ "key": "sshKeys",
+ "value": "old_user:%s\n%s" % (self.SSHKEY, new_entry)
+ }
+ ]
+ }
+
+ self.compute_client.UpdateRsaInMetadata(
+ "fake_zone",
+ "fake_instance",
+ fake_metadata_ssh_keys_exists,
+ new_entry)
+ self.compute_client.SetInstanceMetadata.assert_called_with(
+ "fake_zone",
+ "fake_instance",
+ expected_ssh_keys_exists)
+
+ def testAddSshRsaToInstance(self):
+ """Test add ssh rsa key to instance."""
+ fake_user = "fake_user"
+ instance_metadata_key_not_exist = {
+ "metadata": {
"kind": "compute#metadata",
"fingerprint": "a-23icsyx4E=",
"items": [
{
"key": "sshKeys",
- "value": "user:key"
+ "value": ""
+ }
+ ]
+ }
+ }
+ instance_metadata_key_exist = {
+ "metadata": {
+ "kind": "compute#metadata",
+ "fingerprint": "a-23icsyx4E=",
+ "items": [
+ {
+ "key": "sshKeys",
+ "value": "%s:%s" % (fake_user, self.SSHKEY)
}
]
}
@@ -1055,51 +1230,47 @@
"items": [
{
"key": "sshKeys",
- "value": "user:key\n%s:%s" % (fake_user, sshkey)
+ "value": "%s:%s" % (fake_user, self.SSHKEY)
}
]
}
self.Patch(os.path, "exists", return_value=True)
- m = mock.mock_open(read_data=sshkey)
+ m = mock.mock_open(read_data=self.SSHKEY)
self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
- self.Patch(
- gcompute_client.ComputeClient, "GetProject", return_value=project)
resource_mock = mock.MagicMock()
- self.compute_client._service.projects = mock.MagicMock(
+ self.compute_client._service.instances = mock.MagicMock(
return_value=resource_mock)
- resource_mock.setCommonInstanceMetadata = mock.MagicMock()
+ resource_mock.setMetadata = mock.MagicMock()
- with mock.patch("__builtin__.open", m):
- self.compute_client.AddSshRsa(fake_user, "/path/to/test_rsa.pub")
- resource_mock.setCommonInstanceMetadata.assert_called_with(
- project=PROJECT, body=expected)
-
- def testAddSshRsaInvalidKey(self):
- """Test AddSshRsa.."""
- fake_user = "fake_user"
- sshkey = "ssh-rsa v2VOqkkf7RGL1111 test@test1.org"
- project = {
- "commonInstanceMetadata": {
- "kind": "compute#metadata",
- "fingerprint": "a-23icsyx4E=",
- "items": [
- {
- "key": "sshKeys",
- "value": "user:key"
- }
- ]
- }
- }
- self.Patch(os.path, "exists", return_value=True)
- m = mock.mock_open(read_data=sshkey)
- self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
+ # Test the key not exists in the metadata.
self.Patch(
- gcompute_client.ComputeClient, "GetProject", return_value=project)
+ gcompute_client.ComputeClient, "GetInstance",
+ return_value=instance_metadata_key_not_exist)
with mock.patch("__builtin__.open", m):
- self.assertRaisesRegexp(errors.DriverError, "rsa key is invalid:*",
- self.compute_client.AddSshRsa, fake_user,
- "/path/to/test_rsa.pub")
+ self.compute_client.AddSshRsaInstanceMetadata(
+ "fake_zone",
+ fake_user,
+ "/path/to/test_rsa.pub",
+ "fake_instance")
+ resource_mock.setMetadata.assert_called_with(
+ project=PROJECT,
+ zone="fake_zone",
+ instance="fake_instance",
+ body=expected)
+
+ # Test the key already exists in the metadata.
+ resource_mock.setMetadata.call_count = 0
+ self.Patch(
+ gcompute_client.ComputeClient, "GetInstance",
+ return_value=instance_metadata_key_exist)
+ with mock.patch("__builtin__.open", m):
+ self.compute_client.AddSshRsaInstanceMetadata(
+ "fake_zone",
+ fake_user,
+ "/path/to/test_rsa.pub",
+ "fake_instance")
+ resource_mock.setMetadata.assert_not_called()
@mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
def testDeleteDisks(self, mock_wait):
diff --git a/list/instance.py b/list/instance.py
index d726839..4cc64a7 100644
--- a/list/instance.py
+++ b/list/instance.py
@@ -50,7 +50,7 @@
r"(.+%s)")
_RE_TIMEZONE = re.compile(r"^(?P<time>[0-9\-\.:T]*)(?P<timezone>[+-]\d+:\d+)$")
-_COMMAND_PS_LAUNCH_CVD = ["ps", "-eo", "lstart,cmd"]
+_COMMAND_PS_LAUNCH_CVD = ["ps", "-wweo", "lstart,cmd"]
_RE_LAUNCH_CVD = re.compile(r"(?P<date_str>^[^/]+)(.*launch_cvd --daemon )+"
r"((.*\s*-cpus\s)(?P<cpu>\d+))?"
r"((.*\s*-x_res\s)(?P<x_res>\d+))?"
diff --git a/public/acloud_main.py b/public/acloud_main.py
index bb4da6c..25a23e0 100644
--- a/public/acloud_main.py
+++ b/public/acloud_main.py
@@ -48,7 +48,6 @@
from __future__ import print_function
import argparse
-import getpass
import logging
import platform
import sys
@@ -107,7 +106,6 @@
CMD_CREATE_CUTTLEFISH = "create_cf"
CMD_CREATE_GOLDFISH = "create_gf"
CMD_CLEANUP = "cleanup"
-CMD_SSHKEY = "project_sshkey"
# pylint: disable=too-many-statements
@@ -209,26 +207,6 @@
"images that are older than |expiration_mins|.")
subparser_list.append(cleanup_parser)
- # Command "project_sshkey"
- sshkey_parser = subparsers.add_parser(CMD_SSHKEY)
- sshkey_parser.required = False
- sshkey_parser.set_defaults(which=CMD_SSHKEY)
- sshkey_parser.add_argument(
- "--user",
- type=str,
- dest="user",
- default=getpass.getuser(),
- help="The user name which the sshkey belongs to, default to: %s." %
- getpass.getuser())
- sshkey_parser.add_argument(
- "--ssh_rsa_path",
- type=str,
- dest="ssh_rsa_path",
- required=True,
- help="Absolute path to the file that contains the public rsa key "
- "that will be added as project-wide ssh key.")
- subparser_list.append(sshkey_parser)
-
# Command "create"
subparser_list.append(create_args.GetCreateArgParser(subparsers))
@@ -399,8 +377,6 @@
list_instances.Run(args)
elif args.which == reconnect_args.CMD_RECONNECT:
reconnect.Run(args)
- elif args.which == CMD_SSHKEY:
- report = device_driver.AddSshRsa(cfg, args.user, args.ssh_rsa_path)
elif args.which == setup_args.CMD_SETUP:
setup.Run(args)
else:
diff --git a/public/data/default.config b/public/data/default.config
index ecb0e01..53d114f 100644
--- a/public/data/default.config
+++ b/public/data/default.config
@@ -74,7 +74,7 @@
common_hw_property_map {
key: "tv"
- value: "cpu:2,resolution:1080x1920,dpi:320,memory:4g,disk:4g"
+ value: "cpu:2,resolution:1280x720,dpi:213,memory:2g,disk:4g"
}
# Device resolution
diff --git a/public/device_driver.py b/public/device_driver.py
index 3fabc0c..4d54a98 100755
--- a/public/device_driver.py
+++ b/public/device_driver.py
@@ -575,30 +575,6 @@
return r
-def AddSshRsa(cfg, user, ssh_rsa_path):
- """Add public ssh rsa key to the project.
-
- Args:
- cfg: An AcloudConfig instance.
- user: the name of the user which the key belongs to.
- ssh_rsa_path: The absolute path to public rsa key.
-
- Returns:
- A Report instance.
- """
- r = report.Report(command="sshkey")
- try:
- credentials = auth.CreateCredentials(cfg)
- compute_client = android_compute_client.AndroidComputeClient(
- cfg, credentials)
- compute_client.AddSshRsa(user, ssh_rsa_path)
- r.SetStatus(report.Status.SUCCESS)
- except errors.DriverError as e:
- r.AddError(str(e))
- r.SetStatus(report.Status.FAIL)
- return r
-
-
def CheckAccess(cfg):
"""Check if user has access.
diff --git a/reconnect/reconnect.py b/reconnect/reconnect.py
index 413b146..27f6280 100644
--- a/reconnect/reconnect.py
+++ b/reconnect/reconnect.py
@@ -27,6 +27,8 @@
from acloud.delete import delete
from acloud.internal import constants
+from acloud.internal.lib import auth
+from acloud.internal.lib import android_compute_client
from acloud.internal.lib import utils
from acloud.internal.lib.adb_tools import AdbTools
from acloud.list import list as list_instance
@@ -68,6 +70,26 @@
utils.LaunchVncClient(vnc_port)
+def AddPublicSshRsaToInstance(cfg, user, instance_name):
+ """Add the public rsa key to the instance's metadata.
+
+ When the public key doesn't exist in the metadata, it will add it.
+
+ Args:
+ cfg: An AcloudConfig instance.
+ user: String, the ssh username to access instance.
+ instance_name: String, instance name.
+ """
+ credentials = auth.CreateCredentials(cfg)
+ compute_client = android_compute_client.AndroidComputeClient(
+ cfg, credentials)
+ compute_client.AddSshRsaInstanceMetadata(
+ cfg.zone,
+ user,
+ cfg.ssh_public_key_path,
+ instance_name)
+
+
def ReconnectInstance(ssh_private_key_path, instance):
"""Reconnect adb/vnc/ssh to the specified instance.
@@ -112,4 +134,5 @@
if not instances_to_reconnect:
instances_to_reconnect = list_instance.ChooseInstances(cfg, args.all)
for instance in instances_to_reconnect:
+ AddPublicSshRsaToInstance(cfg, getpass.getuser(), instance.name)
ReconnectInstance(cfg.ssh_private_key_path, instance)