Support K8s 1.22 in notebook controller (kubeflow/kubeflow#6374)

Fix https://github.com/kubeflow/kubeflow/issues/6366

Migrating to Kubebuilder v3 leads to the following changes:
- Add .dockerignore file.
- Upgrade Go version from v1.15 to v1.17.
- Adapt Makefile.
- Add image (build + push) target to makefile.
- Upgrade EnvTest to use K8s v1.22.
- Update PROJECT template.
- Migrate CRD apiVersion from v1beta to v1.
- Add livenessProbe and readinessProbe to controller manager.
- Upgrade controller-runtime from v0.2.0 to v0.11.0.

Other changes:
- Build image using public.ecr.aws registry instead of gcr.io.
- Update README.md documentation.
- Update 3rd party licences.
- Fix notebook.spec description.
- Add 3 sample notebooks (v1, v1alpha1 and v1beta1).

Signed-off-by: Samuel Veloso <svelosol@redhat.com>
This commit is contained in:
Samu 2022-05-03 17:49:01 +02:00 committed by GitHub
parent 22bdc7ad77
commit 0215857aa9
33 changed files with 10967 additions and 3096 deletions

View File

@ -0,0 +1,5 @@
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Ignore build and test binaries.
.git
bin/
testbin/

View File

@ -6,7 +6,7 @@
#
# This is necessary because the Jupyter controller now depends on
# components/common
ARG GOLANG_VERSION=1.15
ARG GOLANG_VERSION=1.17
FROM golang:${GOLANG_VERSION} as builder
WORKDIR /workspace
@ -23,9 +23,9 @@ WORKDIR /workspace/notebook-controller
# Build
RUN if [ "$(uname -m)" = "aarch64" ]; then \
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go build -a -o manager main.go; \
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go build -a -mod=mod -o manager main.go; \
else \
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go; \
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -mod=mod -o manager main.go; \
fi
# Use distroless as minimal base image to package the manager binary

View File

@ -1,18 +1,10 @@
# Image URL to use all building/pushing image targets
IMG ?= gcr.io/kubeflow-images-public/notebook-controller
IMG ?= public.ecr.aws/j1r0q0g6/notebooks/notebook-controller
TAG ?= $(shell git describe --tags --always)
SHELL := /bin/bash
GOLANG_VERSION ?= 1.15
# Whether to use cached images with GCB
USE_IMAGE_CACHE ?= true
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
CRD_OPTIONS ?= "crd"
# Based on recommendation https://sdk.operatorframework.io/docs/building-operators/golang/references/envtest-setup/
ENVTEST_ASSETS_DIR=$(shell pwd)/testbin
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.22
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
@ -21,77 +13,128 @@ else
GOBIN=$(shell go env GOBIN)
endif
# Setting SHELL to bash allows bash commands to be executed by recipes.
# This is a requirement for 'setup-envtest.sh' in the test target.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec
.PHONY: all
all: manager
# check license
check-license:
##@ General
# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk commands is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Development
.PHONY: check-license
check-license: ## Check third-party license
./third_party/check-license.sh
# Run tests
test: generate fmt vet manifests
mkdir -p ${ENVTEST_ASSETS_DIR}
test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/a9bd9117a77a2f84bbc546e28991136fe0000dc0/hack/setup-envtest.sh
source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR);
go test ./api/... ./controllers/... -coverprofile cover.out
.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=role crd:maxDescLen=0 webhook paths="./..." output:crd:artifacts:config=config/crd/bases
# Build manager binary
manager: generate fmt vet
go build -o bin/manager main.go
.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
# Run against the configured Kubernetes cluster in ~/.kube/config
run: generate fmt vet
go run ./main.go
# Install CRDs into a cluster
install: manifests
kubectl apply -f config/crd/bases
# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
deploy: manifests
kubectl apply -f config/crd/bases
kustomize build config/default | kubectl apply -f -
# Generate manifests e.g. CRD, RBAC etc.
manifests: controller-gen
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
# Run go fmt against code
fmt:
.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...
# Run go vet against code
vet:
.PHONY: vet
vet: ## Run go vet against code.
go vet ./...
# Generate code
generate: controller-gen
$(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths=./api/...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
# Build the docker image
docker-build: test
##@ Build
.PHONY: manager
manager: generate fmt vet ## Build manager binary.
go build -o bin/manager main.go
.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./main.go
.PHONY: docker-build
docker-build: test ## Build docker image with the manager.
cd .. && docker build . -t ${IMG}:${TAG} -f ./notebook-controller/Dockerfile
@echo "updating kustomize image patch file for manager resource"
sed -i'' -e 's@image: .*@image: '"${IMG}:${TAG}"'@' ./config/default/manager_image_patch.yaml
# Push the docker image
docker-push:
.PHONY: docker-push
docker-push: ## Push docker image with the manager.
docker push ${IMG}:${TAG}
# find or download controller-gen
# download controller-gen if necessary
controller-gen:
ifeq (, $(shell which controller-gen))
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.0
CONTROLLER_GEN=$(GOBIN)/controller-gen
else
CONTROLLER_GEN=$(shell which controller-gen)
.PHONY: image
image: docker-build docker-push ## Build and push docker image with the manager.
##@ Deployment
ifndef ignore-not-found
ignore-not-found = false
endif
# TODO(jlewi): Can we get rid of this and just use skaffold?
build-gcr: test
docker build -t $(IMG):$(TAG) .
@echo Built $(IMG):$(TAG)
.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | kubectl apply -f -
push-gcr: build-gcr
docker push $(IMG):$(TAG)
@echo Pushed $(IMG):$(TAG)
.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f -
.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
sed -i'' -e 's@newName: .*@newName: '"${IMG}"'@' ./config/base/kustomization.yaml
sed -i'' -e 's@newTag: .*@newTag: '"${TAG}"'@' ./config/base/kustomization.yaml
$(KUSTOMIZE) build config/base | kubectl apply -f -
.PHONY: undeploy
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/base | kubectl delete --ignore-not-found=$(ignore-not-found) -f -
CONTROLLER_GEN = $(shell pwd)/bin/controller-gen
.PHONY: controller-gen
controller-gen: ## Download controller-gen locally if necessary.
$(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0)
KUSTOMIZE = $(shell pwd)/bin/kustomize
.PHONY: kustomize
kustomize: ## Download kustomize locally if necessary.
$(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/v3/cmd/kustomize@v3.2.0)
ENVTEST = $(shell pwd)/bin/setup-envtest
.PHONY: envtest
envtest: ## Download envtest-setup locally if necessary.
$(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
# go-get-tool will 'go get' any package $2 and install it to $1.
PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
define go-get-tool
@[ -f $(1) ] || { \
set -e ;\
TMP_DIR=$$(mktemp -d) ;\
cd $$TMP_DIR ;\
go mod init tmp ;\
echo "Downloading $(2)" ;\
GOBIN=$(PROJECT_DIR)/bin go get $(2) ;\
rm -rf $$TMP_DIR ;\
}
endef

View File

@ -1,12 +1,29 @@
version: "2"
domain: kubeflow.org
layout:
- go.kubebuilder.io/v3
projectName: notebook-controller
repo: github.com/kubeflow/kubeflow/components/notebook-controller
resources:
- group: kubeflow.org
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: kubeflow.org
kind: Notebook
- group: kubeflow.org
version: v1beta1
kind: Notebook
- group: kubeflow.org
path: github.com/kubeflow/kubeflow/components/notebook-controller/api/v1
version: v1
- api:
crdVersion: v1
namespaced: true
domain: kubeflow.org
kind: Notebook
path: github.com/kubeflow/kubeflow/components/notebook-controller/api/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
domain: kubeflow.org
kind: Notebook
path: github.com/kubeflow/kubeflow/components/notebook-controller/api/v1beta1
version: v1beta1
version: "3"

View File

@ -1,31 +1,39 @@
# Notebook Controller
The controller allows users to create a custom resource "Notebook" (jupyter notebook).
We originally wrote the controller using jsonnet and metacontroller, but are migrating to golang and
Kubebuilder here. See [discussion](https://github.com/kubeflow/kubeflow/issues/2269).
The controller allows users to create a custom resource "Notebook" (jupyter
notebook).
It has been developed using **Golang** and
**[Kubebuilder](https://book.kubebuilder.io/quick-start.html)**.
## Spec
The user needs to specify the PodSpec for the jupyter notebook.
The user needs to specify the PodSpec for the Jupyter notebook.
For example:
```
apiVersion: kubeflow.org/v1alpha1
```yaml
apiVersion: kubeflow.org/v1
kind: Notebook
metadata:
name: my-notebook
namespace: test
spec:
template:
spec: # Your PodSpec here
spec:
containers:
- image: gcr.io/kubeflow-images-public/tensorflow-1.10.1-notebook-cpu:v0.3.0
args: ["start.sh", "lab", "--LabApp.token=''", "--LabApp.allow_remote_access='True'",
"--LabApp.allow_root='True'", "--LabApp.ip='*'",
"--LabApp.base_url=/test/my-notebook/",
"--port=8888", "--no-browser"]
name: notebook
...
- name: my-notebook
image: public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter:master
args:
[
"start.sh",
"lab",
"--LabApp.token=''",
"--LabApp.allow_remote_access='True'",
"--LabApp.allow_root='True'",
"--LabApp.ip='*'",
"--LabApp.base_url=/test/my-notebook/",
"--port=8888",
"--no-browser",
]
```
The required fields are `containers[0].image` and (`containers[0].command` and/or `containers[0].args`).
@ -45,6 +53,8 @@ All other fields will be filled in with default value if not specified.
`metrics-addr`: The address the metric endpoint binds to. The default value is `:8080`.
`probe-addr`: The address the health endpoint binds to. The default value is `:8081`.
`enable-leader-election`: Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager. The default value is `false`.
## Implementation detail
@ -53,6 +63,42 @@ This part is WIP as we are still developing.
Under the hood, the controller creates a StatefulSet to run the notebook instance, and a Service for it.
## Deployment
Install the `notebooks.kubeflow.org` CRD:
```
make install
```
Deploy the notebook controller manager:
```
make deploy
```
Verify that the controller is running in the `notebook-controller-system` namespace:
```
$ kubectl get pods -l app=notebook-controller -n notebook-controller-system
NAME READY STATUS RESTARTS AGE
notebook-controller-deployment-564d76877-mqsm8 1/1 Running 0 16s
```
### Clean-up
Uninstall the notebook controller manager:
```
make undeploy
```
Uninstall the `notebooks.kubeflow.org` CRD:
```
make uninstall
```
## Contributing
[https://www.kubeflow.org/docs/about/contributing/](https://www.kubeflow.org/docs/about/contributing/)
@ -61,12 +107,12 @@ Under the hood, the controller creates a StatefulSet to run the notebook instanc
To develop on `notebook-controller`, your environment must have the following:
- [go](https://golang.org/dl/) version v1.15+.
- [docker](https://docs.docker.com/install/) version 17.03+.
- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) version v1.11.3+.
- [kustomize](https://sigs.k8s.io/kustomize/docs/INSTALL.md) v3.1.0+
- Access to a Kubernetes v1.11.3+ cluster.
- [kubebuilder](https://book.kubebuilder.io/quick-start.html#installation)
- [go](https://golang.org/dl/) version v1.17+.
- [docker](https://docs.docker.com/install/) version 20.10+.
- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) version 1.22.0+.
- [kustomize](https://sigs.k8s.io/kustomize/docs/INSTALL.md) version 3.8.7+.
- [kubernetes](https://github.com/kubernetes-sigs/kind) Access to a Kubernetes v1.22.0+ cluster.
- [kubebuilder](https://book.kubebuilder.io/quick-start.html#installation) version 3.3.0+.
In order for the custom Notebook Controller to be functional from your local machine,
the admins must:
@ -79,6 +125,20 @@ the admins must:
```
kubectl proxy
```
3. Start the manager locally in developer mode:
```
export DEV="true"
make run
```
### Testing
Make sure all the tests are passing after you add a new feature:
```
make test
```
## TODO
- e2e test (we have one testing the jsonnet-metacontroller one, we should make it run on this one)

View File

@ -25,8 +25,7 @@ import (
// NotebookSpec defines the desired state of Notebook
type NotebookSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Template describes the notebooks that will be created.
Template NotebookTemplateSpec `json:"template,omitempty"`
}

View File

@ -1,3 +1,4 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
@ -70,7 +71,7 @@ func (in *NotebookCondition) DeepCopy() *NotebookCondition {
func (in *NotebookList) DeepCopyInto(out *NotebookList) {
*out = *in
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Notebook, len(*in))

View File

@ -25,8 +25,7 @@ import (
// NotebookSpec defines the desired state of Notebook
type NotebookSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Template describes the notebooks that will be created.
Template NotebookTemplateSpec `json:"template,omitempty"`
}

View File

@ -1,3 +1,4 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
@ -70,7 +71,7 @@ func (in *NotebookCondition) DeepCopy() *NotebookCondition {
func (in *NotebookList) DeepCopyInto(out *NotebookList) {
*out = *in
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Notebook, len(*in))

View File

@ -25,8 +25,7 @@ import (
// NotebookSpec defines the desired state of Notebook
type NotebookSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Template describes the notebooks that will be created.
Template NotebookTemplateSpec `json:"template,omitempty"`
}

View File

@ -17,7 +17,7 @@ package v1beta1
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.

View File

@ -1,3 +1,4 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
@ -70,7 +71,7 @@ func (in *NotebookCondition) DeepCopy() *NotebookCondition {
func (in *NotebookList) DeepCopyInto(out *NotebookList) {
*out = *in
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Notebook, len(*in))

View File

@ -8,16 +8,6 @@ resources:
patchesStrategicMerge:
- patches/trivial_conversion_patch.yaml
patchesJson6902:
# Remove once the following issue is resolved:
# https://github.com/kubeflow/kubeflow/issues/5722
- path: patches/old_crd.yaml
target:
group: apiextensions.k8s.io
version: v1beta1
kind: CustomResourceDefinition
name: notebooks.kubeflow.org
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
#- patches/webhook_in_notebooks.yaml

View File

@ -1,6 +1,6 @@
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:

View File

@ -1,64 +0,0 @@
# Use the old CRD because of the quantity validation issue:
# https://github.com/kubeflow/kubeflow/issues/5722
- op: replace
path: /spec
value:
group: kubeflow.org
names:
kind: Notebook
plural: notebooks
singular: notebook
scope: Namespaced
subresources:
status: {}
versions:
- name: v1alpha1
served: true
storage: false
- name: v1beta1
served: true
storage: false
- name: v1
served: true
storage: true
validation:
openAPIV3Schema:
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
properties:
template:
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
Important: Run "make" to regenerate code after modifying this file'
properties:
spec:
type: object
type: object
type: object
status:
properties:
conditions:
description: Conditions is an array of current conditions
items:
properties:
type:
description: Type of the confition/
type: string
required:
- type
type: object
type: array
required:
- conditions
type: object

View File

@ -1,8 +1,9 @@
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: notebooks.kubeflow.org
spec:
preserveUnknownFields: false # TODO: Remove in Kubeflow 1.7 release
conversion:
strategy: None

View File

@ -1,6 +1,6 @@
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: notebooks.kubeflow.org

View File

@ -15,9 +15,9 @@ commonLabels:
bases:
- ../crd
- ../rbac
- ../manager
- ../crd
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml
#- ../webhook
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.

View File

@ -35,8 +35,14 @@ spec:
imagePullPolicy: Always
livenessProbe:
httpGet:
path: /metrics
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
path: /healthz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
serviceAccountName: service-account

View File

@ -1,4 +1,3 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole

View File

@ -0,0 +1,11 @@
---
apiVersion: kubeflow.org/v1
kind: Notebook
metadata:
name: notebook-sample-v1
spec:
template:
spec:
containers:
- name: notebook-sample-v1
image: public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter:v1.5.0-rc.1

View File

@ -0,0 +1,11 @@
---
apiVersion: kubeflow.org/v1alpha1
kind: Notebook
metadata:
name: notebook-sample-v1alpha1
spec:
template:
spec:
containers:
- name: notebook-sample-v1
image: public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter:v1.5.0-rc.1

View File

@ -0,0 +1,11 @@
---
apiVersion: kubeflow.org/v1beta1
kind: Notebook
metadata:
name: notebook-sample-v1beta1
spec:
template:
spec:
containers:
- name: notebook-sample-v1
image: public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter:v1.5.0-rc.1

View File

@ -37,6 +37,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
@ -84,8 +85,7 @@ type NotebookReconciler struct {
// +kubebuilder:rbac:groups=kubeflow.org,resources=notebooks;notebooks/status;notebooks/finalizers,verbs="*"
// +kubebuilder:rbac:groups="networking.istio.io",resources=virtualservices,verbs="*"
func (r *NotebookReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background()
func (r *NotebookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := r.Log.WithValues("notebook", req.NamespacedName)
// TODO(yanniszark): Can we avoid reconciling Events and Notebook in the same queue?
@ -628,11 +628,79 @@ func nbNameExists(client client.Client, nbName string, namespace string) bool {
return true
}
// predNBPodIsLabeled filters pods not containing the "notebook-name" label key
func predNBPodIsLabeled() predicate.Funcs {
// Documented at
// https://github.com/kubernetes-sigs/controller-runtime/blob/ce8bdd3d81ab410ff23255e9ad3554f613c5183c/pkg/predicate/predicate_test.go#L884
checkNBLabel := func() func(object client.Object) bool {
return func(object client.Object) bool {
_, labelExists := object.GetLabels()["notebook-name"]
return labelExists
}
}
return predicate.NewPredicateFuncs(checkNBLabel())
}
// predNBEvents filters events not coming from Pod or STS, and coming from
// unknown NBs
func predNBEvents(r *NotebookReconciler) predicate.Funcs {
checkEvent := func() func(object client.Object) bool {
return func(object client.Object) bool {
event := object.(*corev1.Event)
nbName, err := nbNameFromInvolvedObject(r.Client, &event.InvolvedObject)
if err != nil {
return false
}
return isStsOrPodEvent(event) && nbNameExists(r.Client, nbName, object.GetNamespace())
}
}
predicates := predicate.NewPredicateFuncs(checkEvent())
// Do not reconcile when an event gets deleted
predicates.DeleteFunc = func(e event.DeleteEvent) bool {
return false
}
return predicates
}
// SetupWithManager sets up the controller with the Manager.
func (r *NotebookReconciler) SetupWithManager(mgr ctrl.Manager) error {
// Map function to convert pod events to reconciliation requests
mapPodToRequest := func(object client.Object) []reconcile.Request {
return []reconcile.Request{
{NamespacedName: types.NamespacedName{
Name: object.GetLabels()["notebook-name"],
Namespace: object.GetNamespace(),
}},
}
}
// Map function to convert namespace events to reconciliation requests
mapEventToRequest := func(object client.Object) []reconcile.Request {
return []reconcile.Request{
{NamespacedName: types.NamespacedName{
Name: object.GetName(),
Namespace: object.GetNamespace(),
}},
}
}
builder := ctrl.NewControllerManagedBy(mgr).
For(&v1beta1.Notebook{}).
Owns(&appsv1.StatefulSet{}).
Owns(&corev1.Service{})
Owns(&corev1.Service{}).
Watches(
&source.Kind{Type: &corev1.Pod{}},
handler.EnqueueRequestsFromMapFunc(mapPodToRequest),
builder.WithPredicates(predNBPodIsLabeled())).
Watches(
&source.Kind{Type: &corev1.Event{}},
handler.EnqueueRequestsFromMapFunc(mapEventToRequest),
builder.WithPredicates(predNBEvents(r)))
// watch Istio virtual service
if os.Getenv("USE_ISTIO") == "true" {
virtualService := &unstructured.Unstructured{}
@ -641,100 +709,10 @@ func (r *NotebookReconciler) SetupWithManager(mgr ctrl.Manager) error {
builder.Owns(virtualService)
}
// TODO(lunkai): After this is fixed:
// https://github.com/kubernetes-sigs/controller-runtime/issues/572
// We don't have to call Build to get the controller.
c, err := builder.Build(r)
err := builder.Complete(r)
if err != nil {
return err
}
// watch underlying pod
mapFn := handler.ToRequestsFunc(
func(a handler.MapObject) []ctrl.Request {
return []ctrl.Request{
{NamespacedName: types.NamespacedName{
Name: a.Meta.GetLabels()["notebook-name"],
Namespace: a.Meta.GetNamespace(),
}},
}
})
// helper common function for pod predicates. Filter pods not containing the "notebook-name" label key
checkNBLabel := func(m metav1.Object) bool {
_, ok := m.GetLabels()["notebook-name"]
return ok
}
// TODO: refactor to use predicate.NewPredicateFuncs when controller-runtime module version is updated
p := predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
return checkNBLabel(e.MetaOld) && e.ObjectOld != e.ObjectNew
},
CreateFunc: func(e event.CreateEvent) bool {
return checkNBLabel(e.Meta)
},
DeleteFunc: func(e event.DeleteEvent) bool {
return checkNBLabel(e.Meta)
},
GenericFunc: func(e event.GenericEvent) bool {
return checkNBLabel(e.Meta)
},
}
eventToRequest := handler.ToRequestsFunc(
func(a handler.MapObject) []ctrl.Request {
return []reconcile.Request{
{NamespacedName: types.NamespacedName{
Name: a.Meta.GetName(),
Namespace: a.Meta.GetNamespace(),
}},
}
})
// helper common function for event predicates. Filter events not coming from Pod or STS, and coming from unknown NBs
checkEvent := func(o runtime.Object, m metav1.Object) bool {
event := o.(*corev1.Event)
nbName, err := nbNameFromInvolvedObject(r.Client, &event.InvolvedObject)
if err != nil {
return false
}
return isStsOrPodEvent(event) && nbNameExists(r.Client, nbName, m.GetNamespace())
}
// TODO: refactor to use predicate.NewPredicateFuncs when controller-runtime module version is updated
// We don't include DeleteFunc since we don't want the reconcile
// to happen when an event gets deleted
eventsPredicates := predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
return e.ObjectOld != e.ObjectNew && checkEvent(e.ObjectNew, e.MetaNew)
},
CreateFunc: func(e event.CreateEvent) bool {
return checkEvent(e.Object, e.Meta)
},
DeleteFunc: func(e event.DeleteEvent) bool {
return false
},
GenericFunc: func(e event.GenericEvent) bool {
return checkEvent(e.Object, e.Meta)
},
}
if err = c.Watch(
&source.Kind{Type: &corev1.Pod{}},
&handler.EnqueueRequestsFromMapFunc{
ToRequests: mapFn,
},
p); err != nil {
return err
}
if err = c.Watch(
&source.Kind{Type: &corev1.Event{}},
&handler.EnqueueRequestsFromMapFunc{
ToRequests: eventToRequest,
},
eventsPredicates); err != nil {
return err
}
return nil
}

View File

@ -16,6 +16,7 @@ limitations under the License.
package controllers
import (
"context"
"path/filepath"
"testing"
@ -39,22 +40,28 @@ import (
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var cfg *rest.Config
var k8sClient client.Client // You'll be using this client in your tests.
var testEnv *envtest.Environment
var (
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
ctx context.Context
cancel context.CancelFunc
)
var _ = BeforeSuite(func(done Done) {
logf.SetLogger(zap.LoggerTo(GinkgoWriter, true))
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
ctx, cancel = context.WithCancel(context.TODO())
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,
}
var err error
cfg, err = testEnv.Start()
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
cfg, err := testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
err = nbv1beta1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
@ -62,13 +69,13 @@ var _ = BeforeSuite(func(done Done) {
// +kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient).ToNot(BeNil())
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())
k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme.Scheme,
})
Expect(err).ToNot(HaveOccurred())
Expect(err).NotTo(HaveOccurred())
err = (&NotebookReconciler{
Client: k8sManager.GetClient(),
@ -80,20 +87,21 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).ToNot(HaveOccurred())
go func() {
err = k8sManager.Start(ctrl.SetupSignalHandler())
Expect(err).ToNot(HaveOccurred())
defer GinkgoRecover()
err = k8sManager.Start(ctx)
Expect(err).ToNot(HaveOccurred(), "failed to run manager")
}()
k8sClient = k8sManager.GetClient()
Expect(k8sClient).ToNot(BeNil())
close(done)
}, 60)
var _ = AfterSuite(func() {
cancel()
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).ToNot(HaveOccurred())
Expect(err).NotTo(HaveOccurred())
})
func TestAPIs(t *testing.T) {

View File

@ -1,21 +1,75 @@
module github.com/kubeflow/kubeflow/components/notebook-controller
go 1.15
go 1.17
require (
github.com/go-logr/logr v0.1.0
github.com/kubeflow/kubeflow/components/common v0.0.0-20200908101143-7f5e242f4671
github.com/prometheus/client_golang v0.9.0
github.com/onsi/ginkgo v1.12.1
github.com/onsi/gomega v1.10.1
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
sigs.k8s.io/controller-runtime v0.2.0
sigs.k8s.io/controller-tools v0.2.0 // indirect
github.com/go-logr/logr v1.2.0
github.com/kubeflow/kubeflow/components/common v0.0.0-20220218084159-4ad0158e955e
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.17.0
github.com/prometheus/client_golang v1.11.0
k8s.io/api v0.23.0
k8s.io/apimachinery v0.23.0
k8s.io/client-go v0.23.0
sigs.k8s.io/controller-runtime v0.11.0
)
// Ensure we build the notebook-controller with the latest `common`
// module. However, because this module's `replace` will be ignored by
// other modules, we still specify a commit in the `require` directive.
replace github.com/kubeflow/kubeflow/components/common => ../common
require (
cloud.google.com/go v0.81.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-logr/zapr v1.2.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.5 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.28.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20210825183410-e898025ed96a // indirect
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/apiextensions-apiserver v0.23.0 // indirect
k8s.io/component-base v0.23.0 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.0 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

File diff suppressed because it is too large Load Diff

View File

@ -19,17 +19,23 @@ import (
"flag"
"os"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
nbv1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1"
nbv1alpha1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1alpha1"
nbv1beta1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1beta1"
"github.com/kubeflow/kubeflow/components/notebook-controller/controllers"
controller_metrics "github.com/kubeflow/kubeflow/components/notebook-controller/pkg/metrics"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
// +kubebuilder:scaffold:imports
//+kubebuilder:scaffold:imports
)
var (
@ -38,28 +44,36 @@ var (
)
func init() {
_ = clientgoscheme.AddToScheme(scheme)
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
_ = nbv1alpha1.AddToScheme(scheme)
_ = nbv1beta1.AddToScheme(scheme)
_ = nbv1.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
utilruntime.Must(nbv1.AddToScheme(scheme))
utilruntime.Must(nbv1alpha1.AddToScheme(scheme))
utilruntime.Must(nbv1beta1.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme
}
func main() {
var metricsAddr, leaderElectionNamespace string
var enableLeaderElection bool
var probeAddr string
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "probe-addr", ":8081", "The address the health endpoint binds to.")
flag.StringVar(&leaderElectionNamespace, "leader-election-namespace", "",
"Determines the namespace in which the leader election configmap will be created.")
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
opts := zap.Options{
Development: true,
}
opts.BindFlags(flag.CommandLine)
flag.Parse()
ctrl.SetLogger(zap.Logger(true))
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionNamespace: leaderElectionNamespace,
LeaderElectionID: "kubeflow-notebook-controller",
@ -80,13 +94,23 @@ func main() {
os.Exit(1)
}
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up health check")
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up ready check")
os.Exit(1)
}
// uncomment when we need the conversion webhook.
// if err = (&nbv1beta1.Notebook{}).SetupWebhookWithManager(mgr); err != nil {
// setupLog.Error(err, "unable to create webhook", "webhook", "Captain")
// os.Exit(1)
// }
// +kubebuilder:scaffold:builder
//+kubebuilder:scaffold:builder
setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {

View File

@ -12,7 +12,7 @@ import (
"github.com/kubeflow/kubeflow/components/notebook-controller/pkg/metrics"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
var log = logf.Log.WithName("culler")

View File

@ -1,66 +1,291 @@
github.com/kubeflow/kubeflow/components/notebook-controller
cloud.google.com/go
cloud.google.com/go/bigquery
cloud.google.com/go/datastore
cloud.google.com/go/firestore
cloud.google.com/go/pubsub
cloud.google.com/go/storage
dmitri.shuralyov.com/gpu/mtl
github.com/Azure/go-ansiterm
github.com/Azure/go-autorest
github.com/Azure/go-autorest/autorest
github.com/Azure/go-autorest/autorest/adal
github.com/Azure/go-autorest/autorest/date
github.com/Azure/go-autorest/autorest/mocks
github.com/Azure/go-autorest/logger
github.com/Azure/go-autorest/tracing
github.com/BurntSushi/toml
github.com/BurntSushi/xgb
github.com/NYTimes/gziphandler
github.com/OneOfOne/xxhash
github.com/PuerkitoBio/purell
github.com/PuerkitoBio/urlesc
github.com/alecthomas/template
github.com/alecthomas/units
github.com/antihax/optional
github.com/antlr/antlr4/runtime/Go/antlr
github.com/armon/circbuf
github.com/armon/go-metrics
github.com/armon/go-radix
github.com/asaskevich/govalidator
github.com/benbjohnson/clock
github.com/beorn7/perks
github.com/bgentry/speakeasy
github.com/bketelsen/crypt
github.com/blang/semver
github.com/census-instrumentation/opencensus-proto
github.com/certifi/gocertifi
github.com/cespare/xxhash
github.com/cespare/xxhash/v2
github.com/chzyer/logex
github.com/chzyer/readline
github.com/chzyer/test
github.com/client9/misspell
github.com/cncf/udpa/go
github.com/cncf/xds/go
github.com/cockroachdb/datadriven
github.com/cockroachdb/errors
github.com/cockroachdb/logtags
github.com/coreos/bbolt
github.com/coreos/etcd
github.com/coreos/go-oidc
github.com/coreos/go-semver
github.com/coreos/go-systemd
github.com/coreos/go-systemd/v22
github.com/coreos/pkg
github.com/cpuguy83/go-md2man/v2
github.com/creack/pty
github.com/davecgh/go-spew
github.com/dgrijalva/jwt-go
github.com/dgryski/go-sip13
github.com/docopt/docopt-go
github.com/dustin/go-humanize
github.com/elazarl/goproxy
github.com/emicklei/go-restful
github.com/envoyproxy/go-control-plane
github.com/envoyproxy/protoc-gen-validate
github.com/evanphx/json-patch
github.com/fatih/color
github.com/felixge/httpsnoop
github.com/form3tech-oss/jwt-go
github.com/fsnotify/fsnotify
github.com/getkin/kin-openapi
github.com/getsentry/raven-go
github.com/ghodss/yaml
github.com/go-gl/glfw
github.com/go-gl/glfw/v3.3/glfw
github.com/go-kit/kit
github.com/go-kit/log
github.com/go-logfmt/logfmt
github.com/go-logr/logr
github.com/go-logr/zapr
github.com/go-openapi/jsonpointer
github.com/go-openapi/jsonreference
github.com/go-openapi/swag
github.com/go-stack/stack
github.com/go-task/slim-sprig
github.com/godbus/dbus/v5
github.com/gogo/protobuf
github.com/golang/glog
github.com/golang/groupcache
github.com/golang/mock
github.com/golang/protobuf
github.com/google/btree
github.com/google/cel-go
github.com/google/cel-spec
github.com/google/go-cmp
github.com/google/gofuzz
github.com/google/martian
github.com/google/martian/v3
github.com/google/pprof
github.com/google/renameio
github.com/google/uuid
github.com/googleapis/gax-go/v2
github.com/googleapis/gnostic
github.com/gopherjs/gopherjs
github.com/gorilla/mux
github.com/gorilla/websocket
github.com/gregjones/httpcache
github.com/grpc-ecosystem/go-grpc-middleware
github.com/grpc-ecosystem/go-grpc-prometheus
github.com/grpc-ecosystem/grpc-gateway
github.com/hashicorp/consul/api
github.com/hashicorp/consul/sdk
github.com/hashicorp/errwrap
github.com/hashicorp/go-cleanhttp
github.com/hashicorp/go-immutable-radix
github.com/hashicorp/go-msgpack
github.com/hashicorp/go-multierror
github.com/hashicorp/go-rootcerts
github.com/hashicorp/go-sockaddr
github.com/hashicorp/go-syslog
github.com/hashicorp/go-uuid
github.com/hashicorp/go.net
github.com/hashicorp/golang-lru
github.com/hashicorp/hcl
github.com/hashicorp/logutils
github.com/hashicorp/mdns
github.com/hashicorp/memberlist
github.com/hashicorp/serf
github.com/hpcloud/tail
github.com/ianlancetaylor/demangle
github.com/imdario/mergo
github.com/inconshreveable/mousetrap
github.com/jessevdk/go-flags
github.com/jonboulle/clockwork
github.com/josharian/intern
github.com/jpillora/backoff
github.com/json-iterator/go
github.com/jstemmer/go-junit-report
github.com/jtolds/gls
github.com/julienschmidt/httprouter
github.com/kisielk/errcheck
github.com/kisielk/gotool
github.com/konsorten/go-windows-terminal-sequences
github.com/kr/fs
github.com/kr/logfmt
github.com/kr/pretty
github.com/kr/pty
github.com/kr/text
github.com/kubeflow/kubeflow/components/common
github.com/magiconair/properties
github.com/mailru/easyjson
github.com/mattn/go-colorable
github.com/mattn/go-isatty
github.com/matttproud/golang_protobuf_extensions
github.com/miekg/dns
github.com/mitchellh/cli
github.com/mitchellh/go-homedir
github.com/mitchellh/go-testing-interface
github.com/mitchellh/gox
github.com/mitchellh/iochan
github.com/mitchellh/mapstructure
github.com/moby/spdystream
github.com/moby/term
github.com/modern-go/concurrent
github.com/modern-go/reflect2
github.com/munnerz/goautoneg
github.com/mwitkow/go-conntrack
github.com/mxk/go-flowrate
github.com/niemeyer/pretty
github.com/nxadm/tail
github.com/oklog/ulid
github.com/onsi/ginkgo
github.com/onsi/gomega
github.com/pborman/uuid
github.com/opentracing/opentracing-go
github.com/pascaldekloe/goe
github.com/pelletier/go-toml
github.com/peterbourgon/diskv
github.com/pkg/errors
github.com/pkg/sftp
github.com/pmezard/go-difflib
github.com/posener/complete
github.com/pquerna/cachecontrol
github.com/prometheus/client_golang
github.com/prometheus/client_model
github.com/prometheus/common
github.com/prometheus/procfs
github.com/prometheus/tsdb
github.com/rogpeppe/fastuuid
github.com/rogpeppe/go-internal
github.com/russross/blackfriday/v2
github.com/ryanuber/columnize
github.com/sean-/seed
github.com/shurcooL/sanitized_anchor_name
github.com/sirupsen/logrus
github.com/smartystreets/assertions
github.com/smartystreets/goconvey
github.com/soheilhy/cmux
github.com/spaolacci/murmur3
github.com/spf13/afero
github.com/spf13/cast
github.com/spf13/cobra
github.com/spf13/jwalterweatherman
github.com/spf13/pflag
github.com/spf13/viper
github.com/stoewer/go-strcase
github.com/stretchr/objx
github.com/stretchr/testify
github.com/subosito/gotenv
github.com/tmc/grpc-websocket-proxy
github.com/xiang90/probing
github.com/yuin/goldmark
go.etcd.io/bbolt
go.etcd.io/etcd/api/v3
go.etcd.io/etcd/client/pkg/v3
go.etcd.io/etcd/client/v2
go.etcd.io/etcd/client/v3
go.etcd.io/etcd/pkg/v3
go.etcd.io/etcd/raft/v3
go.etcd.io/etcd/server/v3
go.opencensus.io
go.opentelemetry.io/contrib
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
go.opentelemetry.io/otel
go.opentelemetry.io/otel/exporters/otlp
go.opentelemetry.io/otel/metric
go.opentelemetry.io/otel/oteltest
go.opentelemetry.io/otel/sdk
go.opentelemetry.io/otel/sdk/export/metric
go.opentelemetry.io/otel/sdk/metric
go.opentelemetry.io/otel/trace
go.opentelemetry.io/proto/otlp
go.uber.org/atomic
go.uber.org/goleak
go.uber.org/multierr
go.uber.org/zap
golang.org/x/crypto
golang.org/x/exp
golang.org/x/image
golang.org/x/lint
golang.org/x/mobile
golang.org/x/mod
golang.org/x/net
golang.org/x/oauth2
golang.org/x/sync
golang.org/x/sys
golang.org/x/term
golang.org/x/text
golang.org/x/time
golang.org/x/tools
golang.org/x/xerrors
gomodules.xyz/jsonpatch/v2
google.golang.org/api
google.golang.org/appengine
google.golang.org/genproto
google.golang.org/grpc
google.golang.org/protobuf
gopkg.in/alecthomas/kingpin.v2
gopkg.in/check.v1
gopkg.in/errgo.v2
gopkg.in/fsnotify.v1
gopkg.in/inf.v0
gopkg.in/ini.v1
gopkg.in/natefinch/lumberjack.v2
gopkg.in/resty.v1
gopkg.in/square/go-jose.v2
gopkg.in/tomb.v1
gopkg.in/yaml.v2
gopkg.in/yaml.v3
gotest.tools/v3
honnef.co/go/tools
k8s.io/api
k8s.io/apiextensions-apiserver
k8s.io/apimachinery
k8s.io/apiserver
k8s.io/client-go
k8s.io/klog
k8s.io/code-generator
k8s.io/component-base
k8s.io/gengo
k8s.io/klog/v2
k8s.io/kube-openapi
k8s.io/utils
rsc.io/binaryregexp
rsc.io/quote/v3
rsc.io/sampler
sigs.k8s.io/apiserver-network-proxy/konnectivity-client
sigs.k8s.io/controller-runtime
sigs.k8s.io/testing_frameworks
sigs.k8s.io/json
sigs.k8s.io/structured-merge-diff/v4
sigs.k8s.io/yaml

View File

@ -464,7 +464,7 @@ 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
* 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 Evan Phoenix nor the names of its contributors
@ -3987,7 +3987,7 @@ stretchr/testify MIT License https://github.com/stretchr/testify/blob/master/L
--------------------------------------------------------------------------------
MIT License
Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell
Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -4033,7 +4033,7 @@ THE SOFTWARE.
--------------------------------------------------------------------------------
uber-go/multierr MIT License https://github.com/uber-go/multierr/blob/master/LICENSE.txt
--------------------------------------------------------------------------------
Copyright (c) 2017 Uber Technologies, Inc.
Copyright (c) 2017-2021 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal