blob: 9a668e5e5d3974e6fb6d2dbe44bee41578f0a51c [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# Packages "devscripts" and "equivs" are required for "mk-build-deps".
40_AVD_REQUIRED_PKGS = [
41 "devscripts", "equivs", "libvirt-clients", "libvirt-daemon-system"]
Kevin Chengeb997272019-06-05 14:53:18 -070042_BASE_REQUIRED_PKGS = ["ssvnc", "lzop"]
herbertxue975b8872020-02-12 14:41:41 +080043_CUTTLEFISH_COMMOM_PKG = "cuttlefish-common"
44_CF_COMMOM_FOLDER = "cf-common"
Sam Chiu81bdc652018-06-29 18:45:08 +080045_LIST_OF_MODULES = ["kvm_intel", "kvm"]
Kevin Chengf756bbd2018-10-11 13:50:00 -070046_UPDATE_APT_GET_CMD = "sudo apt-get update"
herbertxue975b8872020-02-12 14:41:41 +080047_INSTALL_CUTTLEFISH_COMMOM_CMD = [
48 "git clone https://github.com/google/android-cuttlefish.git {git_folder}",
49 "cd {git_folder}",
50 "yes | sudo mk-build-deps -i -r -B",
51 "dpkg-buildpackage -uc -us",
52 "sudo apt-get install -y -f ../cuttlefish-common_*_amd64.deb"]
Sam Chiu81bdc652018-06-29 18:45:08 +080053
54
Kevin Chengeb997272019-06-05 14:53:18 -070055class BasePkgInstaller(base_task_runner.BaseTaskRunner):
56 """Subtask base runner class for installing packages."""
Sam Chiu81bdc652018-06-29 18:45:08 +080057
Kevin Chengeb997272019-06-05 14:53:18 -070058 # List of packages for child classes to override.
59 PACKAGES = []
Sam Chiu81bdc652018-06-29 18:45:08 +080060
61 def ShouldRun(self):
62 """Check if required packages are all installed.
63
64 Returns:
65 Boolean, True if required packages are not installed.
66 """
Sam Chiu6c738d62018-12-04 10:29:02 +080067 if not utils.IsSupportedPlatform():
Sam Chiu81bdc652018-06-29 18:45:08 +080068 return False
69
70 # Any required package is not installed or not up-to-date will need to
71 # run installation task.
Kevin Chengeb997272019-06-05 14:53:18 -070072 for pkg_name in self.PACKAGES:
Sam Chiu81bdc652018-06-29 18:45:08 +080073 if not setup_common.PackageInstalled(pkg_name):
74 return True
75
76 return False
77
78 def _Run(self):
Kevin Chengeb997272019-06-05 14:53:18 -070079 """Install specified packages."""
Sam Chiuaa703b62019-10-04 19:47:43 +080080 cmd = "\n".join(
81 [setup_common.PKG_INSTALL_CMD % pkg
82 for pkg in self.PACKAGES
83 if not setup_common.PackageInstalled(pkg)])
Sam Chiu81bdc652018-06-29 18:45:08 +080084
Sam Chiuaa703b62019-10-04 19:47:43 +080085 if not utils.GetUserAnswerYes("\nStart to install package(s):\n%s"
86 "\nPress 'y' to continue or anything "
87 "else to do it myself and run acloud "
88 "again[y/N]: " % cmd):
89 sys.exit(constants.EXIT_BY_USER)
Sam Chiu81bdc652018-06-29 18:45:08 +080090
Kevin Chengf756bbd2018-10-11 13:50:00 -070091 setup_common.CheckCmdOutput(_UPDATE_APT_GET_CMD, shell=True)
Kevin Chengeb997272019-06-05 14:53:18 -070092 for pkg in self.PACKAGES:
Sam Chiu81bdc652018-06-29 18:45:08 +080093 setup_common.InstallPackage(pkg)
94
Kevin Chengeb997272019-06-05 14:53:18 -070095 logger.info("All package(s) installed now.")
96
97
98class AvdPkgInstaller(BasePkgInstaller):
99 """Subtask runner class for installing packages for local instances."""
100
101 WELCOME_MESSAGE_TITLE = ("Install required packages for host setup for "
102 "local instances")
103 WELCOME_MESSAGE = ("This step will walk you through the required packages "
104 "installation for running Android cuttlefish devices "
105 "on your host.")
106 PACKAGES = _AVD_REQUIRED_PKGS
107
108
109class HostBasePkgInstaller(BasePkgInstaller):
110 """Subtask runner class for installing base host packages."""
111
112 WELCOME_MESSAGE_TITLE = "Install base packages on the host"
113 WELCOME_MESSAGE = ("This step will walk you through the base packages "
114 "installation for your host.")
115 PACKAGES = _BASE_REQUIRED_PKGS
Sam Chiu81bdc652018-06-29 18:45:08 +0800116
117
herbertxue975b8872020-02-12 14:41:41 +0800118class CuttlefishCommonPkgInstaller(base_task_runner.BaseTaskRunner):
119 """Subtask base runner class for installing cuttlefish-common."""
120
121 WELCOME_MESSAGE_TITLE = "Install cuttlefish-common packages on the host"
122 WELCOME_MESSAGE = ("This step will walk you through the cuttlefish-common "
123 "packages installation for your host.")
124
125 def ShouldRun(self):
126 """Check if cuttlefish-common package is installed.
127
128 Returns:
129 Boolean, True if cuttlefish-common is not installed.
130 """
131 if not utils.IsSupportedPlatform():
132 return False
133
134 # Any required package is not installed or not up-to-date will need to
135 # run installation task.
136 if not setup_common.PackageInstalled(_CUTTLEFISH_COMMOM_PKG):
137 return True
138 return False
139
140 def _Run(self):
141 """Install cuttlefilsh-common packages."""
142 cf_common_path = os.path.join(tempfile.mkdtemp(), _CF_COMMOM_FOLDER)
143 logger.debug("cuttlefish-common path: %s", cf_common_path)
144 cmd = "\n".join(sub_cmd.format(git_folder=cf_common_path)
145 for sub_cmd in _INSTALL_CUTTLEFISH_COMMOM_CMD)
146
147 if not utils.GetUserAnswerYes("\nStart to install cuttlefish-common :\n%s"
148 "\nPress 'y' to continue or anything "
149 "else to do it myself and run acloud "
150 "again[y/N]: " % cmd):
151 sys.exit(constants.EXIT_BY_USER)
152 try:
153 setup_common.CheckCmdOutput(cmd, shell=True)
154 finally:
155 shutil.rmtree(os.path.dirname(cf_common_path))
156 logger.info("Cuttlefish-common package installed now.")
157
158
Sam Chiu81bdc652018-06-29 18:45:08 +0800159class CuttlefishHostSetup(base_task_runner.BaseTaskRunner):
160 """Subtask class that setup host for cuttlefish."""
161
162 WELCOME_MESSAGE_TITLE = "Host Enviornment Setup"
163 WELCOME_MESSAGE = (
164 "This step will help you to setup enviornment for running Android "
165 "cuttlefish devices on your host. That includes adding user to kvm "
166 "related groups and checking required linux modules."
167 )
168
169 def ShouldRun(self):
170 """Check host user groups and modules.
171
172 Returns:
173 Boolean: False if user is in all required groups and all modules
174 are reloaded.
175 """
Sam Chiu6c738d62018-12-04 10:29:02 +0800176 if not utils.IsSupportedPlatform():
Sam Chiu81bdc652018-06-29 18:45:08 +0800177 return False
178
herbertxue07293a32018-11-05 20:40:11 +0800179 return not (utils.CheckUserInGroups(constants.LIST_CF_USER_GROUPS)
Sam Chiu81bdc652018-06-29 18:45:08 +0800180 and self._CheckLoadedModules(_LIST_OF_MODULES))
181
182 @staticmethod
Sam Chiu81bdc652018-06-29 18:45:08 +0800183 def _CheckLoadedModules(module_list):
184 """Check if the modules are all in use.
185
186 Args:
187 module_list: The list of module name.
188 Returns:
189 True if all modules are in use.
190 """
191 logger.info("Checking if modules are loaded: %s", module_list)
192 lsmod_output = setup_common.CheckCmdOutput("lsmod", print_cmd=False)
193 current_modules = [r.split()[0] for r in lsmod_output.splitlines()]
194 all_modules_present = True
195 for module in module_list:
196 if module not in current_modules:
197 logger.info("missing module: %s", module)
198 all_modules_present = False
199 return all_modules_present
200
201 def _Run(self):
202 """Setup host environment for local cuttlefish instance support."""
203 # TODO: provide --uid args to let user use prefered username
204 username = getpass.getuser()
205 setup_cmds = [
206 "sudo rmmod kvm_intel",
207 "sudo rmmod kvm",
208 "sudo modprobe kvm",
209 "sudo modprobe kvm_intel"]
Sam Chiuafbc6582018-09-04 20:47:13 +0800210 for group in constants.LIST_CF_USER_GROUPS:
Sam Chiu81bdc652018-06-29 18:45:08 +0800211 setup_cmds.append("sudo usermod -aG %s % s" % (group, username))
212
213 print("Below commands will be run:")
214 for setup_cmd in setup_cmds:
215 print(setup_cmd)
216
217 if self._ConfirmContinue():
218 for setup_cmd in setup_cmds:
219 setup_common.CheckCmdOutput(setup_cmd, shell=True)
220 print("Host environment setup has done!")
221
222 @staticmethod
223 def _ConfirmContinue():
224 """Ask user if they want to continue.
225
226 Returns:
227 True if user answer yes.
228 """
229 answer_client = utils.InteractWithQuestion(
Sam Chiu705b9012019-01-19 12:11:35 +0800230 "\nPress 'y' to continue or anything else to do it myself[y/N]: ",
Sam Chiu81bdc652018-06-29 18:45:08 +0800231 utils.TextColors.WARNING)
232 return answer_client in constants.USER_ANSWER_YES