Skip to content

Commit

Permalink
Merge pull request #7483 from fejta/config
Browse files Browse the repository at this point in the history
Create a k8s_configmap() rule, use in testgrid
  • Loading branch information
k8s-ci-robot authored Apr 3, 2018
2 parents dfc62d1 + 9405cb8 commit 076e8cd
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 23 deletions.
1 change: 1 addition & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ filegroup(
srcs = [
":package-srcs",
"//boskos:all-srcs",
"//def:all-srcs",
"//experiment:all-srcs",
"//gcsweb/cmd/gcsweb:all-srcs",
"//gcsweb/pkg/version:all-srcs",
Expand Down
16 changes: 16 additions & 0 deletions def/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)

filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//def/configmap:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
96 changes: 96 additions & 0 deletions def/configmap.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright 2018 The Kubernetes Authors.
#
# 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.

load("@io_bazel_rules_k8s//k8s:object.bzl", "k8s_object")

def _impl(ctx):
args = [
"--output=%s" % ctx.outputs.output.path,
"--name=%s" % ctx.label.name[:-len(".generated-yaml")],
"--namespace=%s" % ctx.attr.namespace,
]
for key, value in ctx.attr.labels.items():
args.append("--label=%s=%s" % (key, value))

# Build the {string: label} dict
targets = {}
for i, t in enumerate(ctx.attr.data_strings):
targets[t] = ctx.attr.data_labels[i]

for name, label in ctx.attr.data.items():
fp = targets[label].files.to_list()[0].path
args.append(ctx.expand_location("--data=%s=%s" % (name, fp)))
ctx.actions.run(
inputs=ctx.files.data_labels,
outputs=[ctx.outputs.output],
executable=ctx.executable._writer,
arguments=args,
progress_message="creating %s..." % ctx.outputs.output.short_path,
)

# See https://docs.bazel.build/versions/master/skylark/rules.html
_k8s_configmap = rule(
implementation = _impl,
attrs={
# TODO(fejta): switch to string_keyed_label_dict once it exists
"data": attr.string_dict(mandatory=True, allow_empty=False),
"namespace": attr.string(),
"cluster": attr.string(),
"labels": attr.string_dict(),
"output": attr.output(mandatory=True),
# private attrs, the data_* are used to create a {string: label} dict
"data_strings": attr.string_list(mandatory=True),
"data_labels": attr.label_list(mandatory=True, allow_files=True),
"_writer": attr.label(executable=True, cfg="host", allow_files=True,
default=Label("//def/configmap")),
},
)

# A macro to create a configmap object as well as rules to manage it.
#
# Usage:
# k8s_configmap("something", data={"foo": "//path/to/foo.json"})
#
# This is roughly equivalent to:
# kubectl create configmap something --from-file=foo=path/to/foo.json
# Supports cluster=kubectl_context, namespace="blah", labels={"app": "fancy"}
# as well as any args k8s_object supports.
#
# Generates a k8s_object(kind="configmap") with the generated template.
#
# See also:
# * https://docs.bazel.build/versions/master/skylark/macros.html
# * https://github.com/bazelbuild/rules_k8s#k8s_object
def k8s_configmap(name, data=None, namespace='', labels=None, cluster='', **kw):
# Create the non-duplicated list of data values
_data = data or {}
_data_targets = {v: None for v in _data.values()}.keys()
# Create the rule to generate the configmap
_k8s_configmap(
name = name + ".generated-yaml",
data=data,
namespace=namespace,
labels=labels,
output=name + "_configmap.yaml",
data_strings=_data_targets,
data_labels=_data_targets,
)
# Run k8s_object with the generated configmap
k8s_object(
name = name,
kind = "configmap",
template = name + "_configmap.yaml",
cluster = cluster,
namespace = namespace,
**kw)
32 changes: 32 additions & 0 deletions def/configmap/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_library(
name = "go_default_library",
srcs = ["main.go"],
importpath = "k8s.io/test-infra/def/configmap",
visibility = ["//visibility:private"],
deps = [
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
],
)

go_binary(
name = "configmap",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)

filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)

filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
130 changes: 130 additions & 0 deletions def/configmap/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
Copyright 2018 The Kubernetes Authors.
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.
*/

// configmap will write a configmap to --output from --data=name=/path/to/source
package main

import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"strings"

"github.com/ghodss/yaml"
"k8s.io/api/core/v1"
)

type options struct {
data multiKeyValue
labels multiKeyValue
name string
namespace string
output string
}

// multiKeyValue allows --key=value --key=value
type multiKeyValue map[string]string

func (mkv *multiKeyValue) String() string {
var b bytes.Buffer
if mkv == nil {
return ""
}
for k, v := range *mkv {
if b.Len() > 0 {
b.WriteString(",")
}
fmt.Fprintf(&b, "%s=%s", k, v)
}
return b.String()
}

func (mkv *multiKeyValue) Set(v string) error {
p := strings.SplitN(v, "=", 2)
if len(p) != 2 {
return fmt.Errorf("%s does not match label=value", v)
}
if mkv == nil {
mkv = &multiKeyValue{
p[0]: p[1],
}
} else {
(*mkv)[p[0]] = p[1]
}
return nil
}

func flags() *options {
opt := options{
data: multiKeyValue{},
labels: multiKeyValue{},
}
flag.StringVar(&opt.output, "output", "", "Write configmap here instead of stdout")
flag.StringVar(&opt.name, "name", "", "Name of resource")
flag.StringVar(&opt.namespace, "namespace", "", "Namespace for resource")
flag.Var(&opt.labels, "label", "Add a key=value label (repeat flag)")
flag.Var(&opt.data, "data", "Add a key=/path/to/file configmap source (repeat flag)")
flag.Parse()
return &opt
}

func buildConfigMap(name, namespace string, labels map[string]string, data map[string]string) (*v1.ConfigMap, error) {

var cm v1.ConfigMap
cm.TypeMeta.Kind = "ConfigMap"
cm.TypeMeta.APIVersion = "v1"
cm.ObjectMeta.Name = name
cm.ObjectMeta.Namespace = namespace
cm.ObjectMeta.Labels = labels
if len(data) > 0 {
cm.Data = map[string]string{}
for key, value := range data {
buf, err := ioutil.ReadFile(value)
if err != nil {
wd, _ := os.Getwd()
return nil, fmt.Errorf("could not read %s/%s: %v", wd, value, err)
}
cm.Data[key] = string(buf)
}
}
return &cm, nil
}

func main() {
opt := flags()
if opt.name == "" {
log.Fatal("Non-empty --name required")
}
cm, err := buildConfigMap(opt.name, opt.namespace, opt.labels, opt.data)
if err != nil {
log.Fatalf("Failed to create %s: %v", opt.name, err)
}
buf, err := yaml.Marshal(cm)
if err != nil {
log.Fatalf("Failed to serialize %s: %v", opt.name, err)
}
if opt.output == "" {
fmt.Print(string(buf))
return
}
err = ioutil.WriteFile(opt.output, buf, 0644)
if err != nil {
log.Fatalf("Failed to write %s: %v", opt.output, err)
}
}
26 changes: 11 additions & 15 deletions testgrid/cluster/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@

load("@io_bazel_rules_k8s//k8s:object.bzl", "k8s_object")
load("@io_bazel_rules_k8s//k8s:objects.bzl", "k8s_objects")
load("//def:configmap.bzl", "k8s_configmap")

k8s_objects(
name = "dev",
objects = [
":config",
":testgrid-config",
":configurator",
":updater",
],
Expand Down Expand Up @@ -54,22 +55,17 @@ k8s_object(
template = "configurator_deployment.yaml",
)

genrule(
name = "gen-config",
srcs = [
":config_template.yaml",
"//testgrid:config-yaml",
],
outs = ["config_configmap.yaml"],
cmd = "cat $(location :config_template.yaml) > $@ && echo ' config.yaml: |' >> $@ && cat $(location //testgrid:config-yaml) | sed -e 's/^/ /' >> $@",
)

k8s_object(
name = "config",
k8s_configmap(
name = "testgrid-config",
cluster = CLUSTER,
kind = "configmap",
data = {
"config.yaml": "//testgrid:config-yaml",
},
labels = {
"component": "config",
"app": "testgrid",
},
namespace = "testgrid",
template = "config_configmap.yaml",
)

filegroup(
Expand Down
8 changes: 0 additions & 8 deletions testgrid/cluster/config_template.yaml

This file was deleted.

0 comments on commit 076e8cd

Please sign in to comment.