xref: /aosp_15_r20/external/autotest/server/hosts/gce_host.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
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