1# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4"""This module provides functions for loading side_effects_config.json.
5"""
6
7import errno
8import os
9
10from google.protobuf import json_format
11
12import common
13from autotest_lib.utils.side_effects.proto import config_pb2
14
15_SIDE_EFFECTS_CONFIG_FILE = 'side_effects_config.json'
16
17
18def load(results_dir):
19    """Load a side_effects_config.json file.
20
21    @param results_dir: The path to the results directory containing the file.
22
23    @returns: a side_effects.Config proto object if side_effects_config.json
24              exists, None otherwise.
25
26    @raises: json_format.ParseError if the content of side_effects_config.json
27             is not valid JSON.
28    """
29    config_path = os.path.join(results_dir, _SIDE_EFFECTS_CONFIG_FILE)
30
31    if not os.path.exists(config_path):
32        return None
33
34    with open(config_path, 'r') as config_file:
35        content = config_file.read()
36        config = config_pb2.Config()
37        return json_format.Parse(content, config, ignore_unknown_fields=True)
38
39
40def validate_tko(config):
41    """Validate the tko field of the side_effects.Config.
42
43    @param config: A side_effects.Config proto.
44
45    @raises: ValueError if the tko field does not contain all required fields.
46             OSError if one of the required files is missing.
47    """
48    _check_empty_fields({
49        'TKO proxy socket': config.tko.proxy_socket,
50        'TKO MySQL user': config.tko.mysql_user,
51        'TKO MySQL password file': config.tko.mysql_password_file
52    })
53
54    _check_file_existence({
55        'TKO proxy socket': config.tko.proxy_socket,
56        'TKO MySQL password file': config.tko.mysql_password_file
57    })
58
59
60def validate_google_storage(config):
61    """Validate the google_storage field of the side_effects.Config.
62
63    @param config: A side_effects.Config proto.
64
65    @raises: ValueError if the tko field does not contain all required fields.
66             OSError if one of the required files is missing.
67    """
68    _check_empty_fields({
69        'Google Storage bucket': config.google_storage.bucket,
70        'Google Storage credentials file':
71            config.google_storage.credentials_file
72    })
73
74    _check_file_existence({
75        'Google Storage credentials file':
76            config.google_storage.credentials_file
77    })
78
79
80def _check_empty_fields(fields):
81    """Return a list of missing required TKO-related fields.
82
83    @param fields: A dict mapping string field descriptions to string field
84                   values.
85
86    @raises: ValueError if at least one of the field values is empty.
87    """
88    empty_fields = []
89    for description, value in fields.items():
90        if not value:
91            empty_fields.append(description)
92    if empty_fields:
93        raise ValueError('Missing required fields: ' + ', '.join(empty_fields))
94
95
96def _check_file_existence(files):
97    """Checks that all given files exist.
98
99    @param files: A dict mapping string file descriptions to string file names.
100
101    @raises: OSError if at least one of the files is missing.
102    """
103    missing_files = []
104    for description, path in files.items():
105        if not os.path.exists(path):
106            missing_files.append(description + ': ' + path)
107    if missing_files:
108        raise OSError(errno.ENOENT, os.strerror(errno.ENOENT),
109                      ', '.join(missing_files))
110