1*9c5db199SXin Li# Copyright 2015 The Chromium OS Authors. All rights reserved. 2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 3*9c5db199SXin Li# found in the LICENSE file. 4*9c5db199SXin Li 5*9c5db199SXin Liimport logging 6*9c5db199SXin Liimport os 7*9c5db199SXin Li 8*9c5db199SXin Liimport common 9*9c5db199SXin Lifrom autotest_lib.utils.frozen_chromite.lib import gce 10*9c5db199SXin Li 11*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 12*9c5db199SXin Lifrom autotest_lib.client.common_lib import lsbrelease_utils 13*9c5db199SXin Lifrom autotest_lib.client.cros import constants as client_constants 14*9c5db199SXin Lifrom autotest_lib.server.hosts import abstract_ssh 15*9c5db199SXin Li 16*9c5db199SXin LiSSH_KEYS_METADATA_KEY = "sshKeys" 17*9c5db199SXin LiTMP_DIR='/usr/local/tmp' 18*9c5db199SXin Li 19*9c5db199SXin Lidef extract_arguments(args_dict): 20*9c5db199SXin Li """Extract GCE-specific arguments from arguments dictionary. 21*9c5db199SXin Li 22*9c5db199SXin Li @param args_dict: dictionary of all arguments supplied to the test. 23*9c5db199SXin Li """ 24*9c5db199SXin Li 25*9c5db199SXin Li return {k: v for k, v in args_dict.items() 26*9c5db199SXin Li if k in ('gce_project', 'gce_instance', 27*9c5db199SXin Li 'gce_zone', 'gce_key_file')} 28*9c5db199SXin Li 29*9c5db199SXin Li 30*9c5db199SXin Liclass GceHost(abstract_ssh.AbstractSSHHost): 31*9c5db199SXin Li """GCE-specific subclass of Host.""" 32*9c5db199SXin Li 33*9c5db199SXin Li def _initialize(self, hostname, gce_args=None, 34*9c5db199SXin Li *args, **dargs): 35*9c5db199SXin Li """Initializes this instance of GceHost. 36*9c5db199SXin Li 37*9c5db199SXin Li @param hostname: the hostnname to be passed down to AbstractSSHHost. 38*9c5db199SXin Li @param gce_args: GCE-specific arguments extracted using 39*9c5db199SXin Li extract_arguments(). 40*9c5db199SXin Li """ 41*9c5db199SXin Li super(GceHost, self)._initialize(hostname=hostname, 42*9c5db199SXin Li *args, **dargs) 43*9c5db199SXin Li 44*9c5db199SXin Li if gce_args: 45*9c5db199SXin Li self._gce_project = gce_args['gce_project'] 46*9c5db199SXin Li self._gce_zone = gce_args['gce_zone'] 47*9c5db199SXin Li self._gce_instance = gce_args['gce_instance'] 48*9c5db199SXin Li self._gce_key_file = gce_args['gce_key_file'] 49*9c5db199SXin Li else: 50*9c5db199SXin Li logging.warning("No GCE flags provided, calls to GCE API will fail") 51*9c5db199SXin Li return 52*9c5db199SXin Li 53*9c5db199SXin Li self.gce = gce.GceContext.ForServiceAccountThreadSafe( 54*9c5db199SXin Li self._gce_project, self._gce_zone, self._gce_key_file) 55*9c5db199SXin Li 56*9c5db199SXin Li @staticmethod 57*9c5db199SXin Li def check_host(host, timeout=10): 58*9c5db199SXin Li """ 59*9c5db199SXin Li Check if the given host is running on GCE. 60*9c5db199SXin Li 61*9c5db199SXin Li @param host: An ssh host representing a device. 62*9c5db199SXin Li @param timeout: The timeout for the run command. 63*9c5db199SXin Li 64*9c5db199SXin Li @return: True if the host is running on GCE. 65*9c5db199SXin Li """ 66*9c5db199SXin Li try: 67*9c5db199SXin Li result = host.run( 68*9c5db199SXin Li 'grep CHROMEOS_RELEASE_BOARD /etc/lsb-release', 69*9c5db199SXin Li timeout=timeout) 70*9c5db199SXin Li return lsbrelease_utils.is_gce_board( 71*9c5db199SXin Li lsb_release_content=result.stdout) 72*9c5db199SXin Li except (error.AutoservRunError, error.AutoservSSHTimeout): 73*9c5db199SXin Li return False 74*9c5db199SXin Li 75*9c5db199SXin Li def _modify_ssh_keys(self, to_add, to_remove): 76*9c5db199SXin Li """Modifies the list of ssh keys. 77*9c5db199SXin Li 78*9c5db199SXin Li @param username: user name to add. 79*9c5db199SXin Li @param to_add: a list of new enties. 80*9c5db199SXin Li @param to_remove: a list of enties to be removed. 81*9c5db199SXin Li """ 82*9c5db199SXin Li keys = self.gce.GetCommonInstanceMetadata( 83*9c5db199SXin Li SSH_KEYS_METADATA_KEY) or '' 84*9c5db199SXin Li key_set = set(keys.split('\n')) 85*9c5db199SXin Li new_key_set = (key_set | set(to_add)) - set(to_remove) 86*9c5db199SXin Li if key_set != new_key_set: 87*9c5db199SXin Li self.gce.SetCommonInstanceMetadata( 88*9c5db199SXin Li SSH_KEYS_METADATA_KEY, 89*9c5db199SXin Li '\n'.join(list(new_key_set))) 90*9c5db199SXin Li 91*9c5db199SXin Li def add_ssh_key(self, username, ssh_key): 92*9c5db199SXin Li """Adds a new SSH key in GCE metadata. 93*9c5db199SXin Li 94*9c5db199SXin Li @param username: user name to add. 95*9c5db199SXin Li @param ssh_key: the key to add. 96*9c5db199SXin Li """ 97*9c5db199SXin Li self._modify_ssh_keys(['%s:%s' % (username, ssh_key)], []) 98*9c5db199SXin Li 99*9c5db199SXin Li 100*9c5db199SXin Li def del_ssh_key(self, username, ssh_key): 101*9c5db199SXin Li """Deletes the given SSH key from GCE metadata 102*9c5db199SXin Li 103*9c5db199SXin Li @param username: user name to delete. 104*9c5db199SXin Li @param ssh_key: the key to delete. 105*9c5db199SXin Li """ 106*9c5db199SXin Li self._modify_ssh_keys([], ['%s:%s' % (username, ssh_key)]) 107*9c5db199SXin Li 108*9c5db199SXin Li 109*9c5db199SXin Li def get_release_version(self): 110*9c5db199SXin Li """Get the value of attribute CHROMEOS_RELEASE_VERSION from lsb-release. 111*9c5db199SXin Li 112*9c5db199SXin Li @returns The version string in lsb-release, under attribute 113*9c5db199SXin Li CHROMEOS_RELEASE_VERSION. 114*9c5db199SXin Li """ 115*9c5db199SXin Li lsb_release_content = self.run( 116*9c5db199SXin Li 'cat "%s"' % client_constants.LSB_RELEASE).stdout.strip() 117*9c5db199SXin Li return lsbrelease_utils.get_chromeos_release_version( 118*9c5db199SXin Li lsb_release_content=lsb_release_content) 119*9c5db199SXin Li 120*9c5db199SXin Li def get_tmp_dir(self, parent=TMP_DIR): 121*9c5db199SXin Li """Return the pathname of a directory on the host suitable 122*9c5db199SXin Li for temporary file storage. 123*9c5db199SXin Li 124*9c5db199SXin Li The directory and its content will be deleted automatically 125*9c5db199SXin Li on the destruction of the Host object that was used to obtain 126*9c5db199SXin Li it. 127*9c5db199SXin Li 128*9c5db199SXin Li @param parent: Parent directory of the returned tmp dir. 129*9c5db199SXin Li 130*9c5db199SXin Li @returns a path to the tmp directory on the host. 131*9c5db199SXin Li """ 132*9c5db199SXin Li if not parent.startswith(TMP_DIR): 133*9c5db199SXin Li parent = os.path.join(TMP_DIR, parent.lstrip(os.path.sep)) 134*9c5db199SXin Li self.run("mkdir -p %s" % parent) 135*9c5db199SXin Li template = os.path.join(parent, 'autoserv-XXXXXX') 136*9c5db199SXin Li dir_name = self.run_output("mktemp -d %s" % template) 137*9c5db199SXin Li self.tmp_dirs.append(dir_name) 138*9c5db199SXin Li return dir_name 139*9c5db199SXin Li 140*9c5db199SXin Li 141*9c5db199SXin Li def set_instance_metadata(self, key, value): 142*9c5db199SXin Li """Sets a single metadata value on the DUT instance. 143*9c5db199SXin Li 144*9c5db199SXin Li @param key: Metadata key to be set. 145*9c5db199SXin Li @param value: New value, or None if the given key should be removed. 146*9c5db199SXin Li """ 147*9c5db199SXin Li self.gce.SetInstanceMetadata(self._gce_instance, key, value) 148*9c5db199SXin Li 149*9c5db199SXin Li def stop(self): 150*9c5db199SXin Li """Stops the DUT instance 151*9c5db199SXin Li """ 152*9c5db199SXin Li self.gce.StopInstance(self._gce_instance) 153*9c5db199SXin Li 154*9c5db199SXin Li def start(self): 155*9c5db199SXin Li """Starts the DUT instance 156*9c5db199SXin Li """ 157*9c5db199SXin Li self.gce.StartInstance(self._gce_instance) 158