blob: e6b4dc234309ba50dda329653352e2b42f407ada [file] [log] [blame]
Sam Chiu81bdc652018-06-29 18:45:08 +08001#!/usr/bin/env python
2#
3# Copyright 2018 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16r"""host setup runner
17
18A setup sub task runner to support setting up the local host for AVD local
19instance.
20"""
21
22from __future__ import print_function
23
24import getpass
Sam Chiu81bdc652018-06-29 18:45:08 +080025import logging
herbertxue975b8872020-02-12 14:41:41 +080026import os
27import shutil
Sam Chiuaa703b62019-10-04 19:47:43 +080028import sys
herbertxue975b8872020-02-12 14:41:41 +080029import tempfile
Sam Chiu81bdc652018-06-29 18:45:08 +080030
31from acloud.internal import constants
32from acloud.internal.lib import utils
33from acloud.setup import base_task_runner
34from acloud.setup import setup_common
35
herbertxue1512f8a2019-06-27 13:56:23 +080036
Sam Chiu81bdc652018-06-29 18:45:08 +080037logger = logging.getLogger(__name__)
38
herbertxue975b8872020-02-12 14:41:41 +080039_CF_COMMOM_FOLDER = "cf-common"
chojoyce345c2c02021-08-12 18:24:05 +080040
Sam Chiu81bdc652018-06-29 18:45:08 +080041_LIST_OF_MODULES = ["kvm_intel", "kvm"]
Kevin Chengf756bbd2018-10-11 13:50:00 -070042_UPDATE_APT_GET_CMD = "sudo apt-get update"
herbertxue975b8872020-02-12 14:41:41 +080043_INSTALL_CUTTLEFISH_COMMOM_CMD = [
44 "git clone https://github.com/google/android-cuttlefish.git {git_folder}",
45 "cd {git_folder}",
46 "yes | sudo mk-build-deps -i -r -B",
47 "dpkg-buildpackage -uc -us",
48 "sudo apt-get install -y -f ../cuttlefish-common_*_amd64.deb"]
chojoyce3c5ad5c2021-07-05 10:44:14 +080049_MKCERT_URL = "https://github.com/FiloSottile/mkcert"
50_MKCERT_VERSION = "v1.4.3"
51_MKCERT_INSTALL_PATH = os.path.join(os.path.expanduser("~"), ".config",
52 constants.TOOL_NAME, "mkcert")
53_MKCERT_CAROOT_CMD = "%s/mkcert -install" % _MKCERT_INSTALL_PATH
54_MKCERT_DOWNLOAD_CMD = ("wget -O %(mkcert_install_path)s/mkcert "
55 "%(mkcert_url)s/releases/download/"
56 "%(mkcert_ver)s/mkcert-%(mkcert_ver)s-linux-amd64" %
57 {"mkcert_install_path": _MKCERT_INSTALL_PATH,
58 "mkcert_url": _MKCERT_URL,
59 "mkcert_ver": _MKCERT_VERSION})
Sam Chiu81bdc652018-06-29 18:45:08 +080060
61
Kevin Chengeb997272019-06-05 14:53:18 -070062class BasePkgInstaller(base_task_runner.BaseTaskRunner):
63 """Subtask base runner class for installing packages."""
Sam Chiu81bdc652018-06-29 18:45:08 +080064
Kevin Chengeb997272019-06-05 14:53:18 -070065 # List of packages for child classes to override.
66 PACKAGES = []
Sam Chiu81bdc652018-06-29 18:45:08 +080067
68 def ShouldRun(self):
69 """Check if required packages are all installed.
70
71 Returns:
72 Boolean, True if required packages are not installed.
73 """
Sam Chiu6c738d62018-12-04 10:29:02 +080074 if not utils.IsSupportedPlatform():
Sam Chiu81bdc652018-06-29 18:45:08 +080075 return False
76
77 # Any required package is not installed or not up-to-date will need to
78 # run installation task.
Kevin Chengeb997272019-06-05 14:53:18 -070079 for pkg_name in self.PACKAGES:
Sam Chiu81bdc652018-06-29 18:45:08 +080080 if not setup_common.PackageInstalled(pkg_name):
81 return True
82
83 return False
84
85 def _Run(self):
Kevin Chengeb997272019-06-05 14:53:18 -070086 """Install specified packages."""
Sam Chiuaa703b62019-10-04 19:47:43 +080087 cmd = "\n".join(
88 [setup_common.PKG_INSTALL_CMD % pkg
89 for pkg in self.PACKAGES
90 if not setup_common.PackageInstalled(pkg)])
Sam Chiu81bdc652018-06-29 18:45:08 +080091
Sam Chiuaa703b62019-10-04 19:47:43 +080092 if not utils.GetUserAnswerYes("\nStart to install package(s):\n%s"
herbertxue97af4a62020-11-05 17:12:56 +080093 "\nEnter 'y' to continue, otherwise N or "
94 "enter to exit: " % cmd):
Sam Chiuaa703b62019-10-04 19:47:43 +080095 sys.exit(constants.EXIT_BY_USER)
Sam Chiu81bdc652018-06-29 18:45:08 +080096
Kevin Chengf756bbd2018-10-11 13:50:00 -070097 setup_common.CheckCmdOutput(_UPDATE_APT_GET_CMD, shell=True)
Kevin Chengeb997272019-06-05 14:53:18 -070098 for pkg in self.PACKAGES:
Sam Chiu81bdc652018-06-29 18:45:08 +080099 setup_common.InstallPackage(pkg)
100
Kevin Chengeb997272019-06-05 14:53:18 -0700101 logger.info("All package(s) installed now.")
102
103
104class AvdPkgInstaller(BasePkgInstaller):
105 """Subtask runner class for installing packages for local instances."""
106
107 WELCOME_MESSAGE_TITLE = ("Install required packages for host setup for "
108 "local instances")
109 WELCOME_MESSAGE = ("This step will walk you through the required packages "
110 "installation for running Android cuttlefish devices "
111 "on your host.")
chojoyce8faf8852021-07-12 12:26:28 +0800112 PACKAGES = constants.AVD_REQUIRED_PKGS
Kevin Chengeb997272019-06-05 14:53:18 -0700113
114
115class HostBasePkgInstaller(BasePkgInstaller):
116 """Subtask runner class for installing base host packages."""
117
118 WELCOME_MESSAGE_TITLE = "Install base packages on the host"
119 WELCOME_MESSAGE = ("This step will walk you through the base packages "
120 "installation for your host.")
chojoyce8faf8852021-07-12 12:26:28 +0800121 PACKAGES = constants.BASE_REQUIRED_PKGS
Sam Chiu81bdc652018-06-29 18:45:08 +0800122
123
herbertxue975b8872020-02-12 14:41:41 +0800124class CuttlefishCommonPkgInstaller(base_task_runner.BaseTaskRunner):
125 """Subtask base runner class for installing cuttlefish-common."""
126
127 WELCOME_MESSAGE_TITLE = "Install cuttlefish-common packages on the host"
128 WELCOME_MESSAGE = ("This step will walk you through the cuttlefish-common "
129 "packages installation for your host.")
130
131 def ShouldRun(self):
132 """Check if cuttlefish-common package is installed.
133
134 Returns:
135 Boolean, True if cuttlefish-common is not installed.
136 """
137 if not utils.IsSupportedPlatform():
138 return False
139
140 # Any required package is not installed or not up-to-date will need to
141 # run installation task.
chojoyce8faf8852021-07-12 12:26:28 +0800142 if not setup_common.PackageInstalled(constants.CUTTLEFISH_COMMOM_PKG):
herbertxue975b8872020-02-12 14:41:41 +0800143 return True
144 return False
145
146 def _Run(self):
147 """Install cuttlefilsh-common packages."""
148 cf_common_path = os.path.join(tempfile.mkdtemp(), _CF_COMMOM_FOLDER)
149 logger.debug("cuttlefish-common path: %s", cf_common_path)
150 cmd = "\n".join(sub_cmd.format(git_folder=cf_common_path)
151 for sub_cmd in _INSTALL_CUTTLEFISH_COMMOM_CMD)
152
153 if not utils.GetUserAnswerYes("\nStart to install cuttlefish-common :\n%s"
herbertxue97af4a62020-11-05 17:12:56 +0800154 "\nEnter 'y' to continue, otherwise N or "
155 "enter to exit: " % cmd):
herbertxue975b8872020-02-12 14:41:41 +0800156 sys.exit(constants.EXIT_BY_USER)
157 try:
158 setup_common.CheckCmdOutput(cmd, shell=True)
159 finally:
160 shutil.rmtree(os.path.dirname(cf_common_path))
161 logger.info("Cuttlefish-common package installed now.")
162
chojoyce3c5ad5c2021-07-05 10:44:14 +0800163class MkcertPkgInstaller(base_task_runner.BaseTaskRunner):
164 """Subtask base runner class for installing mkcert."""
165
166 WELCOME_MESSAGE_TITLE = "Install mkcert package on the host"
167 WELCOME_MESSAGE = ("This step will walk you through the mkcert "
168 "package installation to your host for "
169 "assuring a secure localhost url connection "
170 "when launching an AVD over webrtc")
171
172 def ShouldRun(self):
173 """Check if mkcert package is installed.
174
175 Returns:
176 Boolean, True if mkcert is not installed.
177 """
178 if not utils.IsSupportedPlatform():
179 return False
180
181 if not os.path.exists(os.path.join(_MKCERT_INSTALL_PATH, "mkcert")):
182 return True
183 return False
184
185 def _Run(self):
186 """Install mkcert packages."""
chojoyce3c5ad5c2021-07-05 10:44:14 +0800187 if not utils.GetUserAnswerYes("\nStart to install mkcert :\n%s"
188 "\nEnter 'y' to continue, otherwise N or "
chojoyce21b280f2021-09-13 13:53:22 +0800189 "enter to exit: " % _MKCERT_DOWNLOAD_CMD):
chojoyce3c5ad5c2021-07-05 10:44:14 +0800190 sys.exit(constants.EXIT_BY_USER)
191
chojoyce49e7cb92021-08-04 12:01:32 +0800192 if not os.path.isdir(_MKCERT_INSTALL_PATH):
193 os.mkdir(_MKCERT_INSTALL_PATH)
chojoyce21b280f2021-09-13 13:53:22 +0800194 setup_common.CheckCmdOutput(_MKCERT_DOWNLOAD_CMD, shell=True)
chojoyce3c5ad5c2021-07-05 10:44:14 +0800195 utils.SetExecutable(os.path.join(_MKCERT_INSTALL_PATH, "mkcert"))
196 utils.CheckOutput(_MKCERT_CAROOT_CMD, shell=True)
197 logger.info("Mkcert package is installed at \"%s\" now.",
198 _MKCERT_INSTALL_PATH)
herbertxue975b8872020-02-12 14:41:41 +0800199
Sam Chiu81bdc652018-06-29 18:45:08 +0800200class CuttlefishHostSetup(base_task_runner.BaseTaskRunner):
201 """Subtask class that setup host for cuttlefish."""
202
203 WELCOME_MESSAGE_TITLE = "Host Enviornment Setup"
204 WELCOME_MESSAGE = (
205 "This step will help you to setup enviornment for running Android "
206 "cuttlefish devices on your host. That includes adding user to kvm "
207 "related groups and checking required linux modules."
208 )
209
210 def ShouldRun(self):
211 """Check host user groups and modules.
212
213 Returns:
214 Boolean: False if user is in all required groups and all modules
215 are reloaded.
216 """
Sam Chiu6c738d62018-12-04 10:29:02 +0800217 if not utils.IsSupportedPlatform():
Sam Chiu81bdc652018-06-29 18:45:08 +0800218 return False
219
herbertxue07293a32018-11-05 20:40:11 +0800220 return not (utils.CheckUserInGroups(constants.LIST_CF_USER_GROUPS)
Sam Chiu81bdc652018-06-29 18:45:08 +0800221 and self._CheckLoadedModules(_LIST_OF_MODULES))
222
223 @staticmethod
Sam Chiu81bdc652018-06-29 18:45:08 +0800224 def _CheckLoadedModules(module_list):
225 """Check if the modules are all in use.
226
227 Args:
228 module_list: The list of module name.
229 Returns:
230 True if all modules are in use.
231 """
232 logger.info("Checking if modules are loaded: %s", module_list)
233 lsmod_output = setup_common.CheckCmdOutput("lsmod", print_cmd=False)
234 current_modules = [r.split()[0] for r in lsmod_output.splitlines()]
235 all_modules_present = True
236 for module in module_list:
237 if module not in current_modules:
238 logger.info("missing module: %s", module)
239 all_modules_present = False
240 return all_modules_present
241
242 def _Run(self):
243 """Setup host environment for local cuttlefish instance support."""
244 # TODO: provide --uid args to let user use prefered username
245 username = getpass.getuser()
246 setup_cmds = [
247 "sudo rmmod kvm_intel",
248 "sudo rmmod kvm",
249 "sudo modprobe kvm",
250 "sudo modprobe kvm_intel"]
Sam Chiuafbc6582018-09-04 20:47:13 +0800251 for group in constants.LIST_CF_USER_GROUPS:
Sam Chiu81bdc652018-06-29 18:45:08 +0800252 setup_cmds.append("sudo usermod -aG %s % s" % (group, username))
253
254 print("Below commands will be run:")
255 for setup_cmd in setup_cmds:
256 print(setup_cmd)
257
258 if self._ConfirmContinue():
259 for setup_cmd in setup_cmds:
260 setup_common.CheckCmdOutput(setup_cmd, shell=True)
261 print("Host environment setup has done!")
262
263 @staticmethod
264 def _ConfirmContinue():
265 """Ask user if they want to continue.
266
267 Returns:
268 True if user answer yes.
269 """
270 answer_client = utils.InteractWithQuestion(
herbertxue97af4a62020-11-05 17:12:56 +0800271 "\nEnter 'y' to continue, otherwise N or enter to exit: ",
Sam Chiu81bdc652018-06-29 18:45:08 +0800272 utils.TextColors.WARNING)
273 return answer_client in constants.USER_ANSWER_YES