Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 deletions

View File

@ -11,14 +11,15 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//test/images/clusterapi-tester:all-srcs",
"//test/images/apparmor-loader:all-srcs",
"//test/images/crd-conversion-webhook:all-srcs",
"//test/images/echoserver:all-srcs",
"//test/images/entrypoint-tester:all-srcs",
"//test/images/fakegitserver:all-srcs",
"//test/images/goproxy:all-srcs",
"//test/images/liveness:all-srcs",
"//test/images/logs-generator:all-srcs",
"//test/images/metadata-concealment:all-srcs",
"//test/images/mounttest:all-srcs",
"//test/images/n-way-http:all-srcs",
"//test/images/net:all-srcs",
"//test/images/netexec:all-srcs",
"//test/images/nettest:all-srcs",
@ -29,6 +30,7 @@ filegroup(
"//test/images/port-forward-tester:all-srcs",
"//test/images/porter:all-srcs",
"//test/images/resource-consumer:all-srcs",
"//test/images/sample-apiserver:all-srcs",
"//test/images/serve-hostname:all-srcs",
"//test/images/test-webserver:all-srcs",
"//test/images/webhook:all-srcs",

View File

@ -17,7 +17,7 @@ include ../../hack/make-rules/Makefile.manifest
REGISTRY ?= gcr.io/kubernetes-e2e-test-images
GOARM=7
QEMUVERSION=v2.9.1
GOLANG_VERSION=1.10.3
GOLANG_VERSION=1.11.2
export
ifndef WHAT

View File

@ -0,0 +1,4 @@
amd64=alpine:3.8
arm=arm32v6/alpine:3.8
arm64=arm64v8/alpine:3.8
ppc64le=ppc64le/alpine:3.8

View File

@ -0,0 +1,29 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = ["loader.go"],
importpath = "k8s.io/kubernetes/test/images/apparmor-loader",
visibility = ["//visibility:private"],
deps = ["//vendor/k8s.io/klog:go_default_library"],
)
go_binary(
name = "apparmor-loader",
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"],
)

View File

@ -13,5 +13,14 @@
# limitations under the License.
FROM BASEIMAGE
COPY n-way-http /
ENTRYPOINT ["/n-way-http"]
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
RUN apk add apparmor libapparmor --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ --allow-untrusted
ADD loader /usr/bin/loader
ENTRYPOINT ["/usr/bin/loader", "-logtostderr", "-v=2"]
# Default directory to watch.
CMD ["/profiles"]

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
SRCS=goproxy
SRCS=loader
ARCH ?= amd64
TARGET ?= $(CURDIR)
GOLANG_VERSION ?= latest

View File

@ -0,0 +1,66 @@
# AppArmor Profile Loader
This is a small proof-of-concept daemon to demonstrate how AppArmor profiles can be loaded onto
nodes of a Kubernetes cluster. It is not considered production ready, nor will it be supported as a
long-term solution.
## Running the AppArmor Profile Loader
The [example-daemon.yaml](example-daemon.yaml) provides an example manifest for running the loader
as a cluster DaemonSet. In this example, the loader runs in a DaemonSet pod on each node in the
cluster, and periodically (every 30 seconds) polls for new profiles in the `apparmor-profiles`
configmap ([example manifest](example-configmap.yaml)). It is recommended to run the Daemon and
ConfigMap in a separate, restricted namespace:
$ kubectl create -f example-namespace.yaml
$ kubectl create -f example-configmap.yaml # Includes the k8s-nginx profile
$ kubectl create -f example-daemon.yaml
Check that the profile was loaded:
$ POD=$(kubectl --namespace apparmor get pod -o jsonpath="{.items[0].metadata.name}")
$ kubectl --namespace apparmor logs $POD
I0829 22:48:24.917263 1 loader.go:139] Polling /profiles every 30s
I0829 22:48:24.954295 1 loader.go:196] Loading profiles from /profiles/k8s-nginx:
Addition succeeded for "k8s-nginx".
I0829 22:48:24.954328 1 loader.go:100] Successfully loaded profiles: [k8s-nginx]
Trying running a pod with the loaded profile (requires Kubernetes >= v1.4):
$ kubectl create -f example-pod.yaml
# Verify that it's running with the new profile:
$ kubectl exec nginx-apparmor cat /proc/1/attr/current
k8s-nginx (enforce)
$ kubectl exec nginx-apparmor touch /tmp/foo
touch: cannot touch '/tmp/foo': Permission denied
error: error executing remote command: command terminated with non-zero exit code: Error executing in Docker Container: 1
### Standalone
The loader go binary can also be run as a standalone binary on the host. It must be run with root
privileges:
sudo loader -logtostderr /path/to/profile/dir
Alternatively, it can be run with the supplied loader docker image:
PROFILES_PATH=/path/to/profile/dir
sudo docker run \
--privileged \
--detach=true \
--volume=/sys:/sys:ro \
--volume=/etc/apparmor.d:/etc/apparmor.d:ro \
--volume=$PROFILES_PATH:/profiles:ro \
--name=aa-loader \
google/apparmor-loader:latest
## Build the loader
The loader binary is a simple go program, and can be built with `make all-push WHAT=apparmor-loader`
(from test/images).
## Limitations
The loader will not unload profiles that are removed, and will not update profiles that are changed.
This is by design, since there are nuanced issues with changing profiles that are in use.

View File

@ -0,0 +1,76 @@
# An example ConfigMap demonstrating how profiles can be stored as Kubernetes objects, and loaded by
# the apparmor-loader DaemonSet.
apiVersion: v1
kind: ConfigMap
metadata:
name: apparmor-profiles
namespace: apparmor
data:
# Filename k8s-nginx maps to the definition of the nginx profile.
k8s-nginx: |-
#include <tunables/global>
# From https://github.com/jfrazelle/bane/blob/master/docker-nginx-sample
profile k8s-nginx flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network inet tcp,
network inet udp,
network inet icmp,
deny network raw,
deny network packet,
file,
umount,
deny /bin/** wl,
deny /boot/** wl,
deny /dev/** wl,
deny /etc/** wl,
deny /home/** wl,
deny /lib/** wl,
deny /lib64/** wl,
deny /media/** wl,
deny /mnt/** wl,
deny /opt/** wl,
deny /proc/** wl,
deny /root/** wl,
deny /sbin/** wl,
deny /srv/** wl,
deny /tmp/** wl,
deny /sys/** wl,
deny /usr/** wl,
audit /** w,
/var/run/nginx.pid w,
/usr/sbin/nginx ix,
deny /bin/dash mrwklx,
deny /bin/sh mrwklx,
deny /usr/bin/top mrwklx,
capability chown,
capability dac_override,
capability setuid,
capability setgid,
capability net_bind_service,
deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx,
deny @{PROC}/sysrq-trigger rwklx,
deny @{PROC}/mem rwklx,
deny @{PROC}/kmem rwklx,
deny @{PROC}/kcore rwklx,
deny mount,
deny /sys/[^f]*/** wklx,
deny /sys/f[^s]*/** wklx,
deny /sys/fs/[^c]*/** wklx,
deny /sys/fs/c[^g]*/** wklx,
deny /sys/fs/cg[^r]*/** wklx,
deny /sys/firmware/efi/efivars/** rwklx,
deny /sys/kernel/security/** rwklx,
}

View File

@ -0,0 +1,50 @@
# The example DaemonSet demonstrating how the profile loader can be deployed onto a cluster to
# automatically load AppArmor profiles from a ConfigMap.
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: apparmor-loader
# Namespace must match that of the ConfigMap.
namespace: apparmor
spec:
template:
metadata:
name: apparmor-loader
labels:
daemon: apparmor-loader
spec:
containers:
- name: apparmor-loader
image: google/apparmor-loader:latest
args:
# Tell the loader to pull the /profiles directory every 30 seconds.
- -poll
- 30s
- /profiles
securityContext:
# The loader requires root permissions to actually load the profiles.
privileged: true
volumeMounts:
- name: sys
mountPath: /sys
readOnly: true
- name: apparmor-includes
mountPath: /etc/apparmor.d
readOnly: true
- name: profiles
mountPath: /profiles
readOnly: true
volumes:
# The /sys directory must be mounted to interact with the AppArmor module.
- name: sys
hostPath:
path: /sys
# The /etc/apparmor.d directory is required for most apparmor include templates.
- name: apparmor-includes
hostPath:
path: /etc/apparmor.d
# Map in the profile data.
- name: profiles
configMap:
name: apparmor-profiles

View File

@ -0,0 +1,6 @@
# The example Namespace used by other example objects.
apiVersion: v1
kind: Namespace
metadata:
name: apparmor

View File

@ -0,0 +1,19 @@
# The example Pod utilizing the profile loaded by the sample daemon.
apiVersion: v1
kind: Pod
metadata:
name: nginx-apparmor
# Note that the Pod does not need to be in the same namespace as the loader.
labels:
app: nginx
annotations:
# Tell Kubernetes to apply the AppArmor profile "k8s-nginx".
# Note that this is ignored if the Kubernetes node is not running version 1.4 or greater.
container.apparmor.security.beta.kubernetes.io/nginx: localhost/k8s-nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80

View File

@ -0,0 +1,260 @@
/*
Copyright 2015 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.
*/
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"
"k8s.io/klog"
)
var (
// The directories to load profiles from.
dirs []string
poll = flag.Duration("poll", -1, "Poll the directories for new profiles with this interval. Values < 0 disable polling, and exit after loading the profiles.")
)
const (
parser = "apparmor_parser"
apparmorfs = "/sys/kernel/security/apparmor"
)
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [FLAG]... [PROFILE_DIR]...\n", os.Args[0])
fmt.Fprintf(os.Stderr, "Load the AppArmor profiles specified in the PROFILE_DIR directories.\n")
flag.PrintDefaults()
}
flag.Parse()
dirs = flag.Args()
if len(dirs) == 0 {
klog.Errorf("Must specify at least one directory.")
flag.Usage()
os.Exit(1)
}
// Check that the required parser binary is found.
if _, err := exec.LookPath(parser); err != nil {
klog.Exitf("Required binary %s not found in PATH", parser)
}
// Check that loaded profiles can be read.
if _, err := getLoadedProfiles(); err != nil {
klog.Exitf("Unable to access apparmor profiles: %v", err)
}
if *poll < 0 {
runOnce()
} else {
pollForever()
}
}
// No polling: run once and exit.
func runOnce() {
if success, newProfiles := loadNewProfiles(); !success {
if len(newProfiles) > 0 {
klog.Exitf("Not all profiles were successfully loaded. Loaded: %v", newProfiles)
} else {
klog.Exit("Error loading profiles.")
}
} else {
if len(newProfiles) > 0 {
klog.Infof("Successfully loaded profiles: %v", newProfiles)
} else {
klog.Warning("No new profiles found.")
}
}
}
// Poll the directories indefinitely.
func pollForever() {
klog.V(2).Infof("Polling %s every %s", strings.Join(dirs, ", "), poll.String())
pollFn := func() {
_, newProfiles := loadNewProfiles()
if len(newProfiles) > 0 {
klog.V(2).Infof("Successfully loaded profiles: %v", newProfiles)
}
}
pollFn() // Run immediately.
ticker := time.NewTicker(*poll)
for range ticker.C {
pollFn()
}
}
func loadNewProfiles() (success bool, newProfiles []string) {
loadedProfiles, err := getLoadedProfiles()
if err != nil {
klog.Errorf("Error reading loaded profiles: %v", err)
return false, nil
}
success = true
for _, dir := range dirs {
infos, err := ioutil.ReadDir(dir)
if err != nil {
klog.Warningf("Error reading %s: %v", dir, err)
success = false
continue
}
for _, info := range infos {
path := filepath.Join(dir, info.Name())
// If directory, or symlink to a directory, skip it.
resolvedInfo, err := resolveSymlink(dir, info)
if err != nil {
klog.Warningf("Error resolving symlink: %v", err)
continue
}
if resolvedInfo.IsDir() {
// Directory listing is shallow.
klog.V(4).Infof("Skipping directory %s", path)
continue
}
klog.V(4).Infof("Scanning %s for new profiles", path)
profiles, err := getProfileNames(path)
if err != nil {
klog.Warningf("Error reading %s: %v", path, err)
success = false
continue
}
if unloadedProfiles(loadedProfiles, profiles) {
if err := loadProfiles(path); err != nil {
klog.Errorf("Could not load profiles: %v", err)
success = false
continue
}
// Add new profiles to list of loaded profiles.
newProfiles = append(newProfiles, profiles...)
for _, profile := range profiles {
loadedProfiles[profile] = true
}
}
}
}
return success, newProfiles
}
func getProfileNames(path string) ([]string, error) {
cmd := exec.Command(parser, "--names", path)
stderr := &bytes.Buffer{}
cmd.Stderr = stderr
out, err := cmd.Output()
if err != nil {
if stderr.Len() > 0 {
klog.Warning(stderr.String())
}
return nil, fmt.Errorf("error reading profiles from %s: %v", path, err)
}
trimmed := strings.TrimSpace(string(out)) // Remove trailing \n
return strings.Split(trimmed, "\n"), nil
}
func unloadedProfiles(loadedProfiles map[string]bool, profiles []string) bool {
for _, profile := range profiles {
if !loadedProfiles[profile] {
return true
}
}
return false
}
func loadProfiles(path string) error {
cmd := exec.Command(parser, "--verbose", path)
stderr := &bytes.Buffer{}
cmd.Stderr = stderr
out, err := cmd.Output()
klog.V(2).Infof("Loading profiles from %s:\n%s", path, out)
if err != nil {
if stderr.Len() > 0 {
klog.Warning(stderr.String())
}
return fmt.Errorf("error loading profiles from %s: %v", path, err)
}
return nil
}
// If the given fileinfo is a symlink, return the FileInfo of the target. Otherwise, return the
// given fileinfo.
func resolveSymlink(basePath string, info os.FileInfo) (os.FileInfo, error) {
if info.Mode()&os.ModeSymlink == 0 {
// Not a symlink.
return info, nil
}
fpath := filepath.Join(basePath, info.Name())
resolvedName, err := filepath.EvalSymlinks(fpath)
if err != nil {
return nil, fmt.Errorf("error resolving symlink %s: %v", fpath, err)
}
resolvedInfo, err := os.Stat(resolvedName)
if err != nil {
return nil, fmt.Errorf("error calling stat on %s: %v", resolvedName, err)
}
return resolvedInfo, nil
}
// TODO: This is copied from k8s.io/kubernetes/pkg/security/apparmor.getLoadedProfiles.
// Refactor that method to expose it in a reusable way, and delete this version.
func getLoadedProfiles() (map[string]bool, error) {
profilesPath := path.Join(apparmorfs, "profiles")
profilesFile, err := os.Open(profilesPath)
if err != nil {
return nil, fmt.Errorf("failed to open %s: %v", profilesPath, err)
}
defer profilesFile.Close()
profiles := map[string]bool{}
scanner := bufio.NewScanner(profilesFile)
for scanner.Scan() {
profileName := parseProfileName(scanner.Text())
if profileName == "" {
// Unknown line format; skip it.
continue
}
profiles[profileName] = true
}
return profiles, nil
}
// The profiles file is formatted with one profile per line, matching a form:
// namespace://profile-name (mode)
// profile-name (mode)
// Where mode is {enforce, complain, kill}. The "namespace://" is only included for namespaced
// profiles. For the purposes of Kubernetes, we consider the namespace part of the profile name.
func parseProfileName(profileLine string) string {
modeIndex := strings.IndexRune(profileLine, '(')
if modeIndex < 0 {
return ""
}
return strings.TrimSpace(profileLine[:modeIndex])
}

View File

@ -1,5 +0,0 @@
amd64=busybox
arm=arm32v6/busybox
arm64=arm64v8/busybox
ppc64le=ppc64le/busybox
s390x=s390x/busybox

View File

@ -1,36 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "clusterapi-tester",
embed = [":go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["clusterapi-tester.go"],
importpath = "k8s.io/kubernetes/test/images/clusterapi-tester",
deps = [
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,64 +0,0 @@
/*
Copyright 2014 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.
*/
// A simple pod that first lists all nodes/services through the Kubernetes
// api, then serves a 200 on /healthz.
package main
import (
"log"
"fmt"
"net/http"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
restclient "k8s.io/client-go/rest"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
)
func main() {
cc, err := restclient.InClusterConfig()
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
kubeClient, err := clientset.NewForConfig(cc)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
listAll := metav1.ListOptions{}
nodes, err := kubeClient.Core().Nodes().List(listAll)
if err != nil {
log.Fatalf("Failed to list nodes: %v", err)
}
log.Printf("Nodes:")
for _, node := range nodes.Items {
log.Printf("\t%v", node.Name)
}
services, err := kubeClient.Core().Services(metav1.NamespaceDefault).List(listAll)
if err != nil {
log.Fatalf("Failed to list services: %v", err)
}
log.Printf("Services:")
for _, svc := range services.Items {
log.Printf("\t%v", svc.Name)
}
log.Printf("Success")
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Ok")
})
log.Fatal(http.ListenAndServe(":8080", nil))
}

View File

@ -1,19 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: clusterapi-tester
spec:
containers:
- image: gcr.io/kubernetes-e2e-test-images/clusterapi-tester-amd64:1.0
name: clusterapi-tester
readinessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 5
failureThreshold: 3
periodSeconds: 10
successThreshold: 1
restartPolicy: OnFailure

View File

@ -0,0 +1,4 @@
amd64=alpine:3.6
arm=arm32v6/alpine:3.6
arm64=arm64v8/alpine:3.6
ppc64le=ppc64le/alpine:3.6

View File

@ -0,0 +1,40 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = [
"config.go",
"main.go",
],
importpath = "k8s.io/kubernetes/test/images/crd-conversion-webhook",
visibility = ["//visibility:private"],
deps = [
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//test/images/crd-conversion-webhook/converter:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
go_binary(
name = "crd-conversion-webhook",
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",
"//test/images/crd-conversion-webhook/converter:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -1,4 +1,4 @@
# Copyright 2016 The Kubernetes Authors.
# 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.
@ -13,5 +13,6 @@
# limitations under the License.
FROM BASEIMAGE
ADD clusterapi-tester /clusterapi-tester
ENTRYPOINT ["/clusterapi-tester"]
ADD crd_conversion_webhook /crd_conversion_webhook
ENTRYPOINT ["/crd_conversion_webhook"]

View File

@ -1,4 +1,4 @@
# Copyright 2016 The Kubernetes Authors.
# 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.
@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
SRCS = clusterapi-tester
SRCS=crd_conversion_webhook
ARCH ?= amd64
TARGET ?= $(CURDIR)
GOLANG_VERSION ?= latest

View File

@ -0,0 +1,11 @@
# Kubernetes External Admission Webhook Test Image
The image tests CustomResourceConversionWebhook. After deploying it to kubernetes cluster,
administrator needs to create a CustomResourceConversion.Webhook
in kubernetes cluster to use remote webhook for conversions.
## Build the code
```bash
make build
```

View File

@ -0,0 +1 @@
1.13rev2

View File

@ -0,0 +1,50 @@
/*
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.
*/
package main
import (
"crypto/tls"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/klog"
)
// Get a clientset with in-cluster config.
func getClient() *kubernetes.Clientset {
config, err := rest.InClusterConfig()
if err != nil {
klog.Fatal(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
klog.Fatal(err)
}
return clientset
}
func configTLS(config Config, clientset *kubernetes.Clientset) *tls.Config {
sCert, err := tls.LoadX509KeyPair(config.CertFile, config.KeyFile)
if err != nil {
klog.Fatal(err)
}
return &tls.Config{
Certificates: []tls.Certificate{sCert},
// TODO: uses mutual tls after we agree on what cert the apiserver should use.
// ClientAuth: tls.RequireAndVerifyClientCert,
}
}

View File

@ -0,0 +1,47 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"example_converter.go",
"framework.go",
],
importpath = "k8s.io/kubernetes/test/images/crd-conversion-webhook/converter",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
"//vendor/bitbucket.org/ww/goautoneg:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["converter_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,97 @@
/*
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.
*/
package converter
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
)
func TestConverter(t *testing.T) {
sampleObj := `kind: ConversionReview
apiVersion: apiextensions.k8s.io/v1beta1
request:
uid: 0000-0000-0000-0000
desiredAPIVersion: stable.example.com/v2
objects:
- apiVersion: stable.example.com/v1
kind: CronTab
metadata:
name: my-new-cron-object
spec:
cronSpec: "* * * * */5"
image: my-awesome-cron-image
hostPort: "localhost:7070"
`
// First try json, it should fail as the data is taml
response := httptest.NewRecorder()
request, err := http.NewRequest("POST", "/convert", strings.NewReader(sampleObj))
if err != nil {
t.Fatal(err)
}
request.Header.Add("Content-Type", "application/json")
ServeExampleConvert(response, request)
convertReview := v1beta1.ConversionReview{}
scheme := runtime.NewScheme()
jsonSerializer := json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false)
if _, _, err := jsonSerializer.Decode(response.Body.Bytes(), nil, &convertReview); err != nil {
t.Fatal(err)
}
if convertReview.Response.Result.Status != v1.StatusFailure {
t.Fatalf("expected the operation to fail when yaml is provided with json header")
} else if !strings.Contains(convertReview.Response.Result.Message, "json parse error") {
t.Fatalf("expected to fail on json parser, but it failed with: %v", convertReview.Response.Result.Message)
}
// Now try yaml, and it should successfully convert
response = httptest.NewRecorder()
request, err = http.NewRequest("POST", "/convert", strings.NewReader(sampleObj))
if err != nil {
t.Fatal(err)
}
request.Header.Add("Content-Type", "application/yaml")
ServeExampleConvert(response, request)
convertReview = v1beta1.ConversionReview{}
yamlSerializer := json.NewYAMLSerializer(json.DefaultMetaFactory, scheme, scheme)
if _, _, err := yamlSerializer.Decode(response.Body.Bytes(), nil, &convertReview); err != nil {
t.Fatalf("cannot decode data: \n %v\n Error: %v", response.Body, err)
}
if convertReview.Response.Result.Status != v1.StatusSuccess {
t.Fatalf("cr conversion failed: %v", convertReview.Response)
}
convertedObj := unstructured.Unstructured{}
if _, _, err := yamlSerializer.Decode(convertReview.Response.ConvertedObjects[0].Raw, nil, &convertedObj); err != nil {
t.Fatal(err)
}
if e, a := "stable.example.com/v2", convertedObj.GetAPIVersion(); e != a {
t.Errorf("expected= %v, actual= %v", e, a)
}
if e, a := "localhost", convertedObj.Object["host"]; e != a {
t.Errorf("expected= %v, actual= %v", e, a)
}
if e, a := "7070", convertedObj.Object["port"]; e != a {
t.Errorf("expected= %v, actual= %v", e, a)
}
}

View File

@ -0,0 +1,79 @@
/*
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.
*/
package converter
import (
"fmt"
"strings"
"k8s.io/klog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func convertExampleCRD(Object *unstructured.Unstructured, toVersion string) (*unstructured.Unstructured, metav1.Status) {
klog.V(2).Info("converting crd")
convertedObject := Object.DeepCopy()
fromVersion := Object.GetAPIVersion()
if toVersion == fromVersion {
return nil, statusErrorWithMessage("conversion from a version to itself should not call the webhook: %s", toVersion)
}
switch Object.GetAPIVersion() {
case "stable.example.com/v1":
switch toVersion {
case "stable.example.com/v2":
hostPort, ok := convertedObject.Object["hostPort"]
if ok {
delete(convertedObject.Object, "hostPort")
parts := strings.Split(hostPort.(string), ":")
if len(parts) != 2 {
return nil, statusErrorWithMessage("invalid hostPort value `%v`", hostPort)
}
convertedObject.Object["host"] = parts[0]
convertedObject.Object["port"] = parts[1]
}
default:
return nil, statusErrorWithMessage("unexpected conversion version %q", toVersion)
}
case "stable.example.com/v2":
switch toVersion {
case "stable.example.com/v1":
host, hasHost := convertedObject.Object["host"]
port, hasPort := convertedObject.Object["port"]
if hasHost || hasPort {
if !hasHost {
host = ""
}
if !hasPort {
port = ""
}
convertedObject.Object["hostPort"] = fmt.Sprintf("%s:%s", host, port)
delete(convertedObject.Object, "host")
delete(convertedObject.Object, "port")
}
default:
return nil, statusErrorWithMessage("unexpected conversion version %q", toVersion)
}
default:
return nil, statusErrorWithMessage("unexpected conversion version %q", fromVersion)
}
return convertedObject, statusSucceed()
}

View File

@ -0,0 +1,178 @@
/*
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.
*/
package converter
import (
"bitbucket.org/ww/goautoneg"
"fmt"
"io/ioutil"
"net/http"
"strings"
"k8s.io/klog"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
)
// convertFunc is the user defined function for any conversion. The code in this file is a
// template that can be use for any CR conversion given this function.
type convertFunc func(Object *unstructured.Unstructured, version string) (*unstructured.Unstructured, metav1.Status)
// conversionResponseFailureWithMessagef is a helper function to create an AdmissionResponse
// with a formatted embedded error message.
func conversionResponseFailureWithMessagef(msg string, params ...interface{}) *v1beta1.ConversionResponse {
return &v1beta1.ConversionResponse{
Result: metav1.Status{
Message: fmt.Sprintf(msg, params...),
Status: metav1.StatusFailure,
},
}
}
func statusErrorWithMessage(msg string, params ...interface{}) metav1.Status {
return metav1.Status{
Message: fmt.Sprintf(msg, params...),
Status: metav1.StatusFailure,
}
}
func statusSucceed() metav1.Status {
return metav1.Status{
Status: metav1.StatusSuccess,
}
}
// doConversion converts the requested object given the conversion function and returns a conversion response.
// failures will be reported as Reason in the conversion response.
func doConversion(convertRequest *v1beta1.ConversionRequest, convert convertFunc) *v1beta1.ConversionResponse {
var convertedObjects []runtime.RawExtension
for _, obj := range convertRequest.Objects {
cr := unstructured.Unstructured{}
if err := cr.UnmarshalJSON(obj.Raw); err != nil {
klog.Error(err)
return conversionResponseFailureWithMessagef("failed to unmarshall object (%v) with error: %v", string(obj.Raw), err)
}
convertedCR, status := convert(&cr, convertRequest.DesiredAPIVersion)
if status.Status != metav1.StatusSuccess {
klog.Error(status.String())
return &v1beta1.ConversionResponse{
Result: status,
}
}
convertedCR.SetAPIVersion(convertRequest.DesiredAPIVersion)
convertedObjects = append(convertedObjects, runtime.RawExtension{Object: convertedCR})
}
return &v1beta1.ConversionResponse{
ConvertedObjects: convertedObjects,
Result: statusSucceed(),
}
}
func serve(w http.ResponseWriter, r *http.Request, convert convertFunc) {
var body []byte
if r.Body != nil {
if data, err := ioutil.ReadAll(r.Body); err == nil {
body = data
}
}
contentType := r.Header.Get("Content-Type")
serializer := getInputSerializer(contentType)
if serializer == nil {
msg := fmt.Sprintf("invalid Content-Type header `%s`", contentType)
klog.Errorf(msg)
http.Error(w, msg, http.StatusBadRequest)
return
}
klog.V(2).Infof("handling request: %v", body)
convertReview := v1beta1.ConversionReview{}
if _, _, err := serializer.Decode(body, nil, &convertReview); err != nil {
klog.Error(err)
convertReview.Response = conversionResponseFailureWithMessagef("failed to deserialize body (%v) with error %v", string(body), err)
} else {
convertReview.Response = doConversion(convertReview.Request, convert)
convertReview.Response.UID = convertReview.Request.UID
}
klog.V(2).Info(fmt.Sprintf("sending response: %v", convertReview.Response))
// reset the request, it is not needed in a response.
convertReview.Request = &v1beta1.ConversionRequest{}
accept := r.Header.Get("Accept")
outSerializer := getOutputSerializer(accept)
if outSerializer == nil {
msg := fmt.Sprintf("invalid accept header `%s`", accept)
klog.Errorf(msg)
http.Error(w, msg, http.StatusBadRequest)
return
}
err := outSerializer.Encode(&convertReview, w)
if err != nil {
klog.Error(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
// ServeExampleConvert servers endpoint for the example converter defined as convertExampleCRD function.
func ServeExampleConvert(w http.ResponseWriter, r *http.Request) {
serve(w, r, convertExampleCRD)
}
type mediaType struct {
Type, SubType string
}
var scheme = runtime.NewScheme()
var serializers = map[mediaType]runtime.Serializer{
{"application", "json"}: json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false),
{"application", "yaml"}: json.NewYAMLSerializer(json.DefaultMetaFactory, scheme, scheme),
}
func getInputSerializer(contentType string) runtime.Serializer {
parts := strings.SplitN(contentType, "/", 2)
if len(parts) != 2 {
return nil
}
return serializers[mediaType{parts[0], parts[1]}]
}
func getOutputSerializer(accept string) runtime.Serializer {
if len(accept) == 0 {
return serializers[mediaType{"application", "json"}]
}
clauses := goautoneg.ParseAccept(accept)
for _, clause := range clauses {
for k, v := range serializers {
switch {
case clause.Type == k.Type && clause.SubType == k.SubType,
clause.Type == k.Type && clause.SubType == "*",
clause.Type == "*" && clause.SubType == "*":
return v
}
}
}
return nil
}

View File

@ -0,0 +1,52 @@
/*
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.
*/
package main
import (
"flag"
"net/http"
"k8s.io/kubernetes/test/images/crd-conversion-webhook/converter"
)
// Config contains the server (the webhook) cert and key.
type Config struct {
CertFile string
KeyFile string
}
func (c *Config) addFlags() {
flag.StringVar(&c.CertFile, "tls-cert-file", c.CertFile, ""+
"File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated "+
"after server cert).")
flag.StringVar(&c.KeyFile, "tls-private-key-file", c.KeyFile, ""+
"File containing the default x509 private key matching --tls-cert-file.")
}
func main() {
var config Config
config.addFlags()
flag.Parse()
http.HandleFunc("/crdconvert", converter.ServeExampleConvert)
clientset := getClient()
server := &http.Server{
Addr: ":443",
TLSConfig: configTLS(config, clientset),
}
server.ListenAndServeTLS("", "")
}

View File

@ -16,4 +16,4 @@ FROM BASEIMAGE
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
RUN apk add --no-cache bind-tools
RUN apk add --no-cache bind-tools dnsmasq

View File

@ -1 +1 @@
1.0
1.1

View File

@ -0,0 +1,4 @@
amd64=nginx:1.15-alpine
arm=arm32v6/nginx:1.15-alpine
arm64=arm64v8/nginx:1.15-alpine
ppc64le=ppc64le/nginx:1.15-alpine

13
vendor/k8s.io/kubernetes/test/images/echoserver/BUILD generated vendored Normal file
View File

@ -0,0 +1,13 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,27 @@
# Copyright 2017 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.
FROM BASEIMAGE
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
RUN apk add --no-cache openssl nginx-mod-http-lua nginx-mod-http-lua-upstream
RUN mkdir -p /run/nginx
ADD nginx.conf /etc/nginx/nginx.conf
ADD template.lua /usr/local/share/lua/5.1/
ADD README.md README.md
ADD run.sh /usr/local/bin/run.sh
RUN chmod +x /usr/local/bin/run.sh
ENTRYPOINT ["/usr/local/bin/run.sh"]

View File

@ -0,0 +1,10 @@
# Echoserver
This is a simple server that responds with the http headers it received.
Image Versions >= 1.10 support HTTP2 on :8443.
Image Versions >= 1.9 expose HTTPS endpoint on :8443.
Image versions >= 1.4 removes the redirect introduced in 1.3.
Image versions >= 1.3 redirect requests on :80 with `X-Forwarded-Proto: http` to :443.
Image versions > 1.0 run an nginx server, and implement the echoserver using lua in the nginx config.
Image versions <= 1.0 run a python http server instead of nginx, and don't redirect any requests.

View File

@ -0,0 +1 @@
2.2

View File

@ -0,0 +1,103 @@
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_lua_module.so;
load_module modules/ngx_http_lua_upstream_module.so;
events {
worker_connections 1024;
}
env HOSTNAME;
env NODE_NAME;
env POD_NAME;
env POD_NAMESPACE;
env POD_IP;
http {
default_type 'text/plain';
# maximum allowed size of the client request body. By default this is 1m.
# Request with bigger bodies nginx will return error code 413.
# http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size
client_max_body_size 10m;
init_by_lua_block {
local template = require("template")
-- template syntax documented here:
-- https://github.com/bungle/lua-resty-template/blob/master/README.md
tmpl = template.compile([[
Hostname: {{os.getenv("HOSTNAME") or "N/A"}}
Pod Information:
{% if os.getenv("POD_NAME") then %}
node name: {{os.getenv("NODE_NAME") or "N/A"}}
pod name: {{os.getenv("POD_NAME") or "N/A"}}
pod namespace: {{os.getenv("POD_NAMESPACE") or "N/A"}}
pod IP: {{os.getenv("POD_IP") or "N/A"}}
{% else %}
-no pod information available-
{% end %}
Server values:
server_version=nginx: {{ngx.var.nginx_version}} - lua: {{ngx.config.ngx_lua_version}}
Request Information:
client_address={{ngx.var.remote_addr}}
method={{ngx.req.get_method()}}
real path={{ngx.var.request_uri}}
query={{ngx.var.query_string or ""}}
request_version={{ngx.req.http_version()}}
request_scheme={{ngx.var.scheme}}
request_uri={{ngx.var.scheme.."://"..ngx.var.host..":"..ngx.var.server_port..ngx.var.request_uri}}
Request Headers:
{% for i, key in ipairs(keys) do %}
{% local val = headers[key] %}
{% if type(val) == "table" then %}
{% for i = 1,#val do %}
{{key}}={{val[i]}}
{% end %}
{% else %}
{{key}}={{val}}
{% end %}
{% end %}
Request Body:
{{ngx.var.request_body or " -no body in request-"}}
]])
}
server {
# please check the benefits of reuseport https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1
# basically instructs to create an individual listening socket for each worker process (using the SO_REUSEPORT
# socket option), allowing a kernel to distribute incoming connections between worker processes.
listen 8080 default_server reuseport;
listen 8443 default_server ssl http2 reuseport;
ssl_certificate /certs/certificate.crt;
ssl_certificate_key /certs/privateKey.key;
# Replace '_' with your hostname.
server_name _;
# set long keepalive_timeout because some loadbalancer proxies expect the connection
# to remain open for at least ten minutes.
keepalive_timeout 620s;
location / {
lua_need_request_body on;
content_by_lua_block {
ngx.header["Server"] = "echoserver"
local headers = ngx.req.get_headers()
local keys = {}
for key, val in pairs(headers) do
table.insert(keys, key)
end
table.sort(keys)
ngx.say(tmpl({os=os, ngx=ngx, keys=keys, headers=headers}))
}
}
}
}

View File

@ -1,4 +1,6 @@
# Copyright 2016 The Kubernetes Authors.
#!/bin/sh
# 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.
@ -12,14 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM centos:6
echo "Generating self-signed cert"
mkdir -p /certs
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 \
-keyout /certs/privateKey.key \
-out /certs/certificate.crt \
-subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=IT Department/CN=example.com"
ADD install.sh /usr/local/bin/
RUN /usr/local/bin/install.sh
ADD init.sh /usr/local/bin/
ADD index.html /tmp/
RUN chmod 644 /tmp/index.html
EXPOSE 6789/tcp
ENTRYPOINT ["/usr/local/bin/init.sh"]
echo "Starting nginx"
nginx -g "daemon off;"

View File

@ -0,0 +1,509 @@
-- vendored from https://raw.githubusercontent.com/bungle/lua-resty-template/1f9a5c24fc7572dbf5be0b9f8168cc3984b03d24/lib/resty/template.lua
-- only modification: remove / from HTML_ENTITIES to not escape it, and fix the appropriate regex.
--[[
Copyright (c) 2014 - 2017 Aapo Talvensaari
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--]]
local setmetatable = setmetatable
local loadstring = loadstring
local loadchunk
local tostring = tostring
local setfenv = setfenv
local require = require
local capture
local concat = table.concat
local assert = assert
local prefix
local write = io.write
local pcall = pcall
local phase
local open = io.open
local load = load
local type = type
local dump = string.dump
local find = string.find
local gsub = string.gsub
local byte = string.byte
local null
local sub = string.sub
local ngx = ngx
local jit = jit
local var
local _VERSION = _VERSION
local _ENV = _ENV
local _G = _G
local HTML_ENTITIES = {
["&"] = "&amp;",
["<"] = "&lt;",
[">"] = "&gt;",
['"'] = "&quot;",
["'"] = "&#39;",
}
local CODE_ENTITIES = {
["{"] = "&#123;",
["}"] = "&#125;",
["&"] = "&amp;",
["<"] = "&lt;",
[">"] = "&gt;",
['"'] = "&quot;",
["'"] = "&#39;",
["/"] = "&#47;"
}
local VAR_PHASES
local ok, newtab = pcall(require, "table.new")
if not ok then newtab = function() return {} end end
local caching = true
local template = newtab(0, 12)
template._VERSION = "1.9"
template.cache = {}
local function enabled(val)
if val == nil then return true end
return val == true or (val == "1" or val == "true" or val == "on")
end
local function trim(s)
return gsub(gsub(s, "^%s+", ""), "%s+$", "")
end
local function rpos(view, s)
while s > 0 do
local c = sub(view, s, s)
if c == " " or c == "\t" or c == "\0" or c == "\x0B" then
s = s - 1
else
break
end
end
return s
end
local function escaped(view, s)
if s > 1 and sub(view, s - 1, s - 1) == "\\" then
if s > 2 and sub(view, s - 2, s - 2) == "\\" then
return false, 1
else
return true, 1
end
end
return false, 0
end
local function readfile(path)
local file = open(path, "rb")
if not file then return nil end
local content = file:read "*a"
file:close()
return content
end
local function loadlua(path)
return readfile(path) or path
end
local function loadngx(path)
local vars = VAR_PHASES[phase()]
local file, location = path, vars and var.template_location
if sub(file, 1) == "/" then file = sub(file, 2) end
if location and location ~= "" then
if sub(location, -1) == "/" then location = sub(location, 1, -2) end
local res = capture(concat{ location, '/', file})
if res.status == 200 then return res.body end
end
local root = vars and (var.template_root or var.document_root) or prefix
if sub(root, -1) == "/" then root = sub(root, 1, -2) end
return readfile(concat{ root, "/", file }) or path
end
do
if ngx then
VAR_PHASES = {
set = true,
rewrite = true,
access = true,
content = true,
header_filter = true,
body_filter = true,
log = true
}
template.print = ngx.print or write
template.load = loadngx
prefix, var, capture, null, phase = ngx.config.prefix(), ngx.var, ngx.location.capture, ngx.null, ngx.get_phase
if VAR_PHASES[phase()] then
caching = enabled(var.template_cache)
end
else
template.print = write
template.load = loadlua
end
if _VERSION == "Lua 5.1" then
local context = { __index = function(t, k)
return t.context[k] or t.template[k] or _G[k]
end }
if jit then
loadchunk = function(view)
return assert(load(view, nil, nil, setmetatable({ template = template }, context)))
end
else
loadchunk = function(view)
local func = assert(loadstring(view))
setfenv(func, setmetatable({ template = template }, context))
return func
end
end
else
local context = { __index = function(t, k)
return t.context[k] or t.template[k] or _ENV[k]
end }
loadchunk = function(view)
return assert(load(view, nil, nil, setmetatable({ template = template }, context)))
end
end
end
function template.caching(enable)
if enable ~= nil then caching = enable == true end
return caching
end
function template.output(s)
if s == nil or s == null then return "" end
if type(s) == "function" then return template.output(s()) end
return tostring(s)
end
function template.escape(s, c)
if type(s) == "string" then
if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end
return gsub(s, "[\"><'&]", HTML_ENTITIES)
end
return template.output(s)
end
function template.new(view, layout)
assert(view, "view was not provided for template.new(view, layout).")
local render, compile = template.render, template.compile
if layout then
if type(layout) == "table" then
return setmetatable({ render = function(self, context)
local context = context or self
context.blocks = context.blocks or {}
context.view = compile(view)(context)
layout.blocks = context.blocks or {}
layout.view = context.view or ""
return layout:render()
end }, { __tostring = function(self)
local context = self
context.blocks = context.blocks or {}
context.view = compile(view)(context)
layout.blocks = context.blocks or {}
layout.view = context.view
return tostring(layout)
end })
else
return setmetatable({ render = function(self, context)
local context = context or self
context.blocks = context.blocks or {}
context.view = compile(view)(context)
return render(layout, context)
end }, { __tostring = function(self)
local context = self
context.blocks = context.blocks or {}
context.view = compile(view)(context)
return compile(layout)(context)
end })
end
end
return setmetatable({ render = function(self, context)
return render(view, context or self)
end }, { __tostring = function(self)
return compile(view)(self)
end })
end
function template.precompile(view, path, strip)
local chunk = dump(template.compile(view), strip ~= false)
if path then
local file = open(path, "wb")
file:write(chunk)
file:close()
end
return chunk
end
function template.compile(view, key, plain)
assert(view, "view was not provided for template.compile(view, key, plain).")
if key == "no-cache" then
return loadchunk(template.parse(view, plain)), false
end
key = key or view
local cache = template.cache
if cache[key] then return cache[key], true end
local func = loadchunk(template.parse(view, plain))
if caching then cache[key] = func end
return func, false
end
function template.parse(view, plain)
assert(view, "view was not provided for template.parse(view, plain).")
if not plain then
view = template.load(view)
if byte(view, 1, 1) == 27 then return view end
end
local j = 2
local c = {[[
context=... or {}
local function include(v, c) return template.compile(v)(c or context) end
local ___,blocks,layout={},blocks or {}
]] }
local i, s = 1, find(view, "{", 1, true)
while s do
local t, p = sub(view, s + 1, s + 1), s + 2
if t == "{" then
local e = find(view, "}}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, s - 1 - w)
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
c[j] = "___[#___+1]=template.escape("
c[j+1] = trim(sub(view, p, e - 1))
c[j+2] = ")\n"
j=j+3
s, i = e + 1, e + 2
end
end
elseif t == "*" then
local e = find(view, "*}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, s - 1 - w)
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
c[j] = "___[#___+1]=template.output("
c[j+1] = trim(sub(view, p, e - 1))
c[j+2] = ")\n"
j=j+3
s, i = e + 1, e + 2
end
end
elseif t == "%" then
local e = find(view, "%}", p, true)
if e then
local z, w = escaped(view, s)
if z then
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, s - 1 - w)
c[j+2] = "]=]\n"
j=j+3
end
i = s
else
local n = e + 2
if sub(view, n, n) == "\n" then
n = n + 1
end
local r = rpos(view, s - 1)
if i <= r then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, r)
c[j+2] = "]=]\n"
j=j+3
end
c[j] = trim(sub(view, p, e - 1))
c[j+1] = "\n"
j=j+2
s, i = n - 1, n
end
end
elseif t == "(" then
local e = find(view, ")}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, s - 1 - w)
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
local f = sub(view, p, e - 1)
local x = find(f, ",", 2, true)
if x then
c[j] = "___[#___+1]=include([=["
c[j+1] = trim(sub(f, 1, x - 1))
c[j+2] = "]=],"
c[j+3] = trim(sub(f, x + 1))
c[j+4] = ")\n"
j=j+5
else
c[j] = "___[#___+1]=include([=["
c[j+1] = trim(f)
c[j+2] = "]=])\n"
j=j+3
end
s, i = e + 1, e + 2
end
end
elseif t == "[" then
local e = find(view, "]}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, s - 1 - w)
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
c[j] = "___[#___+1]=include("
c[j+1] = trim(sub(view, p, e - 1))
c[j+2] = ")\n"
j=j+3
s, i = e + 1, e + 2
end
end
elseif t == "-" then
local e = find(view, "-}", p, true)
if e then
local x, y = find(view, sub(view, s, e + 1), e + 2, true)
if x then
local z, w = escaped(view, s)
if z then
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, s - 1 - w)
c[j+2] = "]=]\n"
j=j+3
end
i = s
else
y = y + 1
x = x - 1
if sub(view, y, y) == "\n" then
y = y + 1
end
local b = trim(sub(view, p, e - 1))
if b == "verbatim" or b == "raw" then
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, s - 1 - w)
c[j+2] = "]=]\n"
j=j+3
end
c[j] = "___[#___+1]=[=["
c[j+1] = sub(view, e + 2, x)
c[j+2] = "]=]\n"
j=j+3
else
if sub(view, x, x) == "\n" then
x = x - 1
end
local r = rpos(view, s - 1)
if i <= r then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, r)
c[j+2] = "]=]\n"
j=j+3
end
c[j] = 'blocks["'
c[j+1] = b
c[j+2] = '"]=include[=['
c[j+3] = sub(view, e + 2, x)
c[j+4] = "]=]\n"
j=j+5
end
s, i = y - 1, y
end
end
end
elseif t == "#" then
local e = find(view, "#}", p, true)
if e then
local z, w = escaped(view, s)
if i < s - w then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = sub(view, i, s - 1 - w)
c[j+2] = "]=]\n"
j=j+3
end
if z then
i = s
else
e = e + 2
if sub(view, e, e) == "\n" then
e = e + 1
end
s, i = e - 1, e
end
end
end
s = find(view, "{", s + 1, true)
end
s = sub(view, i)
if s and s ~= "" then
c[j] = "___[#___+1]=[=[\n"
c[j+1] = s
c[j+2] = "]=]\n"
j=j+3
end
c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)"
return concat(c)
end
function template.render(view, context, key, plain)
assert(view, "view was not provided for template.render(view, context, key, plain).")
return template.print(template.compile(view, key, plain)(context))
end
return template

View File

@ -1 +0,0 @@
goproxy

View File

@ -1,32 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "goproxy",
embed = [":go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["goproxy.go"],
importpath = "k8s.io/kubernetes/test/images/goproxy",
deps = ["//vendor/github.com/elazarl/goproxy:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,16 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: gcr.io/kubernetes-e2e-test-images/goproxy-amd64:1.0
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080

View File

@ -22,6 +22,7 @@ TASK=$1
IMAGE=$2
KUBE_ROOT="$(cd "$(dirname "${BASH_SOURCE}")/../.." && pwd -P)"
source "${KUBE_ROOT}/hack/lib/util.sh"
# Mapping of go ARCH to actual architectures shipped part of multiarch/qemu-user-static project
declare -A QEMUARCHS=( ["amd64"]="x86_64" ["arm"]="arm" ["arm64"]="aarch64" ["ppc64le"]="ppc64le" ["s390x"]="s390x" )
@ -48,12 +49,17 @@ build() {
archs=${!QEMUARCHS[@]}
fi
kube::util::ensure-gnu-sed
for arch in ${archs}; do
echo "Building image for ${IMAGE} ARCH: ${arch}..."
# Create a temporary directory for every architecture and copy the image content
# and build the image from temporary directory
temp_dir=$(mktemp -d)
mkdir -p ${KUBE_ROOT}/_tmp
temp_dir=$(mktemp -d ${KUBE_ROOT}/_tmp/test-images-build.XXXXXX)
kube::util::trap_add "rm -rf ${temp_dir}" EXIT
cp -r ${IMAGE}/* ${temp_dir}
if [[ -f ${IMAGE}/Makefile ]]; then
# make bin will take care of all the prerequisites needed
@ -66,19 +72,27 @@ build() {
if [[ -f BASEIMAGE ]]; then
BASEIMAGE=$(getBaseImage ${arch})
sed -i "s|BASEIMAGE|${BASEIMAGE}|g" Dockerfile
${SED} -i "s|BASEIMAGE|${BASEIMAGE}|g" Dockerfile
${SED} -i "s|BASEARCH|${arch}|g" Dockerfile
fi
# copy the qemu-*-static binary to docker image to build the multi architecture image on x86 platform
if [[ $(grep "CROSS_BUILD_" Dockerfile) ]]; then
if [[ "${arch}" == "amd64" ]]; then
sed -i "/CROSS_BUILD_/d" Dockerfile
${SED} -i "/CROSS_BUILD_/d" Dockerfile
else
sed -i "s|QEMUARCH|${QEMUARCHS[$arch]}|g" Dockerfile
${SED} -i "s|QEMUARCH|${QEMUARCHS[$arch]}|g" Dockerfile
# Register qemu-*-static for all supported processors except the current one
docker run --rm --privileged multiarch/qemu-user-static:register --reset
echo "Registering qemu-*-static binaries in the kernel"
local sudo=""
if [[ $(id -u) != 0 ]]; then
sudo=sudo
fi
"${sudo}" "${KUBE_ROOT}/third_party/multiarch/qemu-user-static/register/register.sh" --reset
curl -sSL https://github.com/multiarch/qemu-user-static/releases/download/${QEMUVERSION}/x86_64_qemu-${QEMUARCHS[$arch]}-static.tar.gz | tar -xz -C ${temp_dir}
sed -i "s/CROSS_BUILD_//g" Dockerfile
# Ensure we don't get surprised by umask settings
chmod 0755 "${temp_dir}/qemu-${QEMUARCHS[$arch]}-static"
${SED} -i "s/CROSS_BUILD_//g" Dockerfile
fi
fi
@ -88,8 +102,17 @@ build() {
done
}
docker_version_check() {
docker_version=$(docker version --format '{{.Client.Version}}' | cut -d"-" -f1)
if [[ ${docker_version} != 18.06.0 && ${docker_version} < 18.06.0 ]]; then
echo "Minimum docker version 18.06.0 is required for creating and pushing manifest images[found: ${docker_version}]"
exit 1
fi
}
# This function will push the docker images
push() {
docker_version_check
TAG=$(<${IMAGE}/VERSION)
if [[ -f ${IMAGE}/BASEIMAGE ]]; then
archs=$(listArchs)
@ -100,13 +123,15 @@ push() {
docker push ${REGISTRY}/${IMAGE}-${arch}:${TAG}
done
kube::util::ensure-gnu-sed
# Make archs list into image manifest. Eg: 'amd64 ppc64le' to '${REGISTRY}/${IMAGE}-amd64:${TAG} ${REGISTRY}/${IMAGE}-ppc64le:${TAG}'
manifest=$(echo $archs | sed -e "s~[^ ]*~$REGISTRY\/$IMAGE\-&:$TAG~g")
manifest=$(echo $archs | ${SED} -e "s~[^ ]*~$REGISTRY\/$IMAGE\-&:$TAG~g")
docker manifest create --amend ${REGISTRY}/${IMAGE}:${TAG} ${manifest}
for arch in ${archs}; do
docker manifest annotate --arch ${arch} ${REGISTRY}/${IMAGE}:${TAG} ${REGISTRY}/${IMAGE}-${arch}:${TAG}
done
docker manifest push ${REGISTRY}/${IMAGE}:${TAG}
docker manifest push --purge ${REGISTRY}/${IMAGE}:${TAG}
}
# This function is for building the go code

View File

@ -16,6 +16,13 @@ FROM BASEIMAGE
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
# WARNING: Please note that the script below removes the security packages from arm64 and ppc64el images
# as they do not exist anymore in the debian repositories for jessie. So we do not recommend using this
# image for any production use and limit use of this image to just test scenarios.
COPY fixup-apt-list.sh /
RUN ["/fixup-apt-list.sh"]
RUN apt-get -q update && \
apt-get install -y dnsutils && \
apt-get clean

View File

@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Copyright 2017 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.
DEB_ARCH=$(dpkg --print-architecture)
# http://security.debian.org/debian-security/dists/jessie/updates/InRelease is missing
# entries for some platforms, so we just remove the last line in sources.list in
# /etc/apt/sources.list which is "deb http://deb.debian.org/debian jessie-updates main"
case ${DEB_ARCH} in
arm64|ppc64el)
sed -i '/debian-security/d' /etc/apt/sources.list
;;
esac
exit 0

View File

@ -16,8 +16,8 @@ go_library(
srcs = ["logs_generator.go"],
importpath = "k8s.io/kubernetes/test/images/logs-generator",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/rand:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/rand:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)

View File

@ -21,8 +21,8 @@ import (
"fmt"
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/rand"
"k8s.io/klog"
)
var (
@ -47,11 +47,11 @@ func main() {
flag.Parse()
if *linesTotal <= 0 {
glog.Fatalf("Invalid total number of lines: %d", *linesTotal)
klog.Fatalf("Invalid total number of lines: %d", *linesTotal)
}
if *duration <= 0 {
glog.Fatalf("Invalid duration: %v", *duration)
klog.Fatalf("Invalid duration: %v", *duration)
}
generateLogs(*linesTotal, *duration)
@ -60,12 +60,11 @@ func main() {
// Outputs linesTotal lines of logs to stdout uniformly for duration
func generateLogs(linesTotal int, duration time.Duration) {
delay := duration / time.Duration(linesTotal)
rand.Seed(time.Now().UnixNano())
ticker := time.NewTicker(delay)
defer ticker.Stop()
for id := 0; id < linesTotal; id++ {
glog.Info(generateLogLine(id))
klog.Info(generateLogLine(id))
<-ticker.C
}
}

View File

@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = ["check_metadata_concealment.go"],
importpath = "k8s.io/kubernetes/test/images/metadata-concealment",
visibility = ["//visibility:private"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_binary(
name = "metadata-concealment",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)

View File

@ -13,6 +13,7 @@
# limitations under the License.
FROM scratch
ADD goproxy goproxy
EXPOSE 8080
ENTRYPOINT ["/goproxy"]
COPY check_metadata_concealment /
ENTRYPOINT ["/check_metadata_concealment"]

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
SRCS=n-way-http
SRCS=check_metadata_concealment
ARCH ?= amd64
TARGET ?= $(CURDIR)
GOLANG_VERSION ?= latest

View File

@ -0,0 +1 @@
1.1.1

View File

@ -0,0 +1,177 @@
/*
Copyright 2017 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.
*/
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"regexp"
)
var (
successEndpoints = []string{
// Discovery
"http://169.254.169.254",
"http://metadata.google.internal",
"http://169.254.169.254/",
"http://metadata.google.internal/",
"http://metadata.google.internal/0.1",
"http://metadata.google.internal/0.1/",
"http://metadata.google.internal/computeMetadata",
"http://metadata.google.internal/computeMetadata/v1",
// Allowed API versions.
"http://metadata.google.internal/computeMetadata/v1/",
// Service account token endpoints.
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token",
// Params that contain 'recursive' as substring.
"http://metadata.google.internal/computeMetadata/v1/instance/?nonrecursive=true",
"http://metadata.google.internal/computeMetadata/v1/instance/?something=other&nonrecursive=true",
}
legacySuccessEndpoints = []string{
// Discovery
"http://metadata.google.internal/0.1/meta-data",
"http://metadata.google.internal/computeMetadata/v1beta1",
// Allowed API versions.
"http://metadata.google.internal/0.1/meta-data/",
"http://metadata.google.internal/computeMetadata/v1beta1/",
// Service account token endpoints.
"http://metadata.google.internal/0.1/meta-data/service-accounts/default/acquire",
"http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token",
}
noKubeEnvEndpoints = []string{
// Check that these don't get a recursive result.
"http://metadata.google.internal/computeMetadata/v1/instance/?recursive%3Dtrue", // urlencoded
"http://metadata.google.internal/computeMetadata/v1/instance/?re%08ecursive=true", // backspaced
}
failureEndpoints = []string{
// Other API versions.
"http://metadata.google.internal/0.2/",
"http://metadata.google.internal/computeMetadata/v2/",
// kube-env.
"http://metadata.google.internal/0.1/meta-data/attributes/kube-env",
"http://metadata.google.internal/computeMetadata/v1beta1/instance/attributes/kube-env",
"http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env",
// VM identity.
"http://metadata.google.internal/0.1/meta-data/service-accounts/default/identity",
"http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/identity",
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity",
// Recursive.
"http://metadata.google.internal/computeMetadata/v1/instance/?recursive=true",
"http://metadata.google.internal/computeMetadata/v1/instance/?something=other&recursive=true",
"http://metadata.google.internal/computeMetadata/v1/instance/?recursive=true&something=other",
// Other.
"http://metadata.google.internal/computeMetadata/v1/instance/attributes//kube-env",
"http://metadata.google.internal/computeMetadata/v1/instance/attributes/../attributes/kube-env",
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts//default/identity",
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/../service-accounts/default/identity",
}
)
func main() {
success := 0
h := map[string][]string{
"Metadata-Flavor": {"Google"},
}
for _, e := range successEndpoints {
if err := checkURL(e, h, 200, "", ""); err != nil {
log.Printf("Wrong response for %v: %v", e, err)
success = 1
}
}
for _, e := range noKubeEnvEndpoints {
if err := checkURL(e, h, 200, "", "kube-env"); err != nil {
log.Printf("Wrong response for %v: %v", e, err)
success = 1
}
}
for _, e := range failureEndpoints {
if err := checkURL(e, h, 403, "", ""); err != nil {
log.Printf("Wrong response for %v: %v", e, err)
success = 1
}
}
legacyEndpointExpectedStatus := 200
if err := checkURL("http://metadata.google.internal/computeMetadata/v1/instance/attributes/disable-legacy-endpoints", h, 200, "true", ""); err == nil {
// If `disable-legacy-endpoints` is set to true, queries to unconcealed legacy endpoints will return a 403.
legacyEndpointExpectedStatus = 403
}
for _, e := range legacySuccessEndpoints {
if err := checkURL(e, h, legacyEndpointExpectedStatus, "", ""); err != nil {
log.Printf("Wrong response for %v: %v", e, err)
success = 1
}
}
xForwardedForHeader := map[string][]string{
"X-Forwarded-For": {"Somebody-somewhere"},
}
// Check that success endpoints fail if X-Forwarded-For is present.
for _, e := range successEndpoints {
if err := checkURL(e, xForwardedForHeader, 403, "", ""); err != nil {
log.Printf("Wrong response for %v with X-Forwarded-For: %v", e, err)
success = 1
}
}
os.Exit(success)
}
// Checks that a URL with the given headers returns the right code.
// If expectedToContain is non-empty, checks that the body contains expectedToContain.
// Similarly, if expectedToNotContain is non-empty, checks that the body doesn't contain expectedToNotContain.
func checkURL(url string, header http.Header, expectedStatus int, expectedToContain, expectedToNotContain string) error {
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
req.Header = header
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != expectedStatus {
return fmt.Errorf("unexpected response: got %d, want %d", resp.StatusCode, expectedStatus)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if expectedToContain != "" {
matched, err := regexp.Match(expectedToContain, body)
if err != nil {
return err
}
if !matched {
return fmt.Errorf("body didn't contain %q: got %v", expectedToContain, string(body))
}
}
if expectedToNotContain != "" {
matched, err := regexp.Match(expectedToNotContain, body)
if err != nil {
return err
}
if matched {
return fmt.Errorf("body incorrectly contained %q: got %v", expectedToNotContain, string(body))
}
}
return nil
}

View File

@ -8,12 +8,7 @@ load(
go_library(
name = "go_default_library",
srcs = select({
"@io_bazel_rules_go//go/platform:linux": [
"mt.go",
],
"//conditions:default": [],
}),
srcs = ["mt.go"],
importpath = "k8s.io/kubernetes/test/images/mounttest",
)

View File

@ -1,5 +0,0 @@
amd64=busybox
arm=arm32v6/busybox
arm64=arm64v8/busybox
ppc64le=ppc64le/busybox
s390x=s390x/busybox

View File

@ -1,31 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "n-way-http",
embed = [":go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "k8s.io/kubernetes/test/images/n-way-http",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,55 +0,0 @@
/*
Copyright 2015 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.
*/
// A webserver that runs n http handlers. Example invocation:
// - server -port 8080 -prefix foo -num 10 -start 0
// Will given you 10 /foo(i) endpoints that simply echo foo(i) when requested.
// - server -start 3 -num 1
// Will create just one endpoint, at /foo3
package main
import (
"flag"
"fmt"
"log"
"net/http"
)
var (
port = flag.Int("port", 8080, "Port number for requests.")
prefix = flag.String("prefix", "foo", "String used as path prefix")
num = flag.Int("num", 10, "Number of endpoints to create.")
start = flag.Int("start", 0, "Index to start, only makes sense with --num")
)
func main() {
flag.Parse()
// This container is used to test the GCE L7 controller which expects "/"
// to return a 200 response.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "ok")
})
for i := *start; i < *start+*num; i++ {
path := fmt.Sprintf("%v%d", *prefix, i)
http.HandleFunc(fmt.Sprintf("/%v", path), func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, path)
})
}
log.Printf("server -port %d -prefix %v -num %d -start %d", *port, *prefix, *num, *start)
http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
}

View File

@ -15,7 +15,7 @@ go_library(
name = "go_default_library",
srcs = ["netexec.go"],
importpath = "k8s.io/kubernetes/test/images/netexec",
deps = ["//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library"],
)
filegroup(

View File

@ -1 +1 @@
1.0
1.1

View File

@ -357,6 +357,7 @@ func startUDPServer(udpPort int) {
serverAddress, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", udpPort))
assertNoError(err)
serverConn, err := net.ListenUDP("udp", serverAddress)
assertNoError(err)
defer serverConn.Close()
buf := make([]byte, 1024)

View File

@ -7,7 +7,7 @@ metadata:
spec:
containers:
- name: netexec
image: gcr.io/kubernetes-e2e-test-images/netexec-amd64:1.0
image: gcr.io/kubernetes-e2e-test-images/netexec-amd64:1.1
ports:
- containerPort: 8080
protocol: TCP

View File

@ -12,9 +12,9 @@ go_library(
importpath = "k8s.io/kubernetes/test/images/nettest",
deps = [
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
],
)

View File

@ -241,7 +241,7 @@ func contactOthers(state *State) {
if err != nil {
log.Fatalf("Unable to create client; error: %v\n", err)
}
// Double check that that worked by getting the server version.
// Double check that worked by getting the server version.
if v, err := client.Discovery().ServerVersion(); err != nil {
log.Fatalf("Unable to get server version: %v\n", err)
} else {

View File

@ -16,9 +16,9 @@ go_library(
srcs = ["main.go"],
importpath = "k8s.io/kubernetes/test/images/no-snat-test-proxy",
deps = [
"//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/logs:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/logs:go_default_library",
],
)

View File

@ -16,9 +16,9 @@ go_library(
srcs = ["main.go"],
importpath = "k8s.io/kubernetes/test/images/no-snat-test",
deps = [
"//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/logs:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/logs:go_default_library",
],
)

View File

@ -0,0 +1,3 @@
amd64=debian:stretch-slim
arm64=arm64v8/debian:stretch-slim
ppc64le=ppc64le/debian:stretch-slim

View File

@ -0,0 +1,42 @@
# 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.
FROM BASEIMAGE as build_node_perf_npb_ep
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
RUN apt-get update && apt-get install -y build-essential gfortran
ADD http://www.nas.nasa.gov/assets/npb/NPB3.3.1.tar.gz .
RUN tar xzf NPB3.3.1.tar.gz
WORKDIR ./NPB3.3.1/NPB3.3-OMP
RUN if [ $(arch) != "x86_64" ]; then \
sed s/-mcmodel=medium//g config/NAS.samples/make.def.gcc_x86 > config/make.def; \
else \
cp config/NAS.samples/make.def.gcc_x86 config/make.def; \
fi
RUN make EP CLASS=D
# Copying the required libraries (shared object files) to a convenient location so that it can be copied into the
# main container in the second build stage.
RUN mkdir -p /lib-copy && find /usr/lib -name "*.so.*" -exec cp {} /lib-copy \;
FROM BASEIMAGE
COPY --from=build_node_perf_npb_ep /NPB3.3.1/NPB3.3-OMP/bin/ep.D.x /
COPY --from=build_node_perf_npb_ep /lib-copy /lib-copy
ENV LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/lib-copy"
ENTRYPOINT /ep.D.x

View File

@ -0,0 +1,16 @@
## NAS Parallel Benchmark Suite - Embarrassingly Parallel (EP) Benchmark
The container image described here runs the EP benchmark from the
[NAS parallel benchmark suite.](https://www.nas.nasa.gov/publications/npb.html)
This image is used as a workload in in node performance testing.
## How to release:
```
# Build
$ cd $K8S_ROOT/test/images
$ make all WHAT=node-perf/npb-ep
# Push
$ cd $K8S_ROOT/test/images
$ make all-push WHAT=node-perf/npb-ep
```

View File

@ -0,0 +1,3 @@
amd64=debian:stretch-slim
arm64=arm64v8/debian:stretch-slim
ppc64le=ppc64le/debian:stretch-slim

View File

@ -0,0 +1,44 @@
# 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.
FROM BASEIMAGE as build_node_perf_npb_is
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
RUN apt-get update && apt-get install -y build-essential gfortran
ADD http://www.nas.nasa.gov/assets/npb/NPB3.3.1.tar.gz .
RUN tar xzf NPB3.3.1.tar.gz
WORKDIR ./NPB3.3.1/NPB3.3-OMP
# Create build config based on the architecture and build the workload.
RUN if [ $(arch) != "x86_64" ]; then \
sed s/-mcmodel=medium//g config/NAS.samples/make.def.gcc_x86 > config/make.def; \
else \
cp config/NAS.samples/make.def.gcc_x86 config/make.def; \
fi
RUN make IS CLASS=D
# Copying the required libraries (shared object files) to a convenient location so that it can be copied into the
# main container in the second build stage.
RUN mkdir -p /lib-copy && find /usr/lib -name "*.so.*" -exec cp {} /lib-copy \;
FROM BASEIMAGE
COPY --from=build_node_perf_npb_is /NPB3.3.1/NPB3.3-OMP/bin/is.D.x /
COPY --from=build_node_perf_npb_is /lib-copy /lib-copy
ENV LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/lib-copy"
ENTRYPOINT /is.D.x

View File

@ -0,0 +1,16 @@
## NAS Parallel Benchmark Suite - Integer Sort (IS) Benchmark
The container image described here runs the IS benchmark from the
[NAS parallel benchmark suite.](https://www.nas.nasa.gov/publications/npb.html)
This image is used as a workload in in node performance testing.
## How to release:
```
# Build
$ cd $K8S_ROOT/test/images
$ make all WHAT=node-perf/npb-is
# Push
$ cd $K8S_ROOT/test/images
$ make all-push WHAT=node-perf/npb-is
```

View File

@ -0,0 +1 @@
amd64=python:3.6-slim-stretch

View File

@ -0,0 +1,27 @@
# 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.
FROM BASEIMAGE
RUN apt-get update && apt-get install -y wget time
RUN pip install tensorflow
RUN wget https://github.com/tensorflow/models/archive/v1.9.0.tar.gz \
&& tar xzf v1.9.0.tar.gz \
&& rm -f v1.9.0.tar.gz
WORKDIR $HOME/models-1.9.0/official/wide_deep
ENV PYTHONPATH $PYTHONPATH:$HOME/models-1.9.0
ENTRYPOINT python ./wide_deep.py

View File

@ -0,0 +1,17 @@
## Tensorflow Official Wide Deep Model
The container image described here predicts the income using the census income dataset in Tensorflow. For more
information, see
[https://github.com/tensorflow/models/tree/master/official/wide_deep](https://github.com/tensorflow/models/tree/master/official/wide_deep).
This image is used as a workload in in node performance testing.
## How to release:
```
# Build
$ cd $K8S_ROOT/test/images
$ make all WHAT=node-perf/tf-wide-deep
# Push
$ cd $K8S_ROOT/test/images
$ make all-push WHAT=node-perf/tf-wide-deep
```

View File

@ -0,0 +1 @@
1.0

View File

@ -1,4 +1,4 @@
amd64=k8s.gcr.io/debian-base-amd64:0.3
arm=k8s.gcr.io/debian-base-arm:0.3
arm64=k8s.gcr.io/debian-base-arm64:0.3
ppc64le=k8s.gcr.io/debian-base-ppc64le:0.3
amd64=k8s.gcr.io/debian-base-amd64:0.4.0
arm=k8s.gcr.io/debian-base-arm:0.4.0
arm64=k8s.gcr.io/debian-base-arm64:0.4.0
ppc64le=k8s.gcr.io/debian-base-ppc64le:0.4.0

View File

@ -15,7 +15,7 @@ go_library(
name = "go_default_library",
srcs = ["peer-finder.go"],
importpath = "k8s.io/kubernetes/test/images/pets/peer-finder",
deps = ["//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library"],
)
filegroup(

View File

@ -6,13 +6,13 @@ All it does is watch DNS for changes in the set of endpoints that are part of th
of the PetSet. It periodically looks up the SRV record of the DNS entry that corresponds to a Kubernetes
Service which enumerates the set of peers for this the specified service.
Be sure to use the `publishNotReadyAddresses` field on the governing service
Be sure to use the `service.alpha.kubernetes.io/tolerate-unready-endpoints` on the governing service
of the StatefulSet so that all peers are listed in endpoints before any peers are started.
There are several ways to bundle it with your main application.
1. In an [init container](http://kubernetes.io/docs/user-guide/pods/init-container/),
to help your pod determine its peers when it it first started (determine the desired set of
to help your pod determine its peers when it first started (determine the desired set of
peers from the governing service of the StatefulSet. For this use case, the `--on-start` option
can be used, but the `--on-change` option should not be used since the init container will no
longer be running after the pod is started. An example of an `--on-start` script would be to
@ -33,7 +33,14 @@ Options 1 and 2 and 4 may be preferable since they do not require changes to the
Option 3 is useful is signalling is necessary.
The peer-finder tool is intended to help legacy applications run in containers on Kubernetes.
If possible, it may be preferable to modify an applications to poll DNS itself to determine its peer set.
If possible, it may be preferable to modify an application to poll its own DNS to determine its peer set.
Not all StatefulSets are able to be scaled. For unscalable StatefulSets, only the on-start message is needed, and
so option 1 is a good choice.
## DNS Considerations
Unless specified by the `-domain` argument, `peer-finder` will determine the FQDN of the pod by examining the
`/etc/resolv.conf` file, looking for a `search` line and looking for the best match.
If your pod is not using the default `dnsPolicy` value which is `ClusterFirst` as the DNS policy, you may need
to provide the `-domain` argument. In most common configurations, `-domain=cluster.local` will be the correct setting.

View File

@ -1 +1 @@
1.1
1.3

View File

@ -25,6 +25,7 @@ import (
"net"
"os"
"os/exec"
"regexp"
"sort"
"strings"
"time"
@ -41,7 +42,7 @@ var (
onStart = flag.String("on-start", "", "Script to run on start, must accept a new line separated list of peers via stdin.")
svc = flag.String("service", "", "Governing service responsible for the DNS records of the domain this pod is in.")
namespace = flag.String("ns", "", "The namespace this pod is running in. If unspecified, the POD_NAMESPACE env var is used.")
domain = flag.String("domain", "cluster.local", "The Cluster Domain which is used by the Cluster.")
domain = flag.String("domain", "", "The Cluster Domain which is used by the Cluster, if not set tries to determine it from /etc/resolv.conf file.")
)
func lookup(svcName string) (sets.String, error) {
@ -99,9 +100,53 @@ func main() {
if err != nil {
log.Fatalf("Failed to get hostname: %s", err)
}
var domainName string
svcLocalSuffix := strings.Join([]string{"svc", *domain}, ".")
myName := strings.Join([]string{hostname, *svc, ns, svcLocalSuffix}, ".")
// If domain is not provided, try to get it from resolv.conf
if *domain == "" {
resolvConfBytes, err := ioutil.ReadFile("/etc/resolv.conf")
resolvConf := string(resolvConfBytes)
if err != nil {
log.Fatal("Unable to read /etc/resolv.conf")
}
var re *regexp.Regexp
if ns == "" {
// Looking for a domain that looks like with *.svc.**
re, err = regexp.Compile(`\A(.*\n)*search\s{1,}(.*\s{1,})*(?P<goal>[a-zA-Z0-9-]{1,63}.svc.([a-zA-Z0-9-]{1,63}\.)*[a-zA-Z0-9]{2,63})`)
} else {
// Looking for a domain that looks like svc.**
re, err = regexp.Compile(`\A(.*\n)*search\s{1,}(.*\s{1,})*(?P<goal>svc.([a-zA-Z0-9-]{1,63}\.)*[a-zA-Z0-9]{2,63})`)
}
if err != nil {
log.Fatalf("Failed to create regular expression: %v", err)
}
groupNames := re.SubexpNames()
result := re.FindStringSubmatch(resolvConf)
for k, v := range result {
if groupNames[k] == "goal" {
if ns == "" {
// Domain is complete if ns is empty
domainName = v
} else {
// Need to convert svc.** into ns.svc.**
domainName = ns + "." + v
}
break
}
}
log.Printf("Determined Domain to be %s", domainName)
} else {
domainName = strings.Join([]string{ns, "svc", *domain}, ".")
}
if *svc == "" || domainName == "" || (*onChange == "" && *onStart == "") {
log.Fatalf("Incomplete args, require -on-change and/or -on-start, -service and -ns or an env var for POD_NAMESPACE.")
}
myName := strings.Join([]string{hostname, *svc, domainName}, ".")
script := *onStart
if script == "" {
script = *onChange
@ -114,6 +159,7 @@ func main() {
continue
}
if newPeers.Equal(peers) || !newPeers.Has(myName) {
log.Printf("Have not found myself in list yet.\nMy Hostname: %s\nHosts in list: %s", myName, strings.Join(newPeers.List(), ", "))
continue
}
peerList := newPeers.List()

View File

@ -1,4 +1,4 @@
amd64=k8s.gcr.io/debian-base-amd64:0.3
arm=k8s.gcr.io/debian-base-arm:0.3
arm64=k8s.gcr.io/debian-base-arm64:0.3
ppc64le=k8s.gcr.io/debian-base-ppc64le:0.3
amd64=k8s.gcr.io/debian-base-amd64:0.4.0
arm=k8s.gcr.io/debian-base-arm:0.4.0
arm64=k8s.gcr.io/debian-base-arm64:0.4.0
ppc64le=k8s.gcr.io/debian-base-ppc64le:0.4.0

View File

@ -1 +1 @@
1.1
1.2

View File

@ -1,4 +1,4 @@
amd64=k8s.gcr.io/debian-base-amd64:0.3
arm=k8s.gcr.io/debian-base-arm:0.3
arm64=k8s.gcr.io/debian-base-arm64:0.3
ppc64le=k8s.gcr.io/debian-base-ppc64le:0.3
amd64=k8s.gcr.io/debian-base-amd64:0.4.0
arm=k8s.gcr.io/debian-base-arm:0.4.0
arm64=k8s.gcr.io/debian-base-arm64:0.4.0
ppc64le=k8s.gcr.io/debian-base-ppc64le:0.4.0

View File

@ -25,7 +25,7 @@ ADD on-start.sh /
COPY peer-finder /
# See README.md
RUN wget -q -O /zookeeper-3.5.0-alpha.tar.gz http://apache.mirrors.pair.com/zookeeper/zookeeper-3.5.0-alpha/zookeeper-3.5.0-alpha.tar.gz && \
RUN wget -q -O /zookeeper-3.5.0-alpha.tar.gz http://archive.apache.org/dist/zookeeper/zookeeper-3.5.0-alpha/zookeeper-3.5.0-alpha.tar.gz && \
tar -xzf /zookeeper-3.5.0-alpha.tar.gz -C /tmp/ && mv /tmp/zookeeper-3.5.0-alpha /zookeeper && rm /zookeeper-3.5.0-alpha.tar.gz
ADD install.sh /

View File

@ -1 +1 @@
1.1
1.2

View File

@ -1,4 +1,4 @@
amd64=k8s.gcr.io/debian-base-amd64:0.3
arm=k8s.gcr.io/debian-base-arm:0.3
arm64=k8s.gcr.io/debian-base-arm64:0.3
ppc64le=k8s.gcr.io/debian-base-ppc64le:0.3
amd64=k8s.gcr.io/debian-base-amd64:0.4.0
arm=k8s.gcr.io/debian-base-arm:0.4.0
arm64=k8s.gcr.io/debian-base-arm64:0.4.0
ppc64le=k8s.gcr.io/debian-base-ppc64le:0.4.0

View File

@ -48,7 +48,7 @@ Custom metrics in Prometheus format are exposed on "/metrics" endpoint.
### CURL example
```console
$ kubectl run resource-consumer --image=k8s.gcr.io/resource_consumer:beta --expose --service-overrides='{ "spec": { "type": "LoadBalancer" } }' --port 8080
$ kubectl run resource-consumer --image=gcr.io/kubernetes-e2e-test-images/resource-consumer:1.4 --expose --service-overrides='{ "spec": { "type": "LoadBalancer" } }' --port 8080 --requests='cpu=500m,memory=256Mi'
$ kubectl get services resource-consumer
```
@ -62,7 +62,7 @@ $ curl --data "millicores=300&durationSec=600" http://<EXTERNAL-IP>:8080/Consume
## Image
Docker image of Resource Consumer can be found in Google Container Registry as k8s.gcr.io/resource_consumer:beta
Docker image of Resource Consumer can be found in Google Container Registry as gcr.io/kubernetes-e2e-test-images/resource-consumer:1.4
## Use cases

View File

@ -1 +1 @@
1.3
1.4

View File

@ -0,0 +1,5 @@
amd64=alpine:3.8
arm=arm32v6/alpine:3.8
arm64=arm64v8/alpine:3.8
ppc64le=ppc64le/alpine:3.8
s390x=s390x/alpine:3.8

View File

@ -0,0 +1,14 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,36 @@
# 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.
FROM k8s.gcr.io/kube-cross:v1.10.4-1 as build_k8s_1_10_sample_apiserver
ENV GOPATH /go
RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin
ENV PATH $GOPATH/bin:$PATH
# The e2e aggregator test was originally added in #50347 and is designed to test ability to run a 1.7
# sample-apiserver in newer releases. please see e2e test named "Should be able to support the 1.7 Sample
# API Server using the current Aggregator"
RUN go get -d k8s.io/sample-apiserver \
&& cd ${GOPATH}/src/k8s.io/sample-apiserver \
&& git checkout --track origin/release-1.10 \
&& CGO_ENABLED=0 GOOS=linux GOARCH=BASEARCH go install .
# for arm, go install uses go/bin/linux_arm, so just find the file and copy it to the root so
# we can copy it out from this throw away container image from a standard location
RUN find /go/bin -name sample-apiserver -exec cp {} / \;
FROM BASEIMAGE
COPY --from=build_k8s_1_10_sample_apiserver /sample-apiserver /sample-apiserver
ENTRYPOINT ["/sample-apiserver"]

View File

@ -0,0 +1 @@
1.10

View File

@ -0,0 +1,3 @@
amd64=fedora:28
arm64=arm64v8/fedora:28
ppc64le=ppc64le/fedora:28

View File

@ -12,7 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM fedora:26
FROM BASEIMAGE
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
RUN yum -y install hostname glusterfs-server && yum clean all
ADD glusterd.vol /etc/glusterfs/
ADD run_gluster.sh /usr/local/bin/

View File

@ -0,0 +1 @@
1.0

Some files were not shown because too many files have changed in this diff Show More