...

Text file src/edge-infra.dev/hack/build/rules/kustomize/kustomization.bzl

Documentation: edge-infra.dev/hack/build/rules/kustomize

     1"""Implementation for rules_kustomize"""
     2
     3load("//hack/build/rules/container:push_info.bzl", "OCIPushInfo")
     4load("@aspect_bazel_lib//lib:utils.bzl", "propagate_common_rule_attributes")
     5
     6KustomizeInfo = provider(
     7    doc = "Contains information about the built Kustomization",
     8    fields = {
     9        "deps": "Depset of source files for dependencies of this Kustomization.",
    10        "image_labels": "A list of pusher references from images",
    11        "images": "Dict of image references present in the dependencies of this Kustomization keyed by their container_push targets.",
    12    },
    13)
    14
    15def _kustomization_impl(ctx):
    16    kyaml = ctx.file.kustomization_yaml
    17    runfiles = ctx.runfiles()
    18
    19    # Kustomized manifests
    20    out = ctx.actions.declare_file("{0}_manifests.yaml".format(ctx.label.name))
    21
    22    # Script that will cat output of the manifests
    23    printer = ctx.actions.declare_file(ctx.label.name)
    24
    25    # Instantiate container_push label:image ref dictionary to collect pairings
    26    # found in the source files of the implementing kustomization and its deps
    27    image_dict = {}
    28
    29    image_labels = []
    30
    31    # Collect images from deps
    32    for dep in ctx.attr.deps:
    33        if dep[KustomizeInfo].images:
    34            dep_images = dep[KustomizeInfo].images
    35            for image in dep_images:
    36                if OCIPushInfo in image:
    37                    image_dict[image] = dep_images[image]
    38                    image_labels.append(dep_images[image])
    39
    40    # Collect images from the implementing kustomization
    41    if ctx.attr.images:
    42        for image in ctx.attr.images:
    43            if OCIPushInfo in image:
    44                image_dict[image] = ctx.attr.images[image]
    45                image_labels.append(ctx.attr.images[image])
    46
    47    # Instantiate list of input files for go helper
    48    input_files = [kyaml] + ctx.files.srcs
    49
    50    # Instantiate go helper flags and args
    51    helper_args = ctx.actions.args()
    52    helper_args.add_joined(["-src-kustomization", ctx.file.kustomization_yaml], join_with = "=")
    53    helper_args.add_joined(["-out-manifests", out.path], join_with = "=")
    54
    55    # If any images are found, leverage OCIPushInfo for updated references.
    56    if len(image_dict) > 0:
    57        for image in image_dict:
    58            # Add images entry to helper arguments as a tuple
    59            existing_ref = image_dict.get(image)
    60            helper_args.add_joined([existing_ref, image[OCIPushInfo].ref.path], join_with = "=")
    61
    62            # Include captured output with soruce kustomization.yaml for use in the go helper
    63            input_files.append(image[OCIPushInfo].ref)
    64
    65    # Inputs for the go helper
    66    input_deps = depset(
    67        direct = input_files,
    68        transitive = [dep[KustomizeInfo].deps for dep in ctx.attr.deps],
    69    )
    70
    71    # Run go helper which modifies kustomization to include spec.images
    72    ctx.actions.run(
    73        inputs = input_deps,
    74        outputs = [out],
    75        arguments = [helper_args],
    76        executable = ctx.executable._go_helper,
    77        progress_message = "Substituting images for %s kustomization..." % ctx.label.name,
    78    )
    79
    80    # Generate script to invoke all pushers & write manifests to stdout
    81    # The script changes the directory to that which contains the kustomized manifests
    82    ctx.actions.write(
    83        output = printer,
    84        content = """#!/usr/bin/env bash
    85cd ../..
    86echo \"$(cat {manifests})\"
    87        """.format(
    88            manifests = out.basename,
    89        ),
    90        is_executable = True,
    91    )
    92
    93    return [
    94        DefaultInfo(
    95            files = depset([out]),
    96            executable = printer,
    97            runfiles = runfiles,
    98        ),
    99        KustomizeInfo(
   100            deps = input_deps,
   101            images = ctx.attr.images if ctx.attr.images else {},
   102            image_labels = image_dict,
   103        ),
   104    ]
   105
   106_kustomization = rule(
   107    implementation = _kustomization_impl,
   108    attrs = {
   109        "deps": attr.label_list(
   110            doc = "Direct dependencies of the Kustomization",
   111            providers = [KustomizeInfo],
   112        ),
   113        "images": attr.label_keyed_string_dict(
   114            doc = "Image references present in the srcs of this Kustomization paired with their container_push targets",
   115            providers = [OCIPushInfo],
   116        ),
   117        "kustomization_yaml": attr.label(
   118            doc = "Name of the file containing the Kustomization",
   119            allow_single_file = True,
   120            mandatory = True,
   121        ),
   122        "srcs": attr.label_list(
   123            doc = "YAML files included in this Kustomization",
   124            allow_files = True,
   125        ),
   126        "_go_helper": attr.label(
   127            default = Label("//hack/build/rules/kustomize:kustomize_bin"),
   128            executable = True,
   129            cfg = "exec",
   130        ),
   131        "_kustomize": attr.label(
   132            default = Label("//hack/tools:kustomize"),
   133            allow_single_file = True,
   134            executable = True,
   135            cfg = "exec",
   136        ),
   137    },
   138    executable = True,
   139)
   140
   141def _kustomization_push_impl(ctx):
   142    # If any images are found, leverage OCIPushInfo for updated references.
   143    image_labels = ctx.attr.kustomization[KustomizeInfo].image_labels
   144
   145    pushers = []
   146
   147    runfiles = ctx.runfiles()
   148    for image in image_labels:
   149        runfiles = runfiles.merge(image[OCIPushInfo].runfiles)
   150        pushers.append(image[OCIPushInfo].pusher)
   151
   152    # Join all pusher executables collected
   153    push_commands = "\n".join([pusher.short_path for pusher in pushers])
   154
   155    # Script that will invoke any pushers
   156    pusher = ctx.actions.declare_file(ctx.label.name)
   157
   158    # Generate script to invoke all pushers & write manifests to stdout
   159    # The script changes the directory to that which contains the kustomized manifests
   160    ctx.actions.write(
   161        output = pusher,
   162        content = """#!/usr/bin/env bash
   163{pushers}
   164""".format(
   165            pushers = push_commands,
   166        ),
   167        is_executable = True,
   168    )
   169    return [
   170        DefaultInfo(
   171            runfiles = runfiles,
   172            executable = pusher,
   173        ),
   174    ]
   175
   176_kustomization_push = rule(
   177    implementation = _kustomization_push_impl,
   178    attrs = {
   179        "kustomization": attr.label(
   180            doc = "YAML files included in this Kustomization",
   181            providers = [KustomizeInfo],
   182            allow_files = True,
   183        ),
   184    },
   185    executable = True,
   186)
   187
   188def kustomization(
   189        name,
   190        kustomization_yaml,
   191        srcs = None,
   192        deps = None,
   193        images = {},
   194        **kwargs):
   195    """Creates a kustomization from a source files and other kustomization rules as dependencies.
   196
   197    The kustomization macro takes inputs and creats a _kustomization rule that generates
   198    the resolved manifests of the kustomization and any other dependent kustomizations.
   199
   200    The macro also generates a _kustomization_push rule if any image resolutions are included
   201    in the _kustomization generated by a macro. The push rule can be used to push any
   202    images to GAR.
   203
   204    Args:
   205        name:                 name of the generated kustomization.
   206                              Gazelle defaults this to the name of the bazel package
   207        srcs:                 source files to be used in the kustomization
   208        deps:                 a list of labels pointing to other _kustomization rules
   209        images:               a dict of label to GAR url key: vals that can be used to resolve the
   210                              digest/pusher of a container_push target
   211        kustomization_yaml:   the kustomization.yaml source file for the kustomization
   212        **kwargs:             kwargs
   213    """
   214    forwarded_args = propagate_common_rule_attributes(kwargs)
   215
   216    # Build the kustomization
   217    _kustomization(
   218        name = name,
   219        srcs = srcs,
   220        deps = deps,
   221        images = images,
   222        kustomization_yaml = kustomization_yaml,
   223        **forwarded_args
   224    )
   225
   226    if len(images) > 0:
   227        # Add the pusher
   228        _kustomization_push(
   229            name = "{0}_push".format(name),
   230            kustomization = name,
   231            **forwarded_args
   232        )
   233
   234    return

View as plain text