xref: /aosp_15_r20/external/skia/bazel/skia_app_container.bzl (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker"""This module defines the skia_app_container macro."""
2*c8dee2aaSAndroid Build Coastguard Worker
3*c8dee2aaSAndroid Build Coastguard Workerload("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push")
4*c8dee2aaSAndroid Build Coastguard Workerload("@io_bazel_rules_docker//docker/util:run.bzl", "container_run_and_commit")
5*c8dee2aaSAndroid Build Coastguard Workerload("@rules_pkg//:pkg.bzl", "pkg_tar")
6*c8dee2aaSAndroid Build Coastguard Worker
7*c8dee2aaSAndroid Build Coastguard Workerdef skia_app_container(
8*c8dee2aaSAndroid Build Coastguard Worker        name,
9*c8dee2aaSAndroid Build Coastguard Worker        repository,
10*c8dee2aaSAndroid Build Coastguard Worker        dirs,
11*c8dee2aaSAndroid Build Coastguard Worker        entrypoint = "",
12*c8dee2aaSAndroid Build Coastguard Worker        run_commands_root = None,
13*c8dee2aaSAndroid Build Coastguard Worker        run_commands_skia = None,
14*c8dee2aaSAndroid Build Coastguard Worker        base_image = "@basealpine//image",
15*c8dee2aaSAndroid Build Coastguard Worker        env = None,
16*c8dee2aaSAndroid Build Coastguard Worker        default_user = "skia"):
17*c8dee2aaSAndroid Build Coastguard Worker    """Builds a Docker container for a Skia app, and generates a target to push it to GCR.
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker    This macro produces the following:
20*c8dee2aaSAndroid Build Coastguard Worker    * "<name>" target to build the Docker container with skia as default user.
21*c8dee2aaSAndroid Build Coastguard Worker    * "<name>_run_root" target to execute run commands as root on the image.
22*c8dee2aaSAndroid Build Coastguard Worker                        root will be the default user here. Will be created only
23*c8dee2aaSAndroid Build Coastguard Worker                        if run_commands_root is specified.
24*c8dee2aaSAndroid Build Coastguard Worker    * "<name>_run_skia" target to execute run commands as the "skia" user on the image.
25*c8dee2aaSAndroid Build Coastguard Worker                        Will be created only if run_commands_skia is specified.
26*c8dee2aaSAndroid Build Coastguard Worker    * "push_<name>" target to push the container to GCR.
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Worker    Example:
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker    ```
31*c8dee2aaSAndroid Build Coastguard Worker        # //myapp/BUILD.bazel
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker        load("//bazel:skia_app_container.bzl", "skia_app_container")
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker        skia_app_container(
36*c8dee2aaSAndroid Build Coastguard Worker            name = "myapp",
37*c8dee2aaSAndroid Build Coastguard Worker            dirs = {
38*c8dee2aaSAndroid Build Coastguard Worker                "/usr/local/bin/myapp": [
39*c8dee2aaSAndroid Build Coastguard Worker                    ["//myapp/go:mybinary", 755"],
40*c8dee2aaSAndroid Build Coastguard Worker                ],
41*c8dee2aaSAndroid Build Coastguard Worker                "/usr/local/share/myapp": [
42*c8dee2aaSAndroid Build Coastguard Worker                    ["//myapp/config:config.cfg", "644"],
43*c8dee2aaSAndroid Build Coastguard Worker                    ["//myapp/data:data.json", "644"],
44*c8dee2aaSAndroid Build Coastguard Worker                ],
45*c8dee2aaSAndroid Build Coastguard Worker            },
46*c8dee2aaSAndroid Build Coastguard Worker            entrypoint = "/usr/local/bin/myapp/mybinary",
47*c8dee2aaSAndroid Build Coastguard Worker            repository = "skia-public/myapp",
48*c8dee2aaSAndroid Build Coastguard Worker        )
49*c8dee2aaSAndroid Build Coastguard Worker    ```
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker    The above example will produce a Docker container based on gcr.io/skia-public/basealpine with
52*c8dee2aaSAndroid Build Coastguard Worker    the following contents:
53*c8dee2aaSAndroid Build Coastguard Worker
54*c8dee2aaSAndroid Build Coastguard Worker      - /usr/local/bin/myapp/mybinary (mode: 755)
55*c8dee2aaSAndroid Build Coastguard Worker      - /usr/local/share/myapp/config.cfg (mode: 644)
56*c8dee2aaSAndroid Build Coastguard Worker      - /usr/local/share/myapp/data.json (mode: 644)
57*c8dee2aaSAndroid Build Coastguard Worker
58*c8dee2aaSAndroid Build Coastguard Worker    To build the container and load it into Docker:
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker    ```
61*c8dee2aaSAndroid Build Coastguard Worker        $ bazel run //myapp:myapp
62*c8dee2aaSAndroid Build Coastguard Worker        ...
63*c8dee2aaSAndroid Build Coastguard Worker        Loaded image ID: sha256:c0decafe
64*c8dee2aaSAndroid Build Coastguard Worker        Tagging c0decafe as bazel/myapp:myapp
65*c8dee2aaSAndroid Build Coastguard Worker    ```
66*c8dee2aaSAndroid Build Coastguard Worker
67*c8dee2aaSAndroid Build Coastguard Worker    To debug the container locally:
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker    ```
70*c8dee2aaSAndroid Build Coastguard Worker        $ docker run bazel/myapp:myapp
71*c8dee2aaSAndroid Build Coastguard Worker        $ docker run -it --entrypoint /bin/sh bazel/myapp:myapp
72*c8dee2aaSAndroid Build Coastguard Worker    ```
73*c8dee2aaSAndroid Build Coastguard Worker
74*c8dee2aaSAndroid Build Coastguard Worker    To push the container to GCR:
75*c8dee2aaSAndroid Build Coastguard Worker
76*c8dee2aaSAndroid Build Coastguard Worker    ```
77*c8dee2aaSAndroid Build Coastguard Worker        $ bazel run //myapp:push_myapp
78*c8dee2aaSAndroid Build Coastguard Worker        ...
79*c8dee2aaSAndroid Build Coastguard Worker        Successfully pushed Docker image to gcr.io/skia-public/myapp:...
80*c8dee2aaSAndroid Build Coastguard Worker    ```
81*c8dee2aaSAndroid Build Coastguard Worker
82*c8dee2aaSAndroid Build Coastguard Worker    Args:
83*c8dee2aaSAndroid Build Coastguard Worker      name: Name of the rule.
84*c8dee2aaSAndroid Build Coastguard Worker      repository: Name of the repository under gcr.io.
85*c8dee2aaSAndroid Build Coastguard Worker      dirs: Contents of the container, expressed as a dictionary where the keys are directory names
86*c8dee2aaSAndroid Build Coastguard Worker        within the container (e.g. "/usr/local/share/myapp"), and the values are an array of
87*c8dee2aaSAndroid Build Coastguard Worker        [Bazel label, mode] tuples indicating which files should be copied into the directory (e.g.
88*c8dee2aaSAndroid Build Coastguard Worker        ["//myapp/go:mybinary", "755"]).
89*c8dee2aaSAndroid Build Coastguard Worker      entrypoint: The entrypoint of the container, which can be a string or an array (e.g.
90*c8dee2aaSAndroid Build Coastguard Worker        "/usr/local/share/myapp/mybinary", or ["/usr/local/share/myapp/mybinary", "--someflag"]).
91*c8dee2aaSAndroid Build Coastguard Worker        Optional.
92*c8dee2aaSAndroid Build Coastguard Worker      run_commands_root: The RUN commands that should be executed on the container by the root
93*c8dee2aaSAndroid Build Coastguard Worker        user. Optional.
94*c8dee2aaSAndroid Build Coastguard Worker      run_commands_skia: The RUN commands that should be executed on the container by the skia
95*c8dee2aaSAndroid Build Coastguard Worker        user. Optional.
96*c8dee2aaSAndroid Build Coastguard Worker      base_image: The image to base the container_image on. Optional.
97*c8dee2aaSAndroid Build Coastguard Worker      env: A {"var": "val"} dictionary with the environment variables to use when building the
98*c8dee2aaSAndroid Build Coastguard Worker        container. Optional.
99*c8dee2aaSAndroid Build Coastguard Worker      default_user: The user the container will be run with. Defaults to "skia" but some apps
100*c8dee2aaSAndroid Build Coastguard Worker        like skfe requires the default user to be "root".
101*c8dee2aaSAndroid Build Coastguard Worker    """
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker    # According to the container_image rule's docs[1], the recommended way to place files in
104*c8dee2aaSAndroid Build Coastguard Worker    # specific directories is via the pkg_tar rule.
105*c8dee2aaSAndroid Build Coastguard Worker    #
106*c8dee2aaSAndroid Build Coastguard Worker    # The below loop creates one pkg_tar rule for each file in the container.
107*c8dee2aaSAndroid Build Coastguard Worker    #
108*c8dee2aaSAndroid Build Coastguard Worker    # [1] https://github.com/bazelbuild/rules_docker/blob/454981e65fa100d37b19210ee85fedb2f7af9626/README.md#container_image
109*c8dee2aaSAndroid Build Coastguard Worker    pkg_tars = []
110*c8dee2aaSAndroid Build Coastguard Worker    i = 0
111*c8dee2aaSAndroid Build Coastguard Worker    for dir in dirs:
112*c8dee2aaSAndroid Build Coastguard Worker        for file, mode in dirs[dir]:
113*c8dee2aaSAndroid Build Coastguard Worker            pkg_tar_name = name + "_pkg_tar_" + str(i)
114*c8dee2aaSAndroid Build Coastguard Worker            i += 1
115*c8dee2aaSAndroid Build Coastguard Worker            pkg_tars.append(pkg_tar_name)
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker            pkg_tar(
118*c8dee2aaSAndroid Build Coastguard Worker                name = pkg_tar_name,
119*c8dee2aaSAndroid Build Coastguard Worker                srcs = [file],
120*c8dee2aaSAndroid Build Coastguard Worker                package_dir = dir,
121*c8dee2aaSAndroid Build Coastguard Worker                mode = mode,
122*c8dee2aaSAndroid Build Coastguard Worker                tags = ["manual"],  # Exclude it from wildcard queries, e.g. "bazel build //...".
123*c8dee2aaSAndroid Build Coastguard Worker            )
124*c8dee2aaSAndroid Build Coastguard Worker
125*c8dee2aaSAndroid Build Coastguard Worker    image_name = (name + "_base") if (run_commands_root or run_commands_skia) else name
126*c8dee2aaSAndroid Build Coastguard Worker
127*c8dee2aaSAndroid Build Coastguard Worker    container_image(
128*c8dee2aaSAndroid Build Coastguard Worker        name = image_name,
129*c8dee2aaSAndroid Build Coastguard Worker        base = base_image,
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker        # We cannot use an entrypoint with the container_run_and_commit rule
132*c8dee2aaSAndroid Build Coastguard Worker        # required when run_commands_root or run_commands_skia is specified,
133*c8dee2aaSAndroid Build Coastguard Worker        # because the commands we want to execute do not require a specific
134*c8dee2aaSAndroid Build Coastguard Worker        # entrypoint.
135*c8dee2aaSAndroid Build Coastguard Worker        # We will set the entrypoint back after the container_run_and_commit
136*c8dee2aaSAndroid Build Coastguard Worker        # rule is executed.
137*c8dee2aaSAndroid Build Coastguard Worker        entrypoint = None if (run_commands_root or run_commands_skia) else [entrypoint],
138*c8dee2aaSAndroid Build Coastguard Worker        tars = pkg_tars,
139*c8dee2aaSAndroid Build Coastguard Worker        user = default_user,
140*c8dee2aaSAndroid Build Coastguard Worker        tags = ["manual"],  # Exclude it from wildcard queries, e.g. "bazel build //...".
141*c8dee2aaSAndroid Build Coastguard Worker        env = env,
142*c8dee2aaSAndroid Build Coastguard Worker    )
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard Worker    if run_commands_root:
145*c8dee2aaSAndroid Build Coastguard Worker        rule_name = name + "_run_root"
146*c8dee2aaSAndroid Build Coastguard Worker        container_run_and_commit(
147*c8dee2aaSAndroid Build Coastguard Worker            name = rule_name,
148*c8dee2aaSAndroid Build Coastguard Worker            commands = run_commands_root,
149*c8dee2aaSAndroid Build Coastguard Worker            docker_run_flags = ["--user", "root"],
150*c8dee2aaSAndroid Build Coastguard Worker            image = image_name + ".tar",
151*c8dee2aaSAndroid Build Coastguard Worker            tags = [
152*c8dee2aaSAndroid Build Coastguard Worker                "manual",  # Exclude it from wildcard queries, e.g. "bazel build //...".
153*c8dee2aaSAndroid Build Coastguard Worker                # container_run_and_commit requires the docker daemon to be
154*c8dee2aaSAndroid Build Coastguard Worker                # running. This is not possible inside RBE.
155*c8dee2aaSAndroid Build Coastguard Worker                "no-remote",
156*c8dee2aaSAndroid Build Coastguard Worker            ],
157*c8dee2aaSAndroid Build Coastguard Worker        )
158*c8dee2aaSAndroid Build Coastguard Worker        image_name = ":" + rule_name + "_commit.tar"
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker    if run_commands_skia:
161*c8dee2aaSAndroid Build Coastguard Worker        rule_name = name + "_run_skia"
162*c8dee2aaSAndroid Build Coastguard Worker        container_run_and_commit(
163*c8dee2aaSAndroid Build Coastguard Worker            name = rule_name,
164*c8dee2aaSAndroid Build Coastguard Worker            commands = run_commands_skia,
165*c8dee2aaSAndroid Build Coastguard Worker            docker_run_flags = ["--user", "skia"],
166*c8dee2aaSAndroid Build Coastguard Worker            # If run_commands_root was specified then the image_name already contains
167*c8dee2aaSAndroid Build Coastguard Worker            # ".tar" suffix. Make sure we do not add a double ".tar" suffix here.
168*c8dee2aaSAndroid Build Coastguard Worker            image = image_name if image_name.endswith(".tar") else image_name + ".tar",
169*c8dee2aaSAndroid Build Coastguard Worker            tags = [
170*c8dee2aaSAndroid Build Coastguard Worker                "manual",  # Exclude it from wildcard queries, e.g. "bazel build //...".
171*c8dee2aaSAndroid Build Coastguard Worker                # container_run_and_commit requires the docker daemon to be
172*c8dee2aaSAndroid Build Coastguard Worker                # running. This is not possible inside RBE.
173*c8dee2aaSAndroid Build Coastguard Worker                "no-remote",
174*c8dee2aaSAndroid Build Coastguard Worker            ],
175*c8dee2aaSAndroid Build Coastguard Worker        )
176*c8dee2aaSAndroid Build Coastguard Worker        image_name = ":" + rule_name + "_commit.tar"
177*c8dee2aaSAndroid Build Coastguard Worker
178*c8dee2aaSAndroid Build Coastguard Worker    if run_commands_root or run_commands_skia:
179*c8dee2aaSAndroid Build Coastguard Worker        # If run_commands_root was specified then it's container_run_and_commit
180*c8dee2aaSAndroid Build Coastguard Worker        # sets root as the default user and overrides the entrypoint.
181*c8dee2aaSAndroid Build Coastguard Worker        # If run_commands_skia was specified then it overrides the entrypoint.
182*c8dee2aaSAndroid Build Coastguard Worker        #
183*c8dee2aaSAndroid Build Coastguard Worker        # Now execute container_image using the previous image as base to set
184*c8dee2aaSAndroid Build Coastguard Worker        # back skia as the default user and to set back the original entrypoint.
185*c8dee2aaSAndroid Build Coastguard Worker        rule_name = name
186*c8dee2aaSAndroid Build Coastguard Worker        container_image(
187*c8dee2aaSAndroid Build Coastguard Worker            name = rule_name,
188*c8dee2aaSAndroid Build Coastguard Worker            base = image_name,
189*c8dee2aaSAndroid Build Coastguard Worker            entrypoint = [entrypoint],
190*c8dee2aaSAndroid Build Coastguard Worker            user = default_user,
191*c8dee2aaSAndroid Build Coastguard Worker            tags = ["manual"],  # Exclude it from wildcard queries, e.g. "bazel build //...".
192*c8dee2aaSAndroid Build Coastguard Worker            env = env,
193*c8dee2aaSAndroid Build Coastguard Worker        )
194*c8dee2aaSAndroid Build Coastguard Worker        image_name = ":" + rule_name
195*c8dee2aaSAndroid Build Coastguard Worker
196*c8dee2aaSAndroid Build Coastguard Worker    container_push(
197*c8dee2aaSAndroid Build Coastguard Worker        name = "push_" + name,
198*c8dee2aaSAndroid Build Coastguard Worker        format = "Docker",
199*c8dee2aaSAndroid Build Coastguard Worker        image = image_name,
200*c8dee2aaSAndroid Build Coastguard Worker        registry = "gcr.io",
201*c8dee2aaSAndroid Build Coastguard Worker        repository = repository,
202*c8dee2aaSAndroid Build Coastguard Worker        stamp = "@io_bazel_rules_docker//stamp:always",
203*c8dee2aaSAndroid Build Coastguard Worker        tag = "{STABLE_DOCKER_TAG}",
204*c8dee2aaSAndroid Build Coastguard Worker        tags = [
205*c8dee2aaSAndroid Build Coastguard Worker            "manual",  # Exclude it from wildcard queries, e.g. "bazel build //...".
206*c8dee2aaSAndroid Build Coastguard Worker            # container_push requires the docker daemon to be
207*c8dee2aaSAndroid Build Coastguard Worker            # running. This is not possible inside RBE.
208*c8dee2aaSAndroid Build Coastguard Worker            "no-remote",
209*c8dee2aaSAndroid Build Coastguard Worker        ],
210*c8dee2aaSAndroid Build Coastguard Worker    )
211