blob: 28cccc0dbf100a4e8d0d95e92750a6dbacfe50e1 [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
chojoyceb0817032022-01-12 18:29:36 +080035from acloud.setup import mkcert
Sam Chiu81bdc652018-06-29 18:45:08 +080036
herbertxue1512f8a2019-06-27 13:56:23 +080037
Sam Chiu81bdc652018-06-29 18:45:08 +080038logger = logging.getLogger(__name__)
39
herbertxue975b8872020-02-12 14:41:41 +080040_CF_COMMOM_FOLDER = "cf-common"
chojoyce345c2c02021-08-12 18:24:05 +080041
Sam Chiu81bdc652018-06-29 18:45:08 +080042_LIST_OF_MODULES = ["kvm_intel", "kvm"]
Kevin Chengf756bbd2018-10-11 13:50:00 -070043_UPDATE_APT_GET_CMD = "sudo apt-get update"
herbertxue975b8872020-02-12 14:41:41 +080044_INSTALL_CUTTLEFISH_COMMOM_CMD = [
45 "git clone https://github.com/google/android-cuttlefish.git {git_folder}",
46 "cd {git_folder}",
chojoyce1f78dee2022-02-09 17:50:24 +080047 "debuild -i -us -uc -b",
48 "sudo dpkg -i ../cuttlefish-common_*_*64.deb || sudo apt-get install -f"]
Sam Chiu81bdc652018-06-29 18:45:08 +080049
50
Kevin Chengeb997272019-06-05 14:53:18 -070051class BasePkgInstaller(base_task_runner.BaseTaskRunner):
52 """Subtask base runner class for installing packages."""
Sam Chiu81bdc652018-06-29 18:45:08 +080053
Kevin Chengeb997272019-06-05 14:53:18 -070054 # List of packages for child classes to override.
55 PACKAGES = []
Sam Chiu81bdc652018-06-29 18:45:08 +080056
57 def ShouldRun(self):
58 """Check if required packages are all installed.
59
60 Returns:
61 Boolean, True if required packages are not installed.
62 """
Sam Chiu6c738d62018-12-04 10:29:02 +080063 if not utils.IsSupportedPlatform():
Sam Chiu81bdc652018-06-29 18:45:08 +080064 return False
65
66 # Any required package is not installed or not up-to-date will need to
67 # run installation task.
Kevin Chengeb997272019-06-05 14:53:18 -070068 for pkg_name in self.PACKAGES:
Sam Chiu81bdc652018-06-29 18:45:08 +080069 if not setup_common.PackageInstalled(pkg_name):
70 return True
71
72 return False
73
74 def _Run(self):
Kevin Chengeb997272019-06-05 14:53:18 -070075 """Install specified packages."""
Sam Chiuaa703b62019-10-04 19:47:43 +080076 cmd = "\n".join(
77 [setup_common.PKG_INSTALL_CMD % pkg
78 for pkg in self.PACKAGES
79 if not setup_common.PackageInstalled(pkg)])
Sam Chiu81bdc652018-06-29 18:45:08 +080080
Sam Chiuaa703b62019-10-04 19:47:43 +080081 if not utils.GetUserAnswerYes("\nStart to install package(s):\n%s"
herbertxue97af4a62020-11-05 17:12:56 +080082 "\nEnter 'y' to continue, otherwise N or "
83 "enter to exit: " % cmd):
Sam Chiuaa703b62019-10-04 19:47:43 +080084 sys.exit(constants.EXIT_BY_USER)
Sam Chiu81bdc652018-06-29 18:45:08 +080085
Kevin Chengf756bbd2018-10-11 13:50:00 -070086 setup_common.CheckCmdOutput(_UPDATE_APT_GET_CMD, shell=True)
Kevin Chengeb997272019-06-05 14:53:18 -070087 for pkg in self.PACKAGES:
Sam Chiu81bdc652018-06-29 18:45:08 +080088 setup_common.InstallPackage(pkg)
89
Kevin Chengeb997272019-06-05 14:53:18 -070090 logger.info("All package(s) installed now.")
91
92
93class AvdPkgInstaller(BasePkgInstaller):
94 """Subtask runner class for installing packages for local instances."""
95
96 WELCOME_MESSAGE_TITLE = ("Install required packages for host setup for "
97 "local instances")
98 WELCOME_MESSAGE = ("This step will walk you through the required packages "
99 "installation for running Android cuttlefish devices "
100 "on your host.")
chojoyce8faf8852021-07-12 12:26:28 +0800101 PACKAGES = constants.AVD_REQUIRED_PKGS
Kevin Chengeb997272019-06-05 14:53:18 -0700102
103
104class HostBasePkgInstaller(BasePkgInstaller):
105 """Subtask runner class for installing base host packages."""
106
107 WELCOME_MESSAGE_TITLE = "Install base packages on the host"
108 WELCOME_MESSAGE = ("This step will walk you through the base packages "
109 "installation for your host.")
chojoyce8faf8852021-07-12 12:26:28 +0800110 PACKAGES = constants.BASE_REQUIRED_PKGS
Sam Chiu81bdc652018-06-29 18:45:08 +0800111
112
herbertxue975b8872020-02-12 14:41:41 +0800113class CuttlefishCommonPkgInstaller(base_task_runner.BaseTaskRunner):
114 """Subtask base runner class for installing cuttlefish-common."""
115
116 WELCOME_MESSAGE_TITLE = "Install cuttlefish-common packages on the host"
117 WELCOME_MESSAGE = ("This step will walk you through the cuttlefish-common "
118 "packages installation for your host.")
119
120 def ShouldRun(self):
121 """Check if cuttlefish-common package is installed.
122
123 Returns:
124 Boolean, True if cuttlefish-common is not installed.
125 """
126 if not utils.IsSupportedPlatform():
127 return False
128
129 # Any required package is not installed or not up-to-date will need to
130 # run installation task.
chojoyce8faf8852021-07-12 12:26:28 +0800131 if not setup_common.PackageInstalled(constants.CUTTLEFISH_COMMOM_PKG):
herbertxue975b8872020-02-12 14:41:41 +0800132 return True
133 return False
134
135 def _Run(self):
136 """Install cuttlefilsh-common packages."""
137 cf_common_path = os.path.join(tempfile.mkdtemp(), _CF_COMMOM_FOLDER)
138 logger.debug("cuttlefish-common path: %s", cf_common_path)
139 cmd = "\n".join(sub_cmd.format(git_folder=cf_common_path)
140 for sub_cmd in _INSTALL_CUTTLEFISH_COMMOM_CMD)
141
142 if not utils.GetUserAnswerYes("\nStart to install cuttlefish-common :\n%s"
herbertxue97af4a62020-11-05 17:12:56 +0800143 "\nEnter 'y' to continue, otherwise N or "
144 "enter to exit: " % cmd):
herbertxue975b8872020-02-12 14:41:41 +0800145 sys.exit(constants.EXIT_BY_USER)
146 try:
147 setup_common.CheckCmdOutput(cmd, shell=True)
148 finally:
149 shutil.rmtree(os.path.dirname(cf_common_path))
150 logger.info("Cuttlefish-common package installed now.")
151
chojoyce3c5ad5c2021-07-05 10:44:14 +0800152
chojoyceb0817032022-01-12 18:29:36 +0800153class LocalCAHostSetup(base_task_runner.BaseTaskRunner):
154 """Subtask class that setup host for setup local CA."""
155
156 WELCOME_MESSAGE_TITLE = "Local CA Host Environment Setup"
157 WELCOME_MESSAGE = ("This step will walk you through the local CA setup "
158 "to your host for assuring a secure localhost url "
159 "connection when launching an AVD over webrtc.")
chojoyce3c5ad5c2021-07-05 10:44:14 +0800160
161 def ShouldRun(self):
chojoyceb0817032022-01-12 18:29:36 +0800162 """Check if the local CA is setup or not.
chojoyce3c5ad5c2021-07-05 10:44:14 +0800163
164 Returns:
chojoyceb0817032022-01-12 18:29:36 +0800165 Boolean, True if local CA is ready.
chojoyce3c5ad5c2021-07-05 10:44:14 +0800166 """
167 if not utils.IsSupportedPlatform():
168 return False
169
chojoyceb0817032022-01-12 18:29:36 +0800170 return not mkcert.IsRootCAReady()
chojoyce3c5ad5c2021-07-05 10:44:14 +0800171
172 def _Run(self):
chojoyceb0817032022-01-12 18:29:36 +0800173 """Setup host environment for the local CA."""
174 if not utils.GetUserAnswerYes("\nStart to setup the local CA:\n"
chojoyce3c5ad5c2021-07-05 10:44:14 +0800175 "\nEnter 'y' to continue, otherwise N or "
chojoyceb0817032022-01-12 18:29:36 +0800176 "enter to exit: "):
chojoyce3c5ad5c2021-07-05 10:44:14 +0800177 sys.exit(constants.EXIT_BY_USER)
178
chojoyceb0817032022-01-12 18:29:36 +0800179 mkcert.Install()
180 logger.info("The local CA '%s.pem' is installed now.",
181 constants.SSL_CA_NAME)
182
herbertxue975b8872020-02-12 14:41:41 +0800183
Sam Chiu81bdc652018-06-29 18:45:08 +0800184class CuttlefishHostSetup(base_task_runner.BaseTaskRunner):
185 """Subtask class that setup host for cuttlefish."""
186
chojoyceb0817032022-01-12 18:29:36 +0800187 WELCOME_MESSAGE_TITLE = "Host Environment Setup"
Sam Chiu81bdc652018-06-29 18:45:08 +0800188 WELCOME_MESSAGE = (
chojoyceb0817032022-01-12 18:29:36 +0800189 "This step will help you to setup environment for running Android "
Sam Chiu81bdc652018-06-29 18:45:08 +0800190 "cuttlefish devices on your host. That includes adding user to kvm "
191 "related groups and checking required linux modules."
192 )
193
194 def ShouldRun(self):
195 """Check host user groups and modules.
196
197 Returns:
198 Boolean: False if user is in all required groups and all modules
199 are reloaded.
200 """
Sam Chiu6c738d62018-12-04 10:29:02 +0800201 if not utils.IsSupportedPlatform():
Sam Chiu81bdc652018-06-29 18:45:08 +0800202 return False
203
herbertxue07293a32018-11-05 20:40:11 +0800204 return not (utils.CheckUserInGroups(constants.LIST_CF_USER_GROUPS)
Sam Chiu81bdc652018-06-29 18:45:08 +0800205 and self._CheckLoadedModules(_LIST_OF_MODULES))
206
207 @staticmethod
Sam Chiu81bdc652018-06-29 18:45:08 +0800208 def _CheckLoadedModules(module_list):
209 """Check if the modules are all in use.
210
211 Args:
212 module_list: The list of module name.
213 Returns:
214 True if all modules are in use.
215 """
216 logger.info("Checking if modules are loaded: %s", module_list)
217 lsmod_output = setup_common.CheckCmdOutput("lsmod", print_cmd=False)
218 current_modules = [r.split()[0] for r in lsmod_output.splitlines()]
219 all_modules_present = True
220 for module in module_list:
221 if module not in current_modules:
222 logger.info("missing module: %s", module)
223 all_modules_present = False
224 return all_modules_present
225
226 def _Run(self):
227 """Setup host environment for local cuttlefish instance support."""
228 # TODO: provide --uid args to let user use prefered username
229 username = getpass.getuser()
230 setup_cmds = [
231 "sudo rmmod kvm_intel",
232 "sudo rmmod kvm",
233 "sudo modprobe kvm",
234 "sudo modprobe kvm_intel"]
Sam Chiuafbc6582018-09-04 20:47:13 +0800235 for group in constants.LIST_CF_USER_GROUPS:
Sam Chiu81bdc652018-06-29 18:45:08 +0800236 setup_cmds.append("sudo usermod -aG %s % s" % (group, username))
237
238 print("Below commands will be run:")
239 for setup_cmd in setup_cmds:
240 print(setup_cmd)
241
242 if self._ConfirmContinue():
243 for setup_cmd in setup_cmds:
244 setup_common.CheckCmdOutput(setup_cmd, shell=True)
245 print("Host environment setup has done!")
246
247 @staticmethod
248 def _ConfirmContinue():
249 """Ask user if they want to continue.
250
251 Returns:
252 True if user answer yes.
253 """
254 answer_client = utils.InteractWithQuestion(
herbertxue97af4a62020-11-05 17:12:56 +0800255 "\nEnter 'y' to continue, otherwise N or enter to exit: ",
Sam Chiu81bdc652018-06-29 18:45:08 +0800256 utils.TextColors.WARNING)
257 return answer_client in constants.USER_ANSWER_YES