xref: /aosp_15_r20/tools/acloud/public/config.py (revision 800a58d989c669b8eb8a71d8df53b1ba3d411444)
1*800a58d9SAndroid Build Coastguard Worker#!/usr/bin/env python
2*800a58d9SAndroid Build Coastguard Worker#
3*800a58d9SAndroid Build Coastguard Worker# Copyright 2016 - The Android Open Source Project
4*800a58d9SAndroid Build Coastguard Worker#
5*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*800a58d9SAndroid Build Coastguard Worker#
9*800a58d9SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*800a58d9SAndroid Build Coastguard Worker#
11*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*800a58d9SAndroid Build Coastguard Worker# limitations under the License.
16*800a58d9SAndroid Build Coastguard Worker
17*800a58d9SAndroid Build Coastguard Worker"""Config manager.
18*800a58d9SAndroid Build Coastguard Worker
19*800a58d9SAndroid Build Coastguard WorkerThree protobuf messages are defined in
20*800a58d9SAndroid Build Coastguard Worker   driver/internal/config/proto/internal_config.proto
21*800a58d9SAndroid Build Coastguard Worker   driver/internal/config/proto/user_config.proto
22*800a58d9SAndroid Build Coastguard Worker
23*800a58d9SAndroid Build Coastguard WorkerInternal config file     User config file
24*800a58d9SAndroid Build Coastguard Worker      |                         |
25*800a58d9SAndroid Build Coastguard Worker      v                         v
26*800a58d9SAndroid Build Coastguard Worker  InternalConfig           UserConfig
27*800a58d9SAndroid Build Coastguard Worker  (proto message)        (proto message)
28*800a58d9SAndroid Build Coastguard Worker        |                     |
29*800a58d9SAndroid Build Coastguard Worker        |                     |
30*800a58d9SAndroid Build Coastguard Worker        |->   AcloudConfig  <-|
31*800a58d9SAndroid Build Coastguard Worker
32*800a58d9SAndroid Build Coastguard WorkerAt runtime, AcloudConfigManager performs the following steps.
33*800a58d9SAndroid Build Coastguard Worker- Load driver config file into a InternalConfig message instance.
34*800a58d9SAndroid Build Coastguard Worker- Load user config file into a UserConfig message instance.
35*800a58d9SAndroid Build Coastguard Worker- Create AcloudConfig using InternalConfig and UserConfig.
36*800a58d9SAndroid Build Coastguard Worker
37*800a58d9SAndroid Build Coastguard WorkerTODO:
38*800a58d9SAndroid Build Coastguard Worker  1. Add support for override configs with command line args.
39*800a58d9SAndroid Build Coastguard Worker  2. Scan all configs to find the right config for given branch and build_id.
40*800a58d9SAndroid Build Coastguard Worker     Raise an error if the given build_id is smaller than min_build_id
41*800a58d9SAndroid Build Coastguard Worker     only applies to release build id.
42*800a58d9SAndroid Build Coastguard Worker     Raise an error if the branch is not supported.
43*800a58d9SAndroid Build Coastguard Worker
44*800a58d9SAndroid Build Coastguard Worker"""
45*800a58d9SAndroid Build Coastguard Worker
46*800a58d9SAndroid Build Coastguard Workerimport logging
47*800a58d9SAndroid Build Coastguard Workerimport importlib.resources
48*800a58d9SAndroid Build Coastguard Workerimport os
49*800a58d9SAndroid Build Coastguard Worker
50*800a58d9SAndroid Build Coastguard Workerfrom google.protobuf import text_format
51*800a58d9SAndroid Build Coastguard Worker
52*800a58d9SAndroid Build Coastguard Worker# pylint: disable=no-name-in-module,import-error
53*800a58d9SAndroid Build Coastguard Workerfrom acloud import errors
54*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal import constants
55*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.proto import internal_config_pb2
56*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.proto import user_config_pb2
57*800a58d9SAndroid Build Coastguard Workerfrom acloud.create import create_args
58*800a58d9SAndroid Build Coastguard Worker
59*800a58d9SAndroid Build Coastguard Worker
60*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
61*800a58d9SAndroid Build Coastguard Worker
62*800a58d9SAndroid Build Coastguard Worker_DEFAULT_CONFIG_FILE = "acloud.config"
63*800a58d9SAndroid Build Coastguard Worker_DEFAULT_HW_PROPERTY = "cpu:4,resolution:720x1280,dpi:320,memory:4g"
64*800a58d9SAndroid Build Coastguard Worker
65*800a58d9SAndroid Build Coastguard Worker# Resources
66*800a58d9SAndroid Build Coastguard Worker_INTERNAL_CONFIG_FILE = "default.config"
67*800a58d9SAndroid Build Coastguard Worker_VERSION_FILE = "VERSION"
68*800a58d9SAndroid Build Coastguard Worker_UNKNOWN = "UNKNOWN"
69*800a58d9SAndroid Build Coastguard Worker_NUM_INSTANCES_ARG = "-num_instances"
70*800a58d9SAndroid Build Coastguard Worker
71*800a58d9SAndroid Build Coastguard Worker
72*800a58d9SAndroid Build Coastguard Workerdef _OpenTextResource(resource):
73*800a58d9SAndroid Build Coastguard Worker    # Acloud binary does not have the embedded launcher, and it should be
74*800a58d9SAndroid Build Coastguard Worker    # compatible with python3.7 installed on the test servers.
75*800a58d9SAndroid Build Coastguard Worker    return importlib.resources.open_text("acloud.public.data", resource)
76*800a58d9SAndroid Build Coastguard Worker
77*800a58d9SAndroid Build Coastguard Worker
78*800a58d9SAndroid Build Coastguard Workerdef GetVersion():
79*800a58d9SAndroid Build Coastguard Worker    """Print the version of acloud.
80*800a58d9SAndroid Build Coastguard Worker
81*800a58d9SAndroid Build Coastguard Worker    The VERSION file is built into the acloud binary. The version file path is
82*800a58d9SAndroid Build Coastguard Worker    under "public/data".
83*800a58d9SAndroid Build Coastguard Worker
84*800a58d9SAndroid Build Coastguard Worker    Returns:
85*800a58d9SAndroid Build Coastguard Worker        String of the acloud version.
86*800a58d9SAndroid Build Coastguard Worker    """
87*800a58d9SAndroid Build Coastguard Worker    try:
88*800a58d9SAndroid Build Coastguard Worker        with _OpenTextResource(_VERSION_FILE) as version_file:
89*800a58d9SAndroid Build Coastguard Worker            return version_file.read()
90*800a58d9SAndroid Build Coastguard Worker    except FileNotFoundError:
91*800a58d9SAndroid Build Coastguard Worker        return _UNKNOWN
92*800a58d9SAndroid Build Coastguard Worker
93*800a58d9SAndroid Build Coastguard Worker
94*800a58d9SAndroid Build Coastguard Workerdef GetDefaultConfigFile():
95*800a58d9SAndroid Build Coastguard Worker    """Return path to default config file."""
96*800a58d9SAndroid Build Coastguard Worker    config_path = os.path.join(os.path.expanduser("~"), ".config", "acloud")
97*800a58d9SAndroid Build Coastguard Worker    # Create the default config dir if it doesn't exist.
98*800a58d9SAndroid Build Coastguard Worker    if not os.path.exists(config_path):
99*800a58d9SAndroid Build Coastguard Worker        os.makedirs(config_path)
100*800a58d9SAndroid Build Coastguard Worker    return os.path.join(config_path, _DEFAULT_CONFIG_FILE)
101*800a58d9SAndroid Build Coastguard Worker
102*800a58d9SAndroid Build Coastguard Worker
103*800a58d9SAndroid Build Coastguard Workerdef GetUserConfigPath(config_path):
104*800a58d9SAndroid Build Coastguard Worker    """Get Acloud user config file path.
105*800a58d9SAndroid Build Coastguard Worker
106*800a58d9SAndroid Build Coastguard Worker    If there is no config provided, Acloud would use default config path.
107*800a58d9SAndroid Build Coastguard Worker
108*800a58d9SAndroid Build Coastguard Worker    Args:
109*800a58d9SAndroid Build Coastguard Worker        config_path: String, path of Acloud config file.
110*800a58d9SAndroid Build Coastguard Worker
111*800a58d9SAndroid Build Coastguard Worker    Returns:
112*800a58d9SAndroid Build Coastguard Worker        Path (string) of the Acloud config.
113*800a58d9SAndroid Build Coastguard Worker    """
114*800a58d9SAndroid Build Coastguard Worker    if config_path:
115*800a58d9SAndroid Build Coastguard Worker        return config_path
116*800a58d9SAndroid Build Coastguard Worker    return GetDefaultConfigFile()
117*800a58d9SAndroid Build Coastguard Worker
118*800a58d9SAndroid Build Coastguard Worker
119*800a58d9SAndroid Build Coastguard Workerdef GetAcloudConfig(args):
120*800a58d9SAndroid Build Coastguard Worker    """Helper function to initialize Config object.
121*800a58d9SAndroid Build Coastguard Worker
122*800a58d9SAndroid Build Coastguard Worker    Args:
123*800a58d9SAndroid Build Coastguard Worker        args: Namespace object from argparse.parse_args.
124*800a58d9SAndroid Build Coastguard Worker
125*800a58d9SAndroid Build Coastguard Worker    Return:
126*800a58d9SAndroid Build Coastguard Worker        An instance of AcloudConfig.
127*800a58d9SAndroid Build Coastguard Worker    """
128*800a58d9SAndroid Build Coastguard Worker    config_mgr = AcloudConfigManager(args.config_file)
129*800a58d9SAndroid Build Coastguard Worker    cfg = config_mgr.Load()
130*800a58d9SAndroid Build Coastguard Worker    cfg.OverrideWithArgs(args)
131*800a58d9SAndroid Build Coastguard Worker    return cfg
132*800a58d9SAndroid Build Coastguard Worker
133*800a58d9SAndroid Build Coastguard Worker
134*800a58d9SAndroid Build Coastguard Workerclass AcloudConfig():
135*800a58d9SAndroid Build Coastguard Worker    """A class that holds all configurations for acloud."""
136*800a58d9SAndroid Build Coastguard Worker
137*800a58d9SAndroid Build Coastguard Worker    REQUIRED_FIELD = [
138*800a58d9SAndroid Build Coastguard Worker        "machine_type", "network", "min_machine_size",
139*800a58d9SAndroid Build Coastguard Worker        "disk_image_name", "disk_image_mime_type"
140*800a58d9SAndroid Build Coastguard Worker    ]
141*800a58d9SAndroid Build Coastguard Worker
142*800a58d9SAndroid Build Coastguard Worker    # pylint: disable=too-many-statements
143*800a58d9SAndroid Build Coastguard Worker    def __init__(self, usr_cfg, internal_cfg):
144*800a58d9SAndroid Build Coastguard Worker        """Initialize.
145*800a58d9SAndroid Build Coastguard Worker
146*800a58d9SAndroid Build Coastguard Worker        Args:
147*800a58d9SAndroid Build Coastguard Worker            usr_cfg: A protobuf object that holds the user configurations.
148*800a58d9SAndroid Build Coastguard Worker            internal_cfg: A protobuf object that holds internal configurations.
149*800a58d9SAndroid Build Coastguard Worker        """
150*800a58d9SAndroid Build Coastguard Worker        self.service_account_name = usr_cfg.service_account_name
151*800a58d9SAndroid Build Coastguard Worker        # pylint: disable=invalid-name
152*800a58d9SAndroid Build Coastguard Worker        self.service_account_private_key_path = (
153*800a58d9SAndroid Build Coastguard Worker            usr_cfg.service_account_private_key_path)
154*800a58d9SAndroid Build Coastguard Worker        self.service_account_json_private_key_path = (
155*800a58d9SAndroid Build Coastguard Worker            usr_cfg.service_account_json_private_key_path)
156*800a58d9SAndroid Build Coastguard Worker        self.creds_cache_file = internal_cfg.creds_cache_file
157*800a58d9SAndroid Build Coastguard Worker        self.user_agent = internal_cfg.user_agent
158*800a58d9SAndroid Build Coastguard Worker        self.client_id = usr_cfg.client_id
159*800a58d9SAndroid Build Coastguard Worker        self.client_secret = usr_cfg.client_secret
160*800a58d9SAndroid Build Coastguard Worker
161*800a58d9SAndroid Build Coastguard Worker        self.project = usr_cfg.project
162*800a58d9SAndroid Build Coastguard Worker        self.zone = usr_cfg.zone
163*800a58d9SAndroid Build Coastguard Worker        self.machine_type = (usr_cfg.machine_type or
164*800a58d9SAndroid Build Coastguard Worker                             internal_cfg.default_usr_cfg.machine_type)
165*800a58d9SAndroid Build Coastguard Worker        self.network = usr_cfg.network or internal_cfg.default_usr_cfg.network
166*800a58d9SAndroid Build Coastguard Worker        self.ssh_private_key_path = usr_cfg.ssh_private_key_path
167*800a58d9SAndroid Build Coastguard Worker        self.ssh_public_key_path = usr_cfg.ssh_public_key_path
168*800a58d9SAndroid Build Coastguard Worker        self.storage_bucket_name = usr_cfg.storage_bucket_name
169*800a58d9SAndroid Build Coastguard Worker        self.metadata_variable = dict(
170*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.metadata_variable.items())
171*800a58d9SAndroid Build Coastguard Worker        self.metadata_variable.update(usr_cfg.metadata_variable)
172*800a58d9SAndroid Build Coastguard Worker
173*800a58d9SAndroid Build Coastguard Worker        self.device_resolution_map = dict(
174*800a58d9SAndroid Build Coastguard Worker            internal_cfg.device_resolution_map.items())
175*800a58d9SAndroid Build Coastguard Worker        self.device_default_orientation_map = dict(
176*800a58d9SAndroid Build Coastguard Worker            internal_cfg.device_default_orientation_map.items())
177*800a58d9SAndroid Build Coastguard Worker        self.no_project_access_msg_map = dict(
178*800a58d9SAndroid Build Coastguard Worker            internal_cfg.no_project_access_msg_map.items())
179*800a58d9SAndroid Build Coastguard Worker        self.min_machine_size = internal_cfg.min_machine_size
180*800a58d9SAndroid Build Coastguard Worker        self.disk_image_name = internal_cfg.disk_image_name
181*800a58d9SAndroid Build Coastguard Worker        self.disk_image_mime_type = internal_cfg.disk_image_mime_type
182*800a58d9SAndroid Build Coastguard Worker        self.disk_image_extension = internal_cfg.disk_image_extension
183*800a58d9SAndroid Build Coastguard Worker        self.disk_raw_image_name = internal_cfg.disk_raw_image_name
184*800a58d9SAndroid Build Coastguard Worker        self.disk_raw_image_extension = internal_cfg.disk_raw_image_extension
185*800a58d9SAndroid Build Coastguard Worker        self.valid_branch_and_min_build_id = dict(
186*800a58d9SAndroid Build Coastguard Worker            internal_cfg.valid_branch_and_min_build_id.items())
187*800a58d9SAndroid Build Coastguard Worker        self.precreated_data_image_map = dict(
188*800a58d9SAndroid Build Coastguard Worker            internal_cfg.precreated_data_image.items())
189*800a58d9SAndroid Build Coastguard Worker        self.extra_data_disk_size_gb = (
190*800a58d9SAndroid Build Coastguard Worker            usr_cfg.extra_data_disk_size_gb or
191*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.extra_data_disk_size_gb)
192*800a58d9SAndroid Build Coastguard Worker        if self.extra_data_disk_size_gb > 0:
193*800a58d9SAndroid Build Coastguard Worker            if "cfg_sta_persistent_data_device" not in usr_cfg.metadata_variable:
194*800a58d9SAndroid Build Coastguard Worker                # If user did not set it explicity, use default.
195*800a58d9SAndroid Build Coastguard Worker                self.metadata_variable["cfg_sta_persistent_data_device"] = (
196*800a58d9SAndroid Build Coastguard Worker                    internal_cfg.default_extra_data_disk_device)
197*800a58d9SAndroid Build Coastguard Worker            if "cfg_sta_ephemeral_data_size_mb" in usr_cfg.metadata_variable:
198*800a58d9SAndroid Build Coastguard Worker                raise errors.ConfigError(
199*800a58d9SAndroid Build Coastguard Worker                    "The following settings can't be set at the same time: "
200*800a58d9SAndroid Build Coastguard Worker                    "extra_data_disk_size_gb and"
201*800a58d9SAndroid Build Coastguard Worker                    "metadata variable cfg_sta_ephemeral_data_size_mb.")
202*800a58d9SAndroid Build Coastguard Worker            if "cfg_sta_ephemeral_data_size_mb" in self.metadata_variable:
203*800a58d9SAndroid Build Coastguard Worker                del self.metadata_variable["cfg_sta_ephemeral_data_size_mb"]
204*800a58d9SAndroid Build Coastguard Worker
205*800a58d9SAndroid Build Coastguard Worker        # Additional scopes to be passed to the created instance
206*800a58d9SAndroid Build Coastguard Worker        self.extra_scopes = usr_cfg.extra_scopes
207*800a58d9SAndroid Build Coastguard Worker
208*800a58d9SAndroid Build Coastguard Worker        # Fields that can be overriden by args
209*800a58d9SAndroid Build Coastguard Worker        self.orientation = usr_cfg.orientation
210*800a58d9SAndroid Build Coastguard Worker        self.resolution = usr_cfg.resolution
211*800a58d9SAndroid Build Coastguard Worker
212*800a58d9SAndroid Build Coastguard Worker        self.stable_host_image_family = usr_cfg.stable_host_image_family
213*800a58d9SAndroid Build Coastguard Worker        self.stable_host_image_name = (
214*800a58d9SAndroid Build Coastguard Worker            usr_cfg.stable_host_image_name or
215*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.stable_host_image_name)
216*800a58d9SAndroid Build Coastguard Worker        self.stable_host_image_project = (
217*800a58d9SAndroid Build Coastguard Worker            usr_cfg.stable_host_image_project or
218*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.stable_host_image_project)
219*800a58d9SAndroid Build Coastguard Worker        self.kernel_build_target = internal_cfg.kernel_build_target
220*800a58d9SAndroid Build Coastguard Worker
221*800a58d9SAndroid Build Coastguard Worker        self.emulator_build_target = internal_cfg.emulator_build_target
222*800a58d9SAndroid Build Coastguard Worker        self.stable_goldfish_host_image_name = (
223*800a58d9SAndroid Build Coastguard Worker            usr_cfg.stable_goldfish_host_image_name or
224*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.stable_goldfish_host_image_name)
225*800a58d9SAndroid Build Coastguard Worker        self.stable_goldfish_host_image_project = (
226*800a58d9SAndroid Build Coastguard Worker            usr_cfg.stable_goldfish_host_image_project or
227*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.stable_goldfish_host_image_project)
228*800a58d9SAndroid Build Coastguard Worker
229*800a58d9SAndroid Build Coastguard Worker        self.stable_cheeps_host_image_name = (
230*800a58d9SAndroid Build Coastguard Worker            usr_cfg.stable_cheeps_host_image_name or
231*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.stable_cheeps_host_image_name)
232*800a58d9SAndroid Build Coastguard Worker        self.stable_cheeps_host_image_project = (
233*800a58d9SAndroid Build Coastguard Worker            usr_cfg.stable_cheeps_host_image_project or
234*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.stable_cheeps_host_image_project)
235*800a58d9SAndroid Build Coastguard Worker        self.betty_image = usr_cfg.betty_image
236*800a58d9SAndroid Build Coastguard Worker
237*800a58d9SAndroid Build Coastguard Worker        self.extra_args_ssh_tunnel = usr_cfg.extra_args_ssh_tunnel
238*800a58d9SAndroid Build Coastguard Worker
239*800a58d9SAndroid Build Coastguard Worker        self.common_hw_property_map = internal_cfg.common_hw_property_map
240*800a58d9SAndroid Build Coastguard Worker        self.hw_property = usr_cfg.hw_property
241*800a58d9SAndroid Build Coastguard Worker
242*800a58d9SAndroid Build Coastguard Worker        self.launch_args = usr_cfg.launch_args
243*800a58d9SAndroid Build Coastguard Worker        self.oxygen_client = usr_cfg.oxygen_client
244*800a58d9SAndroid Build Coastguard Worker        self.oxygen_lease_args = usr_cfg.oxygen_lease_args
245*800a58d9SAndroid Build Coastguard Worker        self.connect_hostname = usr_cfg.connect_hostname
246*800a58d9SAndroid Build Coastguard Worker        self.instance_name_pattern = (
247*800a58d9SAndroid Build Coastguard Worker            usr_cfg.instance_name_pattern or
248*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.instance_name_pattern)
249*800a58d9SAndroid Build Coastguard Worker        self.fetch_cvd_version = (
250*800a58d9SAndroid Build Coastguard Worker            usr_cfg.fetch_cvd_version or
251*800a58d9SAndroid Build Coastguard Worker            internal_cfg.default_usr_cfg.fetch_cvd_version)
252*800a58d9SAndroid Build Coastguard Worker        if usr_cfg.HasField("enable_multi_stage") is not None:
253*800a58d9SAndroid Build Coastguard Worker            self.enable_multi_stage = usr_cfg.enable_multi_stage
254*800a58d9SAndroid Build Coastguard Worker        elif internal_cfg.default_usr_cfg.HasField("enable_multi_stage"):
255*800a58d9SAndroid Build Coastguard Worker            self.enable_multi_stage = internal_cfg.default_usr_cfg.enable_multi_stage
256*800a58d9SAndroid Build Coastguard Worker        else:
257*800a58d9SAndroid Build Coastguard Worker            self.enable_multi_stage = False
258*800a58d9SAndroid Build Coastguard Worker        self.disk_type = usr_cfg.disk_type
259*800a58d9SAndroid Build Coastguard Worker        self.use_cvdr = usr_cfg.use_cvdr
260*800a58d9SAndroid Build Coastguard Worker        self.use_legacy_acloud = usr_cfg.use_legacy_acloud
261*800a58d9SAndroid Build Coastguard Worker
262*800a58d9SAndroid Build Coastguard Worker        # Verify validity of configurations.
263*800a58d9SAndroid Build Coastguard Worker        self.Verify()
264*800a58d9SAndroid Build Coastguard Worker
265*800a58d9SAndroid Build Coastguard Worker    # pylint: disable=too-many-branches
266*800a58d9SAndroid Build Coastguard Worker    def OverrideWithArgs(self, parsed_args):
267*800a58d9SAndroid Build Coastguard Worker        """Override configuration values with args passed in from cmd line.
268*800a58d9SAndroid Build Coastguard Worker
269*800a58d9SAndroid Build Coastguard Worker        Args:
270*800a58d9SAndroid Build Coastguard Worker            parsed_args: Args parsed from command line.
271*800a58d9SAndroid Build Coastguard Worker        """
272*800a58d9SAndroid Build Coastguard Worker        if parsed_args.which == create_args.CMD_CREATE and parsed_args.spec:
273*800a58d9SAndroid Build Coastguard Worker            if not self.resolution:
274*800a58d9SAndroid Build Coastguard Worker                self.resolution = self.device_resolution_map.get(
275*800a58d9SAndroid Build Coastguard Worker                    parsed_args.spec, "")
276*800a58d9SAndroid Build Coastguard Worker            if not self.orientation:
277*800a58d9SAndroid Build Coastguard Worker                self.orientation = self.device_default_orientation_map.get(
278*800a58d9SAndroid Build Coastguard Worker                    parsed_args.spec, "")
279*800a58d9SAndroid Build Coastguard Worker        if parsed_args.email:
280*800a58d9SAndroid Build Coastguard Worker            self.service_account_name = parsed_args.email
281*800a58d9SAndroid Build Coastguard Worker        if parsed_args.service_account_json_private_key_path:
282*800a58d9SAndroid Build Coastguard Worker            self.service_account_json_private_key_path = (
283*800a58d9SAndroid Build Coastguard Worker                parsed_args.service_account_json_private_key_path)
284*800a58d9SAndroid Build Coastguard Worker        if parsed_args.which == "create_gf" and parsed_args.base_image:
285*800a58d9SAndroid Build Coastguard Worker            self.stable_goldfish_host_image_name = parsed_args.base_image
286*800a58d9SAndroid Build Coastguard Worker        if parsed_args.which in [create_args.CMD_CREATE, "create_cf"]:
287*800a58d9SAndroid Build Coastguard Worker            if parsed_args.network:
288*800a58d9SAndroid Build Coastguard Worker                self.network = parsed_args.network
289*800a58d9SAndroid Build Coastguard Worker            if parsed_args.multi_stage_launch is not None:
290*800a58d9SAndroid Build Coastguard Worker                self.enable_multi_stage = parsed_args.multi_stage_launch
291*800a58d9SAndroid Build Coastguard Worker        if parsed_args.which in [create_args.CMD_CREATE, "create_cf", "create_gf"]:
292*800a58d9SAndroid Build Coastguard Worker            if parsed_args.zone:
293*800a58d9SAndroid Build Coastguard Worker                self.zone = parsed_args.zone
294*800a58d9SAndroid Build Coastguard Worker        if (parsed_args.which == "create_cf" and
295*800a58d9SAndroid Build Coastguard Worker                parsed_args.num_avds_per_instance > 1):
296*800a58d9SAndroid Build Coastguard Worker            scrubbed_args = [arg for arg in self.launch_args.split()
297*800a58d9SAndroid Build Coastguard Worker                             if _NUM_INSTANCES_ARG not in arg]
298*800a58d9SAndroid Build Coastguard Worker            scrubbed_args.append("%s=%d" % (_NUM_INSTANCES_ARG,
299*800a58d9SAndroid Build Coastguard Worker                                            parsed_args.num_avds_per_instance))
300*800a58d9SAndroid Build Coastguard Worker
301*800a58d9SAndroid Build Coastguard Worker            self.launch_args = " ".join(scrubbed_args)
302*800a58d9SAndroid Build Coastguard Worker
303*800a58d9SAndroid Build Coastguard Worker    def GetDefaultHwProperty(self, flavor, instance_type=None):
304*800a58d9SAndroid Build Coastguard Worker        """Get default hw configuration values.
305*800a58d9SAndroid Build Coastguard Worker
306*800a58d9SAndroid Build Coastguard Worker        HwProperty will be overrided according to the change of flavor and
307*800a58d9SAndroid Build Coastguard Worker        instance type. The format of key is flavor or instance_type-flavor.
308*800a58d9SAndroid Build Coastguard Worker        e.g: 'phone' or 'local-phone'.
309*800a58d9SAndroid Build Coastguard Worker        If the giving key is not found, get hw configuration with a default
310*800a58d9SAndroid Build Coastguard Worker        phone property.
311*800a58d9SAndroid Build Coastguard Worker
312*800a58d9SAndroid Build Coastguard Worker        Args:
313*800a58d9SAndroid Build Coastguard Worker            flavor: String of flavor name.
314*800a58d9SAndroid Build Coastguard Worker            instance_type: String of instance type.
315*800a58d9SAndroid Build Coastguard Worker
316*800a58d9SAndroid Build Coastguard Worker        Returns:
317*800a58d9SAndroid Build Coastguard Worker            String of device hardware property, it would be like
318*800a58d9SAndroid Build Coastguard Worker            "cpu:4,resolution:720x1280,dpi:320,memory:4g".
319*800a58d9SAndroid Build Coastguard Worker        """
320*800a58d9SAndroid Build Coastguard Worker        hw_key = ("%s-%s" % (instance_type, flavor)
321*800a58d9SAndroid Build Coastguard Worker                  if instance_type == constants.INSTANCE_TYPE_LOCAL else flavor)
322*800a58d9SAndroid Build Coastguard Worker        return self.common_hw_property_map.get(hw_key, _DEFAULT_HW_PROPERTY)
323*800a58d9SAndroid Build Coastguard Worker
324*800a58d9SAndroid Build Coastguard Worker    def Verify(self):
325*800a58d9SAndroid Build Coastguard Worker        """Verify configuration fields."""
326*800a58d9SAndroid Build Coastguard Worker        missing = self.GetMissingFields(self.REQUIRED_FIELD)
327*800a58d9SAndroid Build Coastguard Worker        if missing:
328*800a58d9SAndroid Build Coastguard Worker            raise errors.ConfigError(
329*800a58d9SAndroid Build Coastguard Worker                "Missing required configuration fields: %s" % missing)
330*800a58d9SAndroid Build Coastguard Worker        if (self.extra_data_disk_size_gb and self.extra_data_disk_size_gb not in
331*800a58d9SAndroid Build Coastguard Worker                self.precreated_data_image_map):
332*800a58d9SAndroid Build Coastguard Worker            raise errors.ConfigError(
333*800a58d9SAndroid Build Coastguard Worker                "Supported extra_data_disk_size_gb options(gb): %s, "
334*800a58d9SAndroid Build Coastguard Worker                "invalid value: %d" % (self.precreated_data_image_map.keys(),
335*800a58d9SAndroid Build Coastguard Worker                                       self.extra_data_disk_size_gb))
336*800a58d9SAndroid Build Coastguard Worker
337*800a58d9SAndroid Build Coastguard Worker    def GetMissingFields(self, fields):
338*800a58d9SAndroid Build Coastguard Worker        """Get missing required fields.
339*800a58d9SAndroid Build Coastguard Worker
340*800a58d9SAndroid Build Coastguard Worker        Args:
341*800a58d9SAndroid Build Coastguard Worker            fields: List of field names.
342*800a58d9SAndroid Build Coastguard Worker
343*800a58d9SAndroid Build Coastguard Worker        Returns:
344*800a58d9SAndroid Build Coastguard Worker            List of missing field names.
345*800a58d9SAndroid Build Coastguard Worker        """
346*800a58d9SAndroid Build Coastguard Worker        return [f for f in fields if not getattr(self, f)]
347*800a58d9SAndroid Build Coastguard Worker
348*800a58d9SAndroid Build Coastguard Worker    def SupportRemoteInstance(self):
349*800a58d9SAndroid Build Coastguard Worker        """Return True if gcp project is provided in config."""
350*800a58d9SAndroid Build Coastguard Worker        return bool(self.project)
351*800a58d9SAndroid Build Coastguard Worker
352*800a58d9SAndroid Build Coastguard Worker
353*800a58d9SAndroid Build Coastguard Workerclass AcloudConfigManager():
354*800a58d9SAndroid Build Coastguard Worker    """A class that loads configurations."""
355*800a58d9SAndroid Build Coastguard Worker
356*800a58d9SAndroid Build Coastguard Worker    def __init__(self, user_config_path):
357*800a58d9SAndroid Build Coastguard Worker        """Initialize with user specified paths to configs.
358*800a58d9SAndroid Build Coastguard Worker
359*800a58d9SAndroid Build Coastguard Worker        Args:
360*800a58d9SAndroid Build Coastguard Worker            user_config_path: path to the user config.
361*800a58d9SAndroid Build Coastguard Worker        """
362*800a58d9SAndroid Build Coastguard Worker        self.user_config_path = user_config_path
363*800a58d9SAndroid Build Coastguard Worker
364*800a58d9SAndroid Build Coastguard Worker    def Load(self):
365*800a58d9SAndroid Build Coastguard Worker        """Load the configurations.
366*800a58d9SAndroid Build Coastguard Worker
367*800a58d9SAndroid Build Coastguard Worker        Load user config with some special design.
368*800a58d9SAndroid Build Coastguard Worker        1. User specified user config:
369*800a58d9SAndroid Build Coastguard Worker            a.User config exist: Load config.
370*800a58d9SAndroid Build Coastguard Worker            b.User config didn't exist: Raise exception.
371*800a58d9SAndroid Build Coastguard Worker        2. User didn't specify user config, use default config:
372*800a58d9SAndroid Build Coastguard Worker            a.Default config exist: Load config.
373*800a58d9SAndroid Build Coastguard Worker            b.Default config didn't exist: provide empty usr_cfg.
374*800a58d9SAndroid Build Coastguard Worker
375*800a58d9SAndroid Build Coastguard Worker        Raises:
376*800a58d9SAndroid Build Coastguard Worker            errors.ConfigError: If config file doesn't exist.
377*800a58d9SAndroid Build Coastguard Worker
378*800a58d9SAndroid Build Coastguard Worker        Returns:
379*800a58d9SAndroid Build Coastguard Worker            An instance of AcloudConfig.
380*800a58d9SAndroid Build Coastguard Worker        """
381*800a58d9SAndroid Build Coastguard Worker        internal_cfg = None
382*800a58d9SAndroid Build Coastguard Worker        usr_cfg = None
383*800a58d9SAndroid Build Coastguard Worker        try:
384*800a58d9SAndroid Build Coastguard Worker            with _OpenTextResource(_INTERNAL_CONFIG_FILE) as cfg_file:
385*800a58d9SAndroid Build Coastguard Worker                internal_cfg = self.LoadConfigFromProtocolBuffer(
386*800a58d9SAndroid Build Coastguard Worker                    cfg_file, internal_config_pb2.InternalConfig)
387*800a58d9SAndroid Build Coastguard Worker        except OSError as e:
388*800a58d9SAndroid Build Coastguard Worker            raise errors.ConfigError("Could not load config files: %s" % str(e))
389*800a58d9SAndroid Build Coastguard Worker        # Load user config file
390*800a58d9SAndroid Build Coastguard Worker        self.user_config_path = GetUserConfigPath(self.user_config_path)
391*800a58d9SAndroid Build Coastguard Worker        if os.path.exists(self.user_config_path):
392*800a58d9SAndroid Build Coastguard Worker            with open(self.user_config_path, "r") as config_file:
393*800a58d9SAndroid Build Coastguard Worker                usr_cfg = self.LoadConfigFromProtocolBuffer(
394*800a58d9SAndroid Build Coastguard Worker                    config_file, user_config_pb2.UserConfig)
395*800a58d9SAndroid Build Coastguard Worker        else:
396*800a58d9SAndroid Build Coastguard Worker            if self.user_config_path != GetDefaultConfigFile():
397*800a58d9SAndroid Build Coastguard Worker                raise errors.ConfigError(
398*800a58d9SAndroid Build Coastguard Worker                    "The config file doesn't exist: %s. For reset config "
399*800a58d9SAndroid Build Coastguard Worker                    "information: go/acloud-googler-setup#reset-configuration" %
400*800a58d9SAndroid Build Coastguard Worker                    (self.user_config_path))
401*800a58d9SAndroid Build Coastguard Worker            usr_cfg = user_config_pb2.UserConfig()
402*800a58d9SAndroid Build Coastguard Worker        return AcloudConfig(usr_cfg, internal_cfg)
403*800a58d9SAndroid Build Coastguard Worker
404*800a58d9SAndroid Build Coastguard Worker    @staticmethod
405*800a58d9SAndroid Build Coastguard Worker    def LoadConfigFromProtocolBuffer(config_file, message_type):
406*800a58d9SAndroid Build Coastguard Worker        """Load config from a text-based protocol buffer file.
407*800a58d9SAndroid Build Coastguard Worker
408*800a58d9SAndroid Build Coastguard Worker        Args:
409*800a58d9SAndroid Build Coastguard Worker            config_file: A python File object.
410*800a58d9SAndroid Build Coastguard Worker            message_type: A proto message class.
411*800a58d9SAndroid Build Coastguard Worker
412*800a58d9SAndroid Build Coastguard Worker        Returns:
413*800a58d9SAndroid Build Coastguard Worker            An instance of type "message_type" populated with data
414*800a58d9SAndroid Build Coastguard Worker            from the file.
415*800a58d9SAndroid Build Coastguard Worker        """
416*800a58d9SAndroid Build Coastguard Worker        try:
417*800a58d9SAndroid Build Coastguard Worker            config = message_type()
418*800a58d9SAndroid Build Coastguard Worker            text_format.Merge(config_file.read(), config)
419*800a58d9SAndroid Build Coastguard Worker            return config
420*800a58d9SAndroid Build Coastguard Worker        except text_format.ParseError as e:
421*800a58d9SAndroid Build Coastguard Worker            raise errors.ConfigError("Could not parse config: %s" % str(e))
422