Skip to content

Commit

Permalink
Add launcher,launcher_args attrs to container_image (#616)
Browse files Browse the repository at this point in the history
* Add launcher,launcher_args attrs to container_image

* Add tests for 'launcher,launcher_args' attrs of container_image rule.

* Better document `container_image.launcher` restrictions.
  • Loading branch information
ceason authored and nlopezgi committed Dec 17, 2018
1 parent f6664b6 commit 9fcb3a7
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 2 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1798,6 +1798,25 @@ container_image(name, base, data_path, directory, files, legacy_repository_namin
syntax, e.g. <code>foo{BUILD_USER}bar</code>.</p>
</td>
</tr>
<tr>
<td><code>launcher</code></td>
<td>
<p><code>Label; optional</code></p>
<p>If present, prefix the image's ENTRYPOINT with this file.
Note that the launcher should be a container-compatible (OS & Arch)
single executable file without any runtime dependencies (as none
of its runfiles will be included in the image).
</p>
</td>
</tr>
<tr>
<td><code>launcher_args</code></td>
<td>
<p><code>String list; optional</code></p>
<p>Optional arguments for the <code>launcher</code> attribute.
Only valid when <code>launcher</code> is specified.</p>
</td>
</tr>
</tbody>
</table>

Expand Down
7 changes: 7 additions & 0 deletions container/create_image_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
choices=['linux', 'windows'],
help=('Operating system to create docker image for, e.g. {linux}'))

parser.add_argument('--entrypoint_prefix', action='append', default=[],
help='Prefix the "Entrypoint" with the specified arguments.')

_PROCESSOR_ARCHITECTURE = 'amd64'

def KeyValueToDict(pair):
Expand Down Expand Up @@ -195,6 +198,10 @@ def Stamp(inp):
args.null_entrypoint == "True"):
del (output['config']['Entrypoint'])

if args.entrypoint_prefix:
output['config']['Entrypoint'] = (args.entrypoint_prefix +
output['config'].get('Entrypoint', []))

with open(args.output, 'w') as fp:
json.dump(output, fp, sort_keys=True)
fp.write('\n')
Expand Down
15 changes: 15 additions & 0 deletions container/image.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,14 @@ def _image_config(
args += ["--stamp-info-file=%s" % f.path for f in stamp_inputs]
inputs += stamp_inputs

if ctx.attr.launcher_args and not ctx.attr.launcher:
fail("launcher_args does nothing when launcher is not specified.", attr = "launcher_args")
if ctx.attr.launcher:
args += [
"--entrypoint_prefix=%s" % x
for x in ["/" + ctx.file.launcher.basename] + ctx.attr.launcher_args
]

ctx.actions.run(
executable = ctx.executable.create_image_config,
arguments = args,
Expand Down Expand Up @@ -302,6 +310,11 @@ def _impl(
legacy_run_behavior = ctx.attr.base[ImageInfo].legacy_run_behavior
docker_run_flags = ctx.attr.base[ImageInfo].docker_run_flags

if ctx.attr.launcher:
if not file_map:
file_map = {}
file_map["/" + ctx.file.launcher.basename] = ctx.file.launcher

# composite a layer from the container_image rule attrs,
image_layer = _layer.implementation(
ctx = ctx,
Expand Down Expand Up @@ -457,6 +470,8 @@ _attrs = dict(_layer.attrs.items() + {
"layers": attr.label_list(providers = [LayerInfo]),
"repository": attr.string(default = "bazel"),
"stamp": attr.bool(default = False),
"launcher": attr.label(allow_single_file = True),
"launcher_args": attr.string_list(default = []),
# Implicit/Undocumented dependencies.
"label_files": attr.label_list(
allow_files = True,
Expand Down
17 changes: 17 additions & 0 deletions testdata/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,23 @@ go_image(
],
)

load("@io_bazel_rules_go//go:def.bzl", "go_binary")

go_binary(
name = "launcher",
srcs = ["launcher_main.go"],
goarch = "amd64",
goos = "linux",
pure = "on",
)

container_image(
name = "launcher_image",
base = ":go_image",
launcher = ":launcher",
launcher_args = ["-env=CUSTOM_MESSAGE=Launched via launcher!"],
)

load("//rust:image.bzl", "rust_image")

rust_image(
Expand Down
46 changes: 46 additions & 0 deletions testdata/launcher_main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file is used to test the launcher attr of container_image
package main

import (
"flag"
"fmt"
"os"
"syscall"
)

func main() {
var extraEnv stringSlice
flag.Var(&extraEnv, "env", "Append to the environment of the launched binary. May be specified multiple times. (eg --env=VAR_NAME=value)")
flag.Parse()
envv := append(os.Environ(), extraEnv...)
argv := flag.Args()
err := syscall.Exec(argv[0], argv, envv)
if err != nil {
panic(err)
}
}

type stringSlice []string

func (i *stringSlice) String() string {
return fmt.Sprintf("%s", *i)
}

func (i *stringSlice) Set(v string) error {
*i = append(*i, v)
return nil
}
11 changes: 9 additions & 2 deletions testdata/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@
// Package main tells the linter to shut up.
package main

import "fmt"
import (
"fmt"
"os"
)

func main() {
fmt.Println("Hello, world!")
message := "Hello, world!"
if v, ok := os.LookupEnv("CUSTOM_MESSAGE"); ok {
message = v
}
fmt.Println(message)
}
7 changes: 7 additions & 0 deletions testing/e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ function test_cc_image_wrapper() {
EXPECT_CONTAINS "$(bazel run "$@" testdata:cc_image_wrapper)" "Hello World"
}

function test_launcher_image() {
cd "${ROOT}"
clear_docker
EXPECT_CONTAINS "$(bazel run "$@" testdata:launcher_image)" "Launched via launcher!"
}

function test_go_image() {
cd "${ROOT}"
clear_docker
Expand Down Expand Up @@ -517,3 +523,4 @@ test_rust_image -c dbg
test_nodejs_image -c opt
test_nodejs_image -c dbg
test_container_push
test_launcher_image

0 comments on commit 9fcb3a7

Please sign in to comment.