blob: c734d99b253a4b037376df94129dc4e9ed1b4e89 [file] [log] [blame]
Alex Klein2966e302019-01-17 13:29:38 -07001# -*- coding: utf-8 -*-
2# Copyright 2018 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Image API Service.
7
8The image related API endpoints should generally be found here.
9"""
10
11from __future__ import print_function
12
13import os
14
Alex Klein7107bdd2019-03-14 17:14:31 -060015from chromite.api.gen.chromite.api import image_pb2
Alex Klein56355682019-02-07 10:36:54 -070016from chromite.lib import constants
17from chromite.lib import image_lib
Alex Kleinb7cdbe62019-02-22 11:41:32 -070018from chromite.service import image
Alex Klein2966e302019-01-17 13:29:38 -070019
Alex Klein56355682019-02-07 10:36:54 -070020# The image.proto ImageType enum ids.
21_BASE_ID = image_pb2.Image.BASE
22_DEV_ID = image_pb2.Image.DEV
23_TEST_ID = image_pb2.Image.TEST
24
25# Dict to allow easily translating names to enum ids and vice versa.
26_IMAGE_MAPPING = {
27 _BASE_ID: constants.IMAGE_TYPE_BASE,
28 constants.IMAGE_TYPE_BASE: _BASE_ID,
29 _DEV_ID: constants.IMAGE_TYPE_DEV,
30 constants.IMAGE_TYPE_DEV: _DEV_ID,
31 _TEST_ID: constants.IMAGE_TYPE_TEST,
32 constants.IMAGE_TYPE_TEST: _TEST_ID,
33}
34
35
Alex Klein2966e302019-01-17 13:29:38 -070036class Error(Exception):
37 """The module's base error class."""
38
39
Alex Klein56355682019-02-07 10:36:54 -070040class InvalidImageTypeError(Error):
41 """Invalid image type given."""
42
43
44class InvalidArgumentError(Error):
45 """Invalid argument to an image service function."""
46
47
48def Create(input_proto, output_proto):
49 """Build an image.
50
51 Args:
52 input_proto (image_pb2.CreateImageRequest): The input message.
53 output_proto (image_pb2.CreateImageResult): The output message.
54 """
55 board = input_proto.build_target.name
56 if not board:
57 raise InvalidArgumentError('build_target.name is required.')
58
59 image_types = set()
60 # Build the base image if no images provided.
61 to_build = input_proto.image_types or [_BASE_ID]
62 for current in to_build:
63 if current not in _IMAGE_MAPPING:
64 # Not expected, but at least it will be obvious if this comes up.
65 raise InvalidImageTypeError(
66 "The service's known image types do not match those in image.proto. "
67 'Unknown Enum ID: %s' % current)
68
69 image_types.add(_IMAGE_MAPPING[current])
70
71 enable_rootfs_verification = not input_proto.disable_rootfs_verification
72 version = input_proto.version or None
73 disk_layout = input_proto.disk_layout or None
74 builder_path = input_proto.builder_path or None
75 build_config = image.BuildConfig(
76 enable_rootfs_verification=enable_rootfs_verification, replace=True,
77 version=version, disk_layout=disk_layout, builder_path=builder_path,
78 )
79
80 # Sorted isn't really necessary here, but it's much easier to test.
81 output_proto.success = image.Build(board=board,
82 images=sorted(list(image_types)),
83 config=build_config)
84 if not output_proto.success:
85 # Nothing else to add on failure.
86 return
87
88 # Build out the ImageType->ImagePath mapping in the output.
89 # We're using the default path, so just fetch that, but read the symlink so
90 # the path we're returning is somewhat more permanent.
91 latest_link = image_lib.GetLatestImageLink(board)
92 read_link = os.readlink(latest_link)
93 if os.path.isabs(read_link):
94 # Absolute path, use the linked location.
95 base_path = os.path.normpath(read_link)
96 else:
97 # Relative path, convert to absolute using the symlink's containing folder.
98 base_path = os.path.join(os.path.dirname(latest_link), read_link)
99 base_path = os.path.normpath(base_path)
100
101 for current in image_types:
102 type_id = _IMAGE_MAPPING[current]
103 path = os.path.join(base_path, constants.IMAGE_TYPE_TO_NAME[current])
104
105 new_image = output_proto.images.add()
106 new_image.path = path
107 new_image.type = type_id
Alex Klein2966e302019-01-17 13:29:38 -0700108
109
110def Test(input_proto, output_proto):
111 """Run image tests.
112
113 Args:
114 input_proto (image_pb2.ImageTestRequest): The input message.
115 output_proto (image_pb2.ImageTestResult): The output message.
116 """
117 image_path = input_proto.image.path
118 board = input_proto.build_target.name
119 result_directory = input_proto.result.directory
120
121 if not board:
Alex Klein56355682019-02-07 10:36:54 -0700122 raise InvalidArgumentError('The build_target.name is required.')
Alex Klein2966e302019-01-17 13:29:38 -0700123 if not result_directory:
Alex Klein56355682019-02-07 10:36:54 -0700124 raise InvalidArgumentError('The result.directory is required.')
Alex Klein2966e302019-01-17 13:29:38 -0700125 if not image_path:
Alex Klein56355682019-02-07 10:36:54 -0700126 raise InvalidArgumentError('The image.path is required.')
Alex Klein2966e302019-01-17 13:29:38 -0700127
128 if not os.path.isfile(image_path) or not image_path.endswith('.bin'):
Alex Klein56355682019-02-07 10:36:54 -0700129 raise InvalidArgumentError(
Alex Klein2966e302019-01-17 13:29:38 -0700130 'The image.path must be an existing image file with a .bin extension.')
131
132 output_proto.success = image.Test(board, result_directory,
133 image_dir=image_path)