From e45a6c25d7aa52607e30fc3ab0a35446d50cc09c Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Tue, 19 Feb 2019 16:34:30 -0800 Subject: [PATCH 01/13] init --- components/profile-controller/.gitignore | 24 ++++++ components/profile-controller/Dockerfile | 17 ++++ components/profile-controller/Makefile | 52 ++++++++++++ components/profile-controller/PROJECT | 3 + .../profile-controller/cmd/manager/main.go | 84 +++++++++++++++++++ .../config/default/kustomization.yaml | 49 +++++++++++ .../default/manager_auth_proxy_patch.yaml | 24 ++++++ .../config/default/manager_image_patch.yaml | 12 +++ .../manager_prometheus_metrics_patch.yaml | 19 +++++ .../config/manager/manager.yaml | 82 ++++++++++++++++++ .../config/rbac/auth_proxy_role.yaml | 13 +++ .../config/rbac/auth_proxy_role_binding.yaml | 12 +++ .../config/rbac/auth_proxy_service.yaml | 20 +++++ .../config/rbac/rbac_role.yaml | 43 ++++++++++ .../config/rbac/rbac_role_binding.yaml | 13 +++ components/profile-controller/go.mod | 72 ++++++++++++++++ .../hack/boilerplate.go.txt | 15 ++++ .../profile-controller/pkg/apis/apis.go | 33 ++++++++ .../pkg/controller/controller.go | 34 ++++++++ .../profile-controller/pkg/webhook/webhook.go | 37 ++++++++ 20 files changed, 658 insertions(+) create mode 100644 components/profile-controller/.gitignore create mode 100644 components/profile-controller/Dockerfile create mode 100644 components/profile-controller/Makefile create mode 100644 components/profile-controller/PROJECT create mode 100644 components/profile-controller/cmd/manager/main.go create mode 100644 components/profile-controller/config/default/kustomization.yaml create mode 100644 components/profile-controller/config/default/manager_auth_proxy_patch.yaml create mode 100644 components/profile-controller/config/default/manager_image_patch.yaml create mode 100644 components/profile-controller/config/default/manager_prometheus_metrics_patch.yaml create mode 100644 components/profile-controller/config/manager/manager.yaml create mode 100644 components/profile-controller/config/rbac/auth_proxy_role.yaml create mode 100644 components/profile-controller/config/rbac/auth_proxy_role_binding.yaml create mode 100644 components/profile-controller/config/rbac/auth_proxy_service.yaml create mode 100644 components/profile-controller/config/rbac/rbac_role.yaml create mode 100644 components/profile-controller/config/rbac/rbac_role_binding.yaml create mode 100644 components/profile-controller/go.mod create mode 100644 components/profile-controller/hack/boilerplate.go.txt create mode 100644 components/profile-controller/pkg/apis/apis.go create mode 100644 components/profile-controller/pkg/controller/controller.go create mode 100644 components/profile-controller/pkg/webhook/webhook.go diff --git a/components/profile-controller/.gitignore b/components/profile-controller/.gitignore new file mode 100644 index 00000000000..d97ffc5159b --- /dev/null +++ b/components/profile-controller/.gitignore @@ -0,0 +1,24 @@ + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Kubernetes Generated files - skip generated files, except for vendored files + +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ diff --git a/components/profile-controller/Dockerfile b/components/profile-controller/Dockerfile new file mode 100644 index 00000000000..83f7d979712 --- /dev/null +++ b/components/profile-controller/Dockerfile @@ -0,0 +1,17 @@ +# Build the manager binary +FROM golang:1.10.3 as builder + +# Copy in the go src +WORKDIR /go/src/github.com/kubeflow/kubeflow/components/profile-controller +COPY pkg/ pkg/ +COPY cmd/ cmd/ +COPY vendor/ vendor/ + +# Build +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager github.com/kubeflow/kubeflow/components/profile-controller/cmd/manager + +# Copy the controller-manager into a thin image +FROM ubuntu:latest +WORKDIR / +COPY --from=builder /go/src/github.com/kubeflow/kubeflow/components/profile-controller/manager . +ENTRYPOINT ["/manager"] diff --git a/components/profile-controller/Makefile b/components/profile-controller/Makefile new file mode 100644 index 00000000000..e684a74f62d --- /dev/null +++ b/components/profile-controller/Makefile @@ -0,0 +1,52 @@ + +# Image URL to use all building/pushing image targets +IMG ?= controller:latest + +all: test manager + +# Run tests +test: generate fmt vet manifests + go test ./pkg/... ./cmd/... -coverprofile cover.out + +# Build manager binary +manager: generate fmt vet + go build -o bin/manager github.com/kubeflow/kubeflow/components/profile-controller/cmd/manager + +# Run against the configured Kubernetes cluster in ~/.kube/config +run: generate fmt vet + go run ./cmd/manager/main.go + +# Install CRDs into a cluster +install: manifests + kubectl apply -f config/crds + +# Deploy controller in the configured Kubernetes cluster in ~/.kube/config +deploy: manifests + kubectl apply -f config/crds + kustomize build config/default | kubectl apply -f - + +# Generate manifests e.g. CRD, RBAC etc. +manifests: + go run vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go all + +# Run go fmt against code +fmt: + go fmt ./pkg/... ./cmd/... + +# Run go vet against code +vet: + go vet ./pkg/... ./cmd/... + +# Generate code +generate: + go generate ./pkg/... ./cmd/... + +# Build the docker image +docker-build: test + docker build . -t ${IMG} + @echo "updating kustomize image patch file for manager resource" + sed -i'' -e 's@image: .*@image: '"${IMG}"'@' ./config/default/manager_image_patch.yaml + +# Push the docker image +docker-push: + docker push ${IMG} diff --git a/components/profile-controller/PROJECT b/components/profile-controller/PROJECT new file mode 100644 index 00000000000..0085e500a61 --- /dev/null +++ b/components/profile-controller/PROJECT @@ -0,0 +1,3 @@ +version: "1" +domain: kubeflow.org +repo: github.com/kubeflow/kubeflow/components/profile-controller diff --git a/components/profile-controller/cmd/manager/main.go b/components/profile-controller/cmd/manager/main.go new file mode 100644 index 00000000000..bfd075cf5ef --- /dev/null +++ b/components/profile-controller/cmd/manager/main.go @@ -0,0 +1,84 @@ +/* +Copyright 2019 The Kubeflow 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" + "os" + + "github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis" + "github.com/kubeflow/kubeflow/components/profile-controller/pkg/controller" + "github.com/kubeflow/kubeflow/components/profile-controller/pkg/webhook" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + "sigs.k8s.io/controller-runtime/pkg/runtime/signals" +) + +func main() { + var metricsAddr string + flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") + flag.Parse() + logf.SetLogger(logf.ZapLogger(false)) + log := logf.Log.WithName("entrypoint") + + // Get a config to talk to the apiserver + log.Info("setting up client for manager") + cfg, err := config.GetConfig() + if err != nil { + log.Error(err, "unable to set up client config") + os.Exit(1) + } + + // Create a new Cmd to provide shared dependencies and start components + log.Info("setting up manager") + mgr, err := manager.New(cfg, manager.Options{MetricsBindAddress: metricsAddr}) + if err != nil { + log.Error(err, "unable to set up overall controller manager") + os.Exit(1) + } + + log.Info("Registering Components.") + + // Setup Scheme for all resources + log.Info("setting up scheme") + if err := apis.AddToScheme(mgr.GetScheme()); err != nil { + log.Error(err, "unable add APIs to scheme") + os.Exit(1) + } + + // Setup all Controllers + log.Info("Setting up controller") + if err := controller.AddToManager(mgr); err != nil { + log.Error(err, "unable to register controllers to the manager") + os.Exit(1) + } + + log.Info("setting up webhooks") + if err := webhook.AddToManager(mgr); err != nil { + log.Error(err, "unable to register webhooks to the manager") + os.Exit(1) + } + + // Start the Cmd + log.Info("Starting the Cmd.") + if err := mgr.Start(signals.SetupSignalHandler()); err != nil { + log.Error(err, "unable to run the manager") + os.Exit(1) + } +} diff --git a/components/profile-controller/config/default/kustomization.yaml b/components/profile-controller/config/default/kustomization.yaml new file mode 100644 index 00000000000..53ad5aa1de4 --- /dev/null +++ b/components/profile-controller/config/default/kustomization.yaml @@ -0,0 +1,49 @@ +# Adds namespace to all resources. +namespace: profile-controller-system + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: profile-controller- + +# Labels to add to all resources and selectors. +#commonLabels: +# someName: someValue + +# Each entry in this list must resolve to an existing +# resource definition in YAML. These are the resource +# files that kustomize reads, modifies and emits as a +# YAML string, with resources separated by document +# markers ("---"). +resources: +- ../rbac/rbac_role.yaml +- ../rbac/rbac_role_binding.yaml +- ../manager/manager.yaml + # Comment the following 3 lines if you want to disable + # the auth proxy (https://github.com/brancz/kube-rbac-proxy) + # which protects your /metrics endpoint. +- ../rbac/auth_proxy_service.yaml +- ../rbac/auth_proxy_role.yaml +- ../rbac/auth_proxy_role_binding.yaml + +patches: +- manager_image_patch.yaml + # Protect the /metrics endpoint by putting it behind auth. + # Only one of manager_auth_proxy_patch.yaml and + # manager_prometheus_metrics_patch.yaml should be enabled. +- manager_auth_proxy_patch.yaml + # If you want your controller-manager to expose the /metrics + # endpoint w/o any authn/z, uncomment the following line and + # comment manager_auth_proxy_patch.yaml. + # Only one of manager_auth_proxy_patch.yaml and + # manager_prometheus_metrics_patch.yaml should be enabled. +#- manager_prometheus_metrics_patch.yaml + +vars: +- name: WEBHOOK_SECRET_NAME + objref: + kind: Secret + name: webhook-server-secret + apiVersion: v1 diff --git a/components/profile-controller/config/default/manager_auth_proxy_patch.yaml b/components/profile-controller/config/default/manager_auth_proxy_patch.yaml new file mode 100644 index 00000000000..eeeba7060af --- /dev/null +++ b/components/profile-controller/config/default/manager_auth_proxy_patch.yaml @@ -0,0 +1,24 @@ +# This patch inject a sidecar container which is a HTTP proxy for the controller manager, +# it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + image: quay.io/brancz/kube-rbac-proxy:v0.4.0 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=10" + ports: + - containerPort: 8443 + name: https + - name: manager + args: + - "--metrics-addr=127.0.0.1:8080" diff --git a/components/profile-controller/config/default/manager_image_patch.yaml b/components/profile-controller/config/default/manager_image_patch.yaml new file mode 100644 index 00000000000..fcbf39dc6a5 --- /dev/null +++ b/components/profile-controller/config/default/manager_image_patch.yaml @@ -0,0 +1,12 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + # Change the value of image field below to your controller image URL + - image: IMAGE_URL + name: manager diff --git a/components/profile-controller/config/default/manager_prometheus_metrics_patch.yaml b/components/profile-controller/config/default/manager_prometheus_metrics_patch.yaml new file mode 100644 index 00000000000..96fdcdac9d9 --- /dev/null +++ b/components/profile-controller/config/default/manager_prometheus_metrics_patch.yaml @@ -0,0 +1,19 @@ +# This patch enables Prometheus scraping for the manager pod. +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: controller-manager + namespace: system +spec: + template: + metadata: + annotations: + prometheus.io/scrape: 'true' + spec: + containers: + # Expose the prometheus metrics on default port + - name: manager + ports: + - containerPort: 8080 + name: metrics + protocol: TCP diff --git a/components/profile-controller/config/manager/manager.yaml b/components/profile-controller/config/manager/manager.yaml new file mode 100644 index 00000000000..3935ac6b028 --- /dev/null +++ b/components/profile-controller/config/manager/manager.yaml @@ -0,0 +1,82 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: system +--- +apiVersion: v1 +kind: Service +metadata: + name: controller-manager-service + namespace: system + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" +spec: + selector: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" + ports: + - port: 443 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: controller-manager + namespace: system + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" +spec: + selector: + matchLabels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" + serviceName: controller-manager-service + template: + metadata: + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" + spec: + containers: + - command: + - /manager + image: controller:latest + imagePullPolicy: Always + name: manager + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SECRET_NAME + value: $(WEBHOOK_SECRET_NAME) + resources: + limits: + cpu: 100m + memory: 30Mi + requests: + cpu: 100m + memory: 20Mi + ports: + - containerPort: 9876 + name: webhook-server + protocol: TCP + volumeMounts: + - mountPath: /tmp/cert + name: cert + readOnly: true + terminationGracePeriodSeconds: 10 + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-secret +--- +apiVersion: v1 +kind: Secret +metadata: + name: webhook-server-secret + namespace: system diff --git a/components/profile-controller/config/rbac/auth_proxy_role.yaml b/components/profile-controller/config/rbac/auth_proxy_role.yaml new file mode 100644 index 00000000000..618f5e4177c --- /dev/null +++ b/components/profile-controller/config/rbac/auth_proxy_role.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: proxy-role +rules: +- apiGroups: ["authentication.k8s.io"] + resources: + - tokenreviews + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: + - subjectaccessreviews + verbs: ["create"] diff --git a/components/profile-controller/config/rbac/auth_proxy_role_binding.yaml b/components/profile-controller/config/rbac/auth_proxy_role_binding.yaml new file mode 100644 index 00000000000..48ed1e4b85c --- /dev/null +++ b/components/profile-controller/config/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: default + namespace: system diff --git a/components/profile-controller/config/rbac/auth_proxy_service.yaml b/components/profile-controller/config/rbac/auth_proxy_service.yaml new file mode 100644 index 00000000000..027073f9528 --- /dev/null +++ b/components/profile-controller/config/rbac/auth_proxy_service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/port: "8443" + prometheus.io/scheme: https + prometheus.io/scrape: "true" + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" diff --git a/components/profile-controller/config/rbac/rbac_role.yaml b/components/profile-controller/config/rbac/rbac_role.yaml new file mode 100644 index 00000000000..35019132bc9 --- /dev/null +++ b/components/profile-controller/config/rbac/rbac_role.yaml @@ -0,0 +1,43 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: manager-role +rules: +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - watch + - create + - update + - patch + - delete diff --git a/components/profile-controller/config/rbac/rbac_role_binding.yaml b/components/profile-controller/config/rbac/rbac_role_binding.yaml new file mode 100644 index 00000000000..c1033e23fb9 --- /dev/null +++ b/components/profile-controller/config/rbac/rbac_role_binding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + creationTimestamp: null + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: +- kind: ServiceAccount + name: default + namespace: system diff --git a/components/profile-controller/go.mod b/components/profile-controller/go.mod new file mode 100644 index 00000000000..e061978d30e --- /dev/null +++ b/components/profile-controller/go.mod @@ -0,0 +1,72 @@ +module github.com/kubeflow/kubeflow/components/profile-controller + +require ( + cloud.google.com/go v0.36.0 + github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30 + github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 + github.com/davecgh/go-spew v1.1.1 + github.com/emicklei/go-restful v2.9.0+incompatible + github.com/ghodss/yaml v1.0.0 + github.com/go-logr/logr v0.1.0 + github.com/go-logr/zapr v0.1.0 + github.com/gobuffalo/envy v1.6.15 + github.com/gogo/protobuf v1.2.1 + github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef + github.com/golang/protobuf v1.2.0 + github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c + github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf + github.com/google/uuid v1.1.0 + github.com/googleapis/gnostic v0.2.0 + github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc + github.com/hashicorp/golang-lru v0.5.0 + github.com/hpcloud/tail v1.0.0 + github.com/imdario/mergo v0.3.7 + github.com/inconshreveable/mousetrap v1.0.0 + github.com/joho/godotenv v1.3.0 + github.com/json-iterator/go v1.1.5 + github.com/markbates/inflect v1.0.4 + github.com/matttproud/golang_protobuf_extensions v1.0.1 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd + github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 + github.com/onsi/ginkgo v1.7.0 + github.com/onsi/gomega v1.4.3 + github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 + github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c + github.com/peterbourgon/diskv v2.0.1+incompatible + github.com/pkg/errors v0.8.1 + github.com/prometheus/client_golang v0.9.2 + github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 + github.com/prometheus/common v0.2.0 + github.com/prometheus/procfs v0.0.0-20190219184716-e4d4a2206da0 + github.com/rogpeppe/go-internal v1.2.2 + github.com/spf13/afero v1.2.1 + github.com/spf13/cobra v0.0.3 + github.com/spf13/pflag v1.0.3 + go.uber.org/atomic v1.3.2 + go.uber.org/multierr v1.1.0 + go.uber.org/zap v1.9.1 + golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 + golang.org/x/net v0.0.0-20190213061140-3a22650c66bd + golang.org/x/oauth2 v0.0.0-20190219183015-4b83411ed2b3 + golang.org/x/sys v0.0.0-20190219203350-90b0e4468f99 + golang.org/x/text v0.3.0 + golang.org/x/time v0.0.0-20181108054448-85acf8d2951c + golang.org/x/tools v0.0.0-20190219185102-9394956cfdc5 + google.golang.org/appengine v1.4.0 + gopkg.in/fsnotify.v1 v1.4.7 + gopkg.in/inf.v0 v0.9.1 + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 + gopkg.in/yaml.v2 v2.2.2 + k8s.io/api v0.0.0-20181213150558-05914d821849 + k8s.io/apiextensions-apiserver v0.0.0-20181213153335-0fe22c71c476 + k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 + k8s.io/client-go v0.0.0-20181213151034-8d9ed539ba31 + k8s.io/code-generator v0.0.0-20190215220509-095ce2f23e83 + k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 + k8s.io/klog v0.2.0 + k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668 + sigs.k8s.io/controller-runtime v0.1.10 + sigs.k8s.io/controller-tools v0.1.9 + sigs.k8s.io/testing_frameworks v0.1.1 + sigs.k8s.io/yaml v1.1.0 +) diff --git a/components/profile-controller/hack/boilerplate.go.txt b/components/profile-controller/hack/boilerplate.go.txt new file mode 100644 index 00000000000..3defa04283f --- /dev/null +++ b/components/profile-controller/hack/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright 2019 The Kubeflow 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. +*/ \ No newline at end of file diff --git a/components/profile-controller/pkg/apis/apis.go b/components/profile-controller/pkg/apis/apis.go new file mode 100644 index 00000000000..bfd9b5549c9 --- /dev/null +++ b/components/profile-controller/pkg/apis/apis.go @@ -0,0 +1,33 @@ +/* +Copyright 2019 The Kubeflow 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. +*/ + +// Generate deepcopy for apis +//go:generate go run ../../vendor/k8s.io/code-generator/cmd/deepcopy-gen/main.go -O zz_generated.deepcopy -i ./... -h ../../hack/boilerplate.go.txt + +// Package apis contains Kubernetes API groups. +package apis + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// AddToSchemes may be used to add all resources defined in the project to a Scheme +var AddToSchemes runtime.SchemeBuilder + +// AddToScheme adds all Resources to the Scheme +func AddToScheme(s *runtime.Scheme) error { + return AddToSchemes.AddToScheme(s) +} diff --git a/components/profile-controller/pkg/controller/controller.go b/components/profile-controller/pkg/controller/controller.go new file mode 100644 index 00000000000..c960a699da4 --- /dev/null +++ b/components/profile-controller/pkg/controller/controller.go @@ -0,0 +1,34 @@ +/* +Copyright 2019 The Kubeflow 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 controller + +import ( + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +// AddToManagerFuncs is a list of functions to add all Controllers to the Manager +var AddToManagerFuncs []func(manager.Manager) error + +// AddToManager adds all Controllers to the Manager +func AddToManager(m manager.Manager) error { + for _, f := range AddToManagerFuncs { + if err := f(m); err != nil { + return err + } + } + return nil +} diff --git a/components/profile-controller/pkg/webhook/webhook.go b/components/profile-controller/pkg/webhook/webhook.go new file mode 100644 index 00000000000..8d9572b8b5c --- /dev/null +++ b/components/profile-controller/pkg/webhook/webhook.go @@ -0,0 +1,37 @@ +/* +Copyright 2019 The Kubeflow 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 webhook + +import ( + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +// AddToManagerFuncs is a list of functions to add all Controllers to the Manager +var AddToManagerFuncs []func(manager.Manager) error + +// AddToManager adds all Controllers to the Manager +// +kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=mutatingwebhookconfigurations;validatingwebhookconfigurations,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups="",resources=services,verbs=get;list;watch;create;update;patch;delete +func AddToManager(m manager.Manager) error { + for _, f := range AddToManagerFuncs { + if err := f(m); err != nil { + return err + } + } + return nil +} From d363b1212a01a26912a4f6b205e12c31d1847e41 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Wed, 20 Feb 2019 17:02:20 -0800 Subject: [PATCH 02/13] create api --- .../crds/kubeflow_v1alpha1_profile.yaml | 39 ++++ .../config/rbac/rbac_role.yaml | 40 +++++ .../samples/kubeflow_v1alpha1_profile.yaml | 9 + .../pkg/apis/addtoscheme_kubeflow_v1alpha1.go | 26 +++ .../pkg/apis/kubeflow/group.go | 18 ++ .../pkg/apis/kubeflow/v1alpha1/doc.go | 23 +++ .../apis/kubeflow/v1alpha1/profile_types.go | 62 +++++++ .../kubeflow/v1alpha1/profile_types_test.go | 58 ++++++ .../pkg/apis/kubeflow/v1alpha1/register.go | 46 +++++ .../kubeflow/v1alpha1/v1alpha1_suite_test.go | 55 ++++++ .../v1alpha1/zz_generated.deepcopy.go | 117 ++++++++++++ .../pkg/controller/add_profile.go | 26 +++ .../controller/profile/profile_controller.go | 169 ++++++++++++++++++ .../profile/profile_controller_suite_test.go | 75 ++++++++ .../profile/profile_controller_test.go | 87 +++++++++ 15 files changed, 850 insertions(+) create mode 100644 components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml create mode 100644 components/profile-controller/config/samples/kubeflow_v1alpha1_profile.yaml create mode 100644 components/profile-controller/pkg/apis/addtoscheme_kubeflow_v1alpha1.go create mode 100644 components/profile-controller/pkg/apis/kubeflow/group.go create mode 100644 components/profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go create mode 100644 components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go create mode 100644 components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types_test.go create mode 100644 components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go create mode 100644 components/profile-controller/pkg/apis/kubeflow/v1alpha1/v1alpha1_suite_test.go create mode 100644 components/profile-controller/pkg/apis/kubeflow/v1alpha1/zz_generated.deepcopy.go create mode 100644 components/profile-controller/pkg/controller/add_profile.go create mode 100644 components/profile-controller/pkg/controller/profile/profile_controller.go create mode 100644 components/profile-controller/pkg/controller/profile/profile_controller_suite_test.go create mode 100644 components/profile-controller/pkg/controller/profile/profile_controller_test.go diff --git a/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml b/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml new file mode 100644 index 00000000000..ceb6f56ddea --- /dev/null +++ b/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml @@ -0,0 +1,39 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + controller-tools.k8s.io: "1.0" + name: profiles.kubeflow.kubeflow.org +spec: + group: kubeflow.kubeflow.org + names: + kind: Profile + plural: profiles + scope: Namespaced + 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: + type: object + status: + type: object + version: v1alpha1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/components/profile-controller/config/rbac/rbac_role.yaml b/components/profile-controller/config/rbac/rbac_role.yaml index 35019132bc9..5e8f324507b 100644 --- a/components/profile-controller/config/rbac/rbac_role.yaml +++ b/components/profile-controller/config/rbac/rbac_role.yaml @@ -4,6 +4,46 @@ metadata: creationTimestamp: null name: manager-role rules: +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - apps + resources: + - deployments/status + verbs: + - get + - update + - patch +- apiGroups: + - kubeflow.kubeflow.org + resources: + - profiles + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - kubeflow.kubeflow.org + resources: + - profiles/status + verbs: + - get + - update + - patch - apiGroups: - admissionregistration.k8s.io resources: diff --git a/components/profile-controller/config/samples/kubeflow_v1alpha1_profile.yaml b/components/profile-controller/config/samples/kubeflow_v1alpha1_profile.yaml new file mode 100644 index 00000000000..dd530be2d01 --- /dev/null +++ b/components/profile-controller/config/samples/kubeflow_v1alpha1_profile.yaml @@ -0,0 +1,9 @@ +apiVersion: kubeflow.kubeflow.org/v1alpha1 +kind: Profile +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: profile-sample +spec: + # Add fields here + foo: bar diff --git a/components/profile-controller/pkg/apis/addtoscheme_kubeflow_v1alpha1.go b/components/profile-controller/pkg/apis/addtoscheme_kubeflow_v1alpha1.go new file mode 100644 index 00000000000..4475129e650 --- /dev/null +++ b/components/profile-controller/pkg/apis/addtoscheme_kubeflow_v1alpha1.go @@ -0,0 +1,26 @@ +/* +Copyright 2019 The Kubeflow 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 apis + +import ( + "github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow/v1alpha1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme) +} diff --git a/components/profile-controller/pkg/apis/kubeflow/group.go b/components/profile-controller/pkg/apis/kubeflow/group.go new file mode 100644 index 00000000000..7d2bf37e81b --- /dev/null +++ b/components/profile-controller/pkg/apis/kubeflow/group.go @@ -0,0 +1,18 @@ +/* +Copyright 2019 The Kubeflow 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 kubeflow contains kubeflow API versions +package kubeflow diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go new file mode 100644 index 00000000000..bea9fb8522c --- /dev/null +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2019 The Kubeflow 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 v1alpha1 contains API Schema definitions for the kubeflow v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow +// +k8s:defaulter-gen=TypeMeta +// +groupName=kubeflow.kubeflow.org +package v1alpha1 diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go new file mode 100644 index 00000000000..30cecf0e41a --- /dev/null +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go @@ -0,0 +1,62 @@ +/* +Copyright 2019 The Kubeflow 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ProfileSpec defines the desired state of Profile +type ProfileSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +// ProfileStatus defines the observed state of Profile +type ProfileStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Profile is the Schema for the profiles API +// +k8s:openapi-gen=true +type Profile struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ProfileSpec `json:"spec,omitempty"` + Status ProfileStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ProfileList contains a list of Profile +type ProfileList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Profile `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Profile{}, &ProfileList{}) +} diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types_test.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types_test.go new file mode 100644 index 00000000000..4de7c737fae --- /dev/null +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types_test.go @@ -0,0 +1,58 @@ +/* +Copyright 2019 The Kubeflow 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 v1alpha1 + +import ( + "testing" + + "github.com/onsi/gomega" + "golang.org/x/net/context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +func TestStorageProfile(t *testing.T) { + key := types.NamespacedName{ + Name: "foo", + Namespace: "default", + } + created := &Profile{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }} + g := gomega.NewGomegaWithT(t) + + // Test Create + fetched := &Profile{} + g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred()) + + g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred()) + g.Expect(fetched).To(gomega.Equal(created)) + + // Test Updating the Labels + updated := fetched.DeepCopy() + updated.Labels = map[string]string{"hello": "world"} + g.Expect(c.Update(context.TODO(), updated)).NotTo(gomega.HaveOccurred()) + + g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred()) + g.Expect(fetched).To(gomega.Equal(updated)) + + // Test Delete + g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred()) + g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred()) +} diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go new file mode 100644 index 00000000000..e41344681bd --- /dev/null +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go @@ -0,0 +1,46 @@ +/* +Copyright 2019 The Kubeflow 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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// Package v1alpha1 contains API Schema definitions for the kubeflow v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow +// +k8s:defaulter-gen=TypeMeta +// +groupName=kubeflow.kubeflow.org +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "kubeflow.kubeflow.org", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + + // AddToScheme is required by pkg/client/... + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource is required by pkg/client/listers/... +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/v1alpha1_suite_test.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/v1alpha1_suite_test.go new file mode 100644 index 00000000000..64db2285500 --- /dev/null +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/v1alpha1_suite_test.go @@ -0,0 +1,55 @@ +/* +Copyright 2019 The Kubeflow 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 v1alpha1 + +import ( + "log" + "os" + "path/filepath" + "testing" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" +) + +var cfg *rest.Config +var c client.Client + +func TestMain(m *testing.M) { + t := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "config", "crds")}, + } + + err := SchemeBuilder.AddToScheme(scheme.Scheme) + if err != nil { + log.Fatal(err) + } + + if cfg, err = t.Start(); err != nil { + log.Fatal(err) + } + + if c, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}); err != nil { + log.Fatal(err) + } + + code := m.Run() + t.Stop() + os.Exit(code) +} diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/zz_generated.deepcopy.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..055ec8003e3 --- /dev/null +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,117 @@ +// +build !ignore_autogenerated + +/* +Copyright 2019 The Kubeflow 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. +*/ +// Code generated by main. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Profile) DeepCopyInto(out *Profile) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Profile. +func (in *Profile) DeepCopy() *Profile { + if in == nil { + return nil + } + out := new(Profile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Profile) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProfileList) DeepCopyInto(out *ProfileList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Profile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProfileList. +func (in *ProfileList) DeepCopy() *ProfileList { + if in == nil { + return nil + } + out := new(ProfileList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ProfileList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProfileSpec) DeepCopyInto(out *ProfileSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProfileSpec. +func (in *ProfileSpec) DeepCopy() *ProfileSpec { + if in == nil { + return nil + } + out := new(ProfileSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProfileStatus) DeepCopyInto(out *ProfileStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProfileStatus. +func (in *ProfileStatus) DeepCopy() *ProfileStatus { + if in == nil { + return nil + } + out := new(ProfileStatus) + in.DeepCopyInto(out) + return out +} diff --git a/components/profile-controller/pkg/controller/add_profile.go b/components/profile-controller/pkg/controller/add_profile.go new file mode 100644 index 00000000000..b5f66a86c9c --- /dev/null +++ b/components/profile-controller/pkg/controller/add_profile.go @@ -0,0 +1,26 @@ +/* +Copyright 2019 The Kubeflow 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 controller + +import ( + "github.com/kubeflow/kubeflow/components/profile-controller/pkg/controller/profile" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, profile.Add) +} diff --git a/components/profile-controller/pkg/controller/profile/profile_controller.go b/components/profile-controller/pkg/controller/profile/profile_controller.go new file mode 100644 index 00000000000..fb7ba86f44d --- /dev/null +++ b/components/profile-controller/pkg/controller/profile/profile_controller.go @@ -0,0 +1,169 @@ +/* +Copyright 2019 The Kubeflow 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 profile + +import ( + "context" + "reflect" + + kubeflowv1alpha1 "github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow/v1alpha1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +var log = logf.Log.WithName("controller") + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new Profile Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileProfile{Client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("profile-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to Profile + err = c.Watch(&source.Kind{Type: &kubeflowv1alpha1.Profile{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create + // Uncomment watch a Deployment created by Profile - change this for objects you create + err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &kubeflowv1alpha1.Profile{}, + }) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileProfile{} + +// ReconcileProfile reconciles a Profile object +type ReconcileProfile struct { + client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a Profile object and makes changes based on the state read +// and what is in the Profile.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes +// a Deployment as an example +// Automatically generate RBAC rules to allow the Controller to read and write Deployments +// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=kubeflow.kubeflow.org,resources=profiles,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=kubeflow.kubeflow.org,resources=profiles/status,verbs=get;update;patch +func (r *ReconcileProfile) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Fetch the Profile instance + instance := &kubeflowv1alpha1.Profile{} + err := r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + // TODO(user): Change this to be the object type created by your controller + // Define the desired Deployment object + deploy := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: instance.Name + "-deployment", + Namespace: instance.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"deployment": instance.Name + "-deployment"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"deployment": instance.Name + "-deployment"}}, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "nginx", + Image: "nginx", + }, + }, + }, + }, + }, + } + if err := controllerutil.SetControllerReference(instance, deploy, r.scheme); err != nil { + return reconcile.Result{}, err + } + + // TODO(user): Change this for the object type created by your controller + // Check if the Deployment already exists + found := &appsv1.Deployment{} + err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found) + if err != nil && errors.IsNotFound(err) { + log.Info("Creating Deployment", "namespace", deploy.Namespace, "name", deploy.Name) + err = r.Create(context.TODO(), deploy) + if err != nil { + return reconcile.Result{}, err + } + } else if err != nil { + return reconcile.Result{}, err + } + + // TODO(user): Change this for the object type created by your controller + // Update the found object and write the result back if there are any changes + if !reflect.DeepEqual(deploy.Spec, found.Spec) { + found.Spec = deploy.Spec + log.Info("Updating Deployment", "namespace", deploy.Namespace, "name", deploy.Name) + err = r.Update(context.TODO(), found) + if err != nil { + return reconcile.Result{}, err + } + } + return reconcile.Result{}, nil +} diff --git a/components/profile-controller/pkg/controller/profile/profile_controller_suite_test.go b/components/profile-controller/pkg/controller/profile/profile_controller_suite_test.go new file mode 100644 index 00000000000..00c2d58aa22 --- /dev/null +++ b/components/profile-controller/pkg/controller/profile/profile_controller_suite_test.go @@ -0,0 +1,75 @@ +/* +Copyright 2019 The Kubeflow 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 profile + +import ( + stdlog "log" + "os" + "path/filepath" + "sync" + "testing" + + "github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis" + "github.com/onsi/gomega" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +var cfg *rest.Config + +func TestMain(m *testing.M) { + t := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")}, + } + apis.AddToScheme(scheme.Scheme) + + var err error + if cfg, err = t.Start(); err != nil { + stdlog.Fatal(err) + } + + code := m.Run() + t.Stop() + os.Exit(code) +} + +// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and +// writes the request to requests after Reconcile is finished. +func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) { + requests := make(chan reconcile.Request) + fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) { + result, err := inner.Reconcile(req) + requests <- req + return result, err + }) + return fn, requests +} + +// StartTestManager adds recFn +func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) { + stop := make(chan struct{}) + wg := &sync.WaitGroup{} + go func() { + wg.Add(1) + g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred()) + wg.Done() + }() + return stop, wg +} diff --git a/components/profile-controller/pkg/controller/profile/profile_controller_test.go b/components/profile-controller/pkg/controller/profile/profile_controller_test.go new file mode 100644 index 00000000000..5e673abe1a4 --- /dev/null +++ b/components/profile-controller/pkg/controller/profile/profile_controller_test.go @@ -0,0 +1,87 @@ +/* +Copyright 2019 The Kubeflow 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 profile + +import ( + "testing" + "time" + + kubeflowv1alpha1 "github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow/v1alpha1" + "github.com/onsi/gomega" + "golang.org/x/net/context" + appsv1 "k8s.io/api/apps/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +var c client.Client + +var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}} +var depKey = types.NamespacedName{Name: "foo-deployment", Namespace: "default"} + +const timeout = time.Second * 5 + +func TestReconcile(t *testing.T) { + g := gomega.NewGomegaWithT(t) + instance := &kubeflowv1alpha1.Profile{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} + + // Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a + // channel when it is finished. + mgr, err := manager.New(cfg, manager.Options{}) + g.Expect(err).NotTo(gomega.HaveOccurred()) + c = mgr.GetClient() + + recFn, requests := SetupTestReconcile(newReconciler(mgr)) + g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred()) + + stopMgr, mgrStopped := StartTestManager(mgr, g) + + defer func() { + close(stopMgr) + mgrStopped.Wait() + }() + + // Create the Profile object and expect the Reconcile and Deployment to be created + err = c.Create(context.TODO(), instance) + // The instance object may not be a valid object because it might be missing some required fields. + // Please modify the instance object by adding required fields and then remove the following if statement. + if apierrors.IsInvalid(err) { + t.Logf("failed to create object, got an invalid object error: %v", err) + return + } + g.Expect(err).NotTo(gomega.HaveOccurred()) + defer c.Delete(context.TODO(), instance) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + + deploy := &appsv1.Deployment{} + g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout). + Should(gomega.Succeed()) + + // Delete the Deployment and expect Reconcile to be called for Deployment deletion + g.Expect(c.Delete(context.TODO(), deploy)).NotTo(gomega.HaveOccurred()) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout). + Should(gomega.Succeed()) + + // Manually delete Deployment since GC isn't enabled in the test control plane + g.Expect(c.Delete(context.TODO(), deploy)).To(gomega.Succeed()) + +} From e3d48c5be484abc104672624cd4be362d9fbd331 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Thu, 21 Feb 2019 16:12:59 -0800 Subject: [PATCH 03/13] wip --- components/profile-controller/go.mod | 4 +- components/profile-controller/go.sum | 284 ++++++++++++++ .../apis/kubeflow/v1alpha1/profile_types.go | 11 +- .../v1alpha1/zz_generated.deepcopy.go | 1 + .../controller/profile/profile_controller.go | 361 ++++++++++++++++-- 5 files changed, 616 insertions(+), 45 deletions(-) create mode 100644 components/profile-controller/go.sum diff --git a/components/profile-controller/go.mod b/components/profile-controller/go.mod index e061978d30e..b0c27116d23 100644 --- a/components/profile-controller/go.mod +++ b/components/profile-controller/go.mod @@ -49,7 +49,7 @@ require ( golang.org/x/net v0.0.0-20190213061140-3a22650c66bd golang.org/x/oauth2 v0.0.0-20190219183015-4b83411ed2b3 golang.org/x/sys v0.0.0-20190219203350-90b0e4468f99 - golang.org/x/text v0.3.0 + golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c golang.org/x/tools v0.0.0-20190219185102-9394956cfdc5 google.golang.org/appengine v1.4.0 @@ -59,7 +59,7 @@ require ( gopkg.in/yaml.v2 v2.2.2 k8s.io/api v0.0.0-20181213150558-05914d821849 k8s.io/apiextensions-apiserver v0.0.0-20181213153335-0fe22c71c476 - k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 + k8s.io/apimachinery v0.0.0-20190221093215-450d01ad5771 k8s.io/client-go v0.0.0-20181213151034-8d9ed539ba31 k8s.io/code-generator v0.0.0-20190215220509-095ce2f23e83 k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 diff --git a/components/profile-controller/go.sum b/components/profile-controller/go.sum new file mode 100644 index 00000000000..f4787f1657d --- /dev/null +++ b/components/profile-controller/go.sum @@ -0,0 +1,284 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.36.0 h1:+aCSj7tOo2LODWVEuZDZeGCckdt6MlSF+X/rB3wUiS8= +cloud.google.com/go v0.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30 h1:Kn3rqvbUFqSepE2OqVu0Pn1CbDw9IuMlONapol0zuwk= +github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30/go.mod h1:4AJxUpXUhv4N+ziTvIcWWXgeorXpxPZOfk9HdEVr96M= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/emicklei/go-restful v2.9.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/evanphx/json-patch v4.0.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= +github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= +github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 h1:zNBQb37RGLmJybyMcs983HfUfpkw9OTFD9tbBfAViHE= +github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190219184716-e4d4a2206da0 h1:4+Tdy73otddqWxwK30bAMLH9ymeHQ1Y5+fmSoCF1XtU= +github.com/prometheus/procfs v0.0.0-20190219184716-e4d4a2206da0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 h1:NwxKRvbkH5MsNkvOtPZi3/3kmI8CAzs3mtv+GLQMkNo= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190219183015-4b83411ed2b3 h1:OFrJ/rEn4wUq1PbIHcIdfOGIy3uCTe5XOealV2ngn/w= +golang.org/x/oauth2 v0.0.0-20190219183015-4b83411ed2b3/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219203350-90b0e4468f99 h1:mlL4HvR5ojTCLdWRydhoj7jto5SXLsxLc0b1r/3DNlE= +golang.org/x/sys v0.0.0-20190219203350-90b0e4468f99/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190219185102-9394956cfdc5 h1:b4GZ2lQCm9+A7Et8ySqSq+t8f3wN+q56prDeN1DPAhQ= +golang.org/x/tools v0.0.0-20190219185102-9394956cfdc5/go.mod h1:E6PF97AdD6v0s+fPshSmumCW1S1Ne85RbPQxELkKa44= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.0.0-20181213150558-05914d821849 h1:WZFcFPXmLR7g5CxQNmjWv0mg8qulJLxDghbzS4pQtzY= +k8s.io/api v0.0.0-20181213150558-05914d821849/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apiextensions-apiserver v0.0.0-20181213153335-0fe22c71c476 h1:Ws9zfxsgV19Durts9ftyTG7TO0A/QLhmu98VqNWLiH8= +k8s.io/apiextensions-apiserver v0.0.0-20181213153335-0fe22c71c476/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 h1:tT6oQBi0qwLbbZSfDkdIsb23EwaLY85hoAV4SpXfdao= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20190221093215-450d01ad5771 h1:XMECjVNpkFVT9uY40z07scw8Xtn2mUnkxx8BC3gjwoE= +k8s.io/apimachinery v0.0.0-20190221093215-450d01ad5771/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/client-go v0.0.0-20181213151034-8d9ed539ba31 h1:OH3z6khCtxnJBAc0C5CMYWLl1CoK5R5fngX7wrwdN5c= +k8s.io/client-go v0.0.0-20181213151034-8d9ed539ba31/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/code-generator v0.0.0-20190215220509-095ce2f23e83 h1:nIYxtB9HoX2UqCnuF6bm1Zev6RNa/FLv1Dp92yNl9YQ= +k8s.io/code-generator v0.0.0-20190215220509-095ce2f23e83/go.mod h1:MYiN+ZJZ9HkETbgVZdWw2AsuAi9PZ4V80cwfuf2axe8= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c= +k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668 h1:M80qeWaBNOX2Uc4plRHcb6k+3YE5VWMaJXKZo+tX9aU= +k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +sigs.k8s.io/controller-runtime v0.1.10 h1:amLOmcekVdnsD1uIpmgRqfTbQWJ2qxvQkcdeFhcotn4= +sigs.k8s.io/controller-runtime v0.1.10/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8= +sigs.k8s.io/controller-tools v0.1.9/go.mod h1:6g08p9m9G/So3sBc1AOQifHfhxH/mb6Sc4z0LMI8XMw= +sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs= +sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go index 30cecf0e41a..10d9fbe229b 100644 --- a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go @@ -17,16 +17,17 @@ limitations under the License. package v1alpha1 import ( + rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - // ProfileSpec defines the desired state of Profile type ProfileSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file + // The namespace for this user + Namespace string `json:"namespace,omitempty"` + + // The profile owner + Owner rbacv1.Subject `json:"owner,omitempty"` } // ProfileStatus defines the observed state of Profile diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/zz_generated.deepcopy.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/zz_generated.deepcopy.go index 055ec8003e3..9ac7a9afceb 100644 --- a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/zz_generated.deepcopy.go +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/zz_generated.deepcopy.go @@ -87,6 +87,7 @@ func (in *ProfileList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProfileSpec) DeepCopyInto(out *ProfileSpec) { *out = *in + out.Owner = in.Owner return } diff --git a/components/profile-controller/pkg/controller/profile/profile_controller.go b/components/profile-controller/pkg/controller/profile/profile_controller.go index fb7ba86f44d..47edbf57945 100644 --- a/components/profile-controller/pkg/controller/profile/profile_controller.go +++ b/components/profile-controller/pkg/controller/profile/profile_controller.go @@ -23,6 +23,7 @@ import ( kubeflowv1alpha1 "github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow/v1alpha1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -39,11 +40,6 @@ import ( var log = logf.Log.WithName("controller") -/** -* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller -* business logic. Delete these comments after modifying this file.* - */ - // Add creates a new Profile Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager) error { @@ -113,53 +109,83 @@ func (r *ReconcileProfile) Reconcile(request reconcile.Request) (reconcile.Resul return reconcile.Result{}, err } - // TODO(user): Change this to be the object type created by your controller - // Define the desired Deployment object - deploy := &appsv1.Deployment{ + ns := corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - Name: instance.Name + "-deployment", - Namespace: instance.Namespace, - }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"deployment": instance.Name + "-deployment"}, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"deployment": instance.Name + "-deployment"}}, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "nginx", - Image: "nginx", - }, - }, - }, - }, + Name: instance.Spec.Namespace, }, } - if err := controllerutil.SetControllerReference(instance, deploy, r.scheme); err != nil { + if err := controllerutil.SetControllerReference(instance, ns, r.scheme); err != nil { + return reconcile.Result{}, err + } + foundNs := &corev1.Namespace{} + err = r.Get(context.TODO(), types.Name{Name: ns.Name}, foundNs) + if err != nil && errors.IsNotFound(err) { + log.Info("Creating Namespace: " + ns.Name) + err = r.Create(context.TODO(), ns) + if err != nil { + return reconcile.Result{}, err + } + } else if err != nil { return reconcile.Result{}, err } + // No need to update namespace - // TODO(user): Change this for the object type created by your controller - // Check if the Deployment already exists - found := &appsv1.Deployment{} - err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found) + role := generateRole(instance) + if err := controllerutil.SetControllerReference(instance, role, r.scheme); err != nil { + return reconcile.Result{}, err + } + foundRole := &rbacv1.Role{} + err = r.Get(context.TODO(), types.NamespacedName{Name: role.Name, Namespace: role.Namespace}, foundRole) if err != nil && errors.IsNotFound(err) { - log.Info("Creating Deployment", "namespace", deploy.Namespace, "name", deploy.Name) - err = r.Create(context.TODO(), deploy) + log.Info("Creating Role", "namespace", role.Namespace, "name", role.Name) + err = r.Create(context.TODO(), role) if err != nil { return reconcile.Result{}, err } } else if err != nil { return reconcile.Result{}, err } + if !reflect.DeepEqual(role.Rules, foundRole.Rules) { + foundRole.Rules = role.Rules + log.Info("Updating Role", "namespace", role.Namespace, "name", role.Name) + err = r.Update(context.TODO(), foundRole) + if err != nil { + return reconcile.Result{}, err + } + } - // TODO(user): Change this for the object type created by your controller - // Update the found object and write the result back if there are any changes - if !reflect.DeepEqual(deploy.Spec, found.Spec) { - found.Spec = deploy.Spec - log.Info("Updating Deployment", "namespace", deploy.Namespace, "name", deploy.Name) + roleBinding := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Namespace: instance.Spec.Namespace, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "edit", + }, + Subjects: []rbacv1.Subject{ + instance.Spec.Owner, + }, + } + if err := controllerutil.SetControllerReference(instance, roleBinding, r.scheme); err != nil { + return reconcile.Result{}, err + } + found := &rbacv1.RoleBinding{} + err = r.Get(context.TODO(), types.NamespacedName{Name: roleBinding.Name, Namespace: roleBinding.Namespace}, found) + if err != nil && errors.IsNotFound(err) { + log.Info("Creating RoleBinding", "namespace", roleBinding.Namespace, "name", roleBinding.Name) + err = r.Create(context.TODO(), roleBinding) + if err != nil { + return reconcile.Result{}, err + } + } else if err != nil { + return reconcile.Result{}, err + } + if !(reflect.DeepEqual(roleBinding.RoleRef, found.RoleRef) && reflect.DeepEqual(roleBinding.Subjects, found.Subjects)) { + found.RoleRef = roleBinding.RoleRef + found.Subjects = roleBinding.Subjects + log.Info("Updating RoleBinding", "namespace", roleBinding.Namespace, "name", roleBinding.Name) err = r.Update(context.TODO(), found) if err != nil { return reconcile.Result{}, err @@ -167,3 +193,262 @@ func (r *ReconcileProfile) Reconcile(request reconcile.Request) (reconcile.Resul } return reconcile.Result{}, nil } + +func generateRole(instance *kubeflowv1alpha1.Profile) *rbacv1.Role { + role := &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "edit", + Namespace: instance.Spec.Namespace, + }, + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{ + "metacontroller.k8s.io", + }, + Resources: []string{ + "compositecontrollers", + "decoratecontrollers", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "kubeflow.org", + }, + Resources: []string{ + "notebooks", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "app.k8s.io", + }, + Resources: []string{ + "applications", + "apps", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "", + }, + Resources: []string{ + "pods", + "pods/attach", + "pods/exec", + "pods/portforward", + "pods/proxy", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "", + }, + Resources: []string{ + "configmaps", + "endpoints", + "persistentvolumeclaims", + "replicationcontrollers", + "replicationcontrollers/scale", + "secrets", + "serviceaccounts", + "services", + "services/proxy", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "", + }, + Resources: []string{ + "bindings", + "events", + "limitranges", + "pods/log", + "pods/status", + "replicationcontrollers/status", + "resourcequotas", + "resourcequotas/status", + }, + Verbs: []string{ + "get", + "list", + "watch", + }, + }, + { + APIGroups: []string{ + "", + }, + Resources: []string{ + "serviceaccounts", + }, + Verbs: []string{ + "impersonate", + }, + }, + { + APIGroups: []string{ + "apps", + }, + Resources: []string{ + "daemonsets", + "deployments", + "deployments/rollback", + "deployments/scale", + "replicasets", + "replicasets/scale", + "statefulsets", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "autoscaling", + }, + Resources: []string{ + "horizontalpodautoscalers", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "batch", + }, + Resources: []string{ + "cronjobs", + "jobs", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "extensions", + }, + Resources: []string{ + "daemonsets", + "deployments", + "deployments/rollback", + "deployments/scale", + "ingresses", + "networkpolicies", + "replicasets", + "replicasets/scale", + "replicationcontrollers/scale", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "policy", + }, + Resources: []string{ + "poddistruptionbudgets", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + { + APIGroups: []string{ + "networking.k8s.io", + }, + Resources: []string{ + "networkpolicies", + }, + Verbs: []string{ + "create", + "delete", + "get", + "list", + "patch", + "update", + "watch", + }, + }, + }, + } + return role +} From c64db59226a4bfc44a3aa5a9116f1c5ea2325b48 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Fri, 22 Feb 2019 13:36:54 -0800 Subject: [PATCH 04/13] fix --- .../pkg/controller/profile/profile_controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/profile-controller/pkg/controller/profile/profile_controller.go b/components/profile-controller/pkg/controller/profile/profile_controller.go index 47edbf57945..35413eb39cc 100644 --- a/components/profile-controller/pkg/controller/profile/profile_controller.go +++ b/components/profile-controller/pkg/controller/profile/profile_controller.go @@ -109,7 +109,7 @@ func (r *ReconcileProfile) Reconcile(request reconcile.Request) (reconcile.Resul return reconcile.Result{}, err } - ns := corev1.Namespace{ + ns := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: instance.Spec.Namespace, }, @@ -118,7 +118,7 @@ func (r *ReconcileProfile) Reconcile(request reconcile.Request) (reconcile.Resul return reconcile.Result{}, err } foundNs := &corev1.Namespace{} - err = r.Get(context.TODO(), types.Name{Name: ns.Name}, foundNs) + err = r.Get(context.TODO(), types.NamespacedName{Name: ns.Name}, foundNs) if err != nil && errors.IsNotFound(err) { log.Info("Creating Namespace: " + ns.Name) err = r.Create(context.TODO(), ns) From 3d6f6656da32faeadc4222789bb54794f908cd2d Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Fri, 22 Feb 2019 14:48:04 -0800 Subject: [PATCH 05/13] fix --- components/profile-controller/Dockerfile | 9 +- components/profile-controller/Makefile | 15 +- .../crds/kubeflow_v1alpha1_profile.yaml | 7 + components/profile-controller/go.sum | 8 + kubeflow/profiles/profiles.libsonnet | 297 ++++-------------- kubeflow/profiles/prototypes/profiles.jsonnet | 2 +- 6 files changed, 92 insertions(+), 246 deletions(-) diff --git a/components/profile-controller/Dockerfile b/components/profile-controller/Dockerfile index 83f7d979712..b697513d64d 100644 --- a/components/profile-controller/Dockerfile +++ b/components/profile-controller/Dockerfile @@ -1,14 +1,17 @@ # Build the manager binary -FROM golang:1.10.3 as builder +ARG GOLANG_VERSION=1.11.5 +FROM golang:${GOLANG_VERSION} as builder # Copy in the go src WORKDIR /go/src/github.com/kubeflow/kubeflow/components/profile-controller COPY pkg/ pkg/ COPY cmd/ cmd/ -COPY vendor/ vendor/ +COPY go.mod . + +ENV GO111MODULE=on # Build -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager github.com/kubeflow/kubeflow/components/profile-controller/cmd/manager +RUN go build -gcflags 'all=-N -l' -o manager cmd/manager/main.go # Copy the controller-manager into a thin image FROM ubuntu:latest diff --git a/components/profile-controller/Makefile b/components/profile-controller/Makefile index e684a74f62d..3ed57d02218 100644 --- a/components/profile-controller/Makefile +++ b/components/profile-controller/Makefile @@ -1,12 +1,15 @@ # Image URL to use all building/pushing image targets -IMG ?= controller:latest +IMG ?= gcr.io/kubeflow-images-public/notebook-controller +TAG ?= $(eval TAG := $(shell date +v%Y%m%d)-$(shell git describe --tags --always --dirty)-$(shell git diff | shasum -a256 | cut -c -6))$(TAG) +GOLANG_VERSION ?= 1.11.5 all: test manager # Run tests test: generate fmt vet manifests - go test ./pkg/... ./cmd/... -coverprofile cover.out + echo "Skip test..." + #go test ./pkg/... ./cmd/... -coverprofile cover.out # Build manager binary manager: generate fmt vet @@ -50,3 +53,11 @@ docker-build: test # Push the docker image docker-push: docker push ${IMG} + +build-gcr: test + docker build -t $(IMG):$(TAG) . + @echo Built $(IMG):$(TAG) + +push-gcr: build-gcr + docker push $(IMG):$(TAG) + @echo Pushed $(IMG):$(TAG) diff --git a/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml b/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml index ceb6f56ddea..f86e060fa39 100644 --- a/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml +++ b/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml @@ -27,6 +27,13 @@ spec: metadata: type: object spec: + properties: + namespace: + description: The namespace for this user + type: string + owner: + description: The profile owner + type: object type: object status: type: object diff --git a/components/profile-controller/go.sum b/components/profile-controller/go.sum index f4787f1657d..20fb888d8ae 100644 --- a/components/profile-controller/go.sum +++ b/components/profile-controller/go.sum @@ -38,6 +38,7 @@ github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.15 h1:OsV5vOpHYUpP7ZLS6sem1y40/lNX1BZj+ynMiRi21lQ= github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= @@ -79,6 +80,7 @@ github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -91,6 +93,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/markbates/inflect v1.0.4 h1:5fh1gzTFhfae06u3hzHYO9xe3l3v3nW5Pwt3naLTP5g= github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -114,6 +117,7 @@ github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzk github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -133,6 +137,7 @@ github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190219184716-e4d4a2206da0 h1:4+Tdy73otddqWxwK30bAMLH9ymeHQ1Y5+fmSoCF1XtU= github.com/prometheus/procfs v0.0.0-20190219184716-e4d4a2206da0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2 h1:J7U/N7eRtzjhs26d6GqMh2HBuXP8/Z64Densiiieafo= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -161,7 +166,9 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -275,6 +282,7 @@ k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668 h1:M80qeWaBNOX2Uc4plRHcb6 k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= sigs.k8s.io/controller-runtime v0.1.10 h1:amLOmcekVdnsD1uIpmgRqfTbQWJ2qxvQkcdeFhcotn4= sigs.k8s.io/controller-runtime v0.1.10/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8= +sigs.k8s.io/controller-tools v0.1.9 h1:1MLDl41OqveAqWA1urQ3KU58fM5NMZF1/NDdVyWRY5Q= sigs.k8s.io/controller-tools v0.1.9/go.mod h1:6g08p9m9G/So3sBc1AOQifHfhxH/mb6Sc4z0LMI8XMw= sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs= sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U= diff --git a/kubeflow/profiles/profiles.libsonnet b/kubeflow/profiles/profiles.libsonnet index b3fcae26f8a..2e4a1626672 100644 --- a/kubeflow/profiles/profiles.libsonnet +++ b/kubeflow/profiles/profiles.libsonnet @@ -19,7 +19,7 @@ singular: "profile", kind: "Profile", shortNames: [ - "prj", + "prf", ], }, validation: { @@ -37,137 +37,8 @@ spec: { type: "object", properties: { - selector: { - type: "object", - }, - template: { - type: "object", - properties: { - metadata: { - type: "object", - properties: { - namespace: { - type: "string", - }, - quota: { - type: "object", - properties: { - name: { - type: "string", - }, - requests: { - type: "object", - properties: { - cpu: { - type: "string", - }, - memory: { - type: "string", - }, - gpu: { - type: "string", - }, - }, - }, - limits: { - type: "object", - properties: { - cpu: { - type: "string", - }, - memory: { - type: "string", - }, - gpu: { - type: "string", - }, - }, - }, - }, - }, - }, - }, - spec: { - type: "object", - properties: { - owner: { - type: "object", - required: [ - "kind", - "name", - ], - properties: { - apiGroup: { - type: "string", - }, - kind: { - enum: [ - "ServiceAccount", - "User", - ], - }, - namespace: { - type: "string", - }, - name: { - type: "string", - }, - }, - }, - }, - }, - }, - }, - }, - }, - status: { - properties: { - observedGeneration: { - type: "integer", - format: "int64", - }, - }, - type: "object", - }, - }, - }, - }, - }, - }, - profilesCRD:: profilesCRD, - - local permissionsCRD = { - apiVersion: "apiextensions.k8s.io/v1beta1", - kind: "CustomResourceDefinition", - metadata: { - name: "permissions.kubeflow.org", - }, - spec: { - group: "kubeflow.org", - version: "v1alpha1", - scope: "Namespaced", - names: { - plural: "permissions", - singular: "permission", - kind: "Permission", - }, - validation: { - openAPIV3Schema: { - properties: { - apiVersion: { - type: "string", - }, - kind: { - type: "string", - }, - metadata: { - type: "object", - }, - spec: { - type: "object", - properties: { - selector: { - type: "object", + namespace: { + type: "string", }, owner: { type: "object", @@ -198,7 +69,8 @@ status: { properties: { observedGeneration: { - type: "int64", + type: "integer", + format: "int64", }, }, type: "object", @@ -208,7 +80,7 @@ }, }, }, - permissionsCRD:: permissionsCRD, + profilesCRD:: profilesCRD, local profilesService = { apiVersion: "v1", @@ -223,8 +95,7 @@ }, ports: [ { - port: 80, - targetPort: 8080, + port: 443, }, ], }, @@ -233,21 +104,32 @@ local profilesRole = { apiVersion: "rbac.authorization.k8s.io/v1", - kind: "Role", + kind: "ClusterRole", metadata: { - name: "view", - namespace: params.namespace, + name: "profiles", }, rules: [ { apiGroups: [ - "kubeflow.org", + "", ], resources: [ - "profiles", + "namespaces", ], verbs: [ - "create", + "*", + ], + }, + { + apiGroups: [ + "rbac", + ], + resources: [ + "roles", + "rolebindings", + ], + verbs: [ + "*", ], }, { @@ -258,26 +140,46 @@ "profiles", ], verbs: [ - "get", + "*", ], }, ], }, profilesRole:: profilesRole, - local profilesConfigMap = { + local serviceAccount = { apiVersion: "v1", - kind: "ConfigMap", + kind: "ServiceAccount", metadata: { + labels: { + app: "profiles", + }, name: "profiles", namespace: params.namespace, }, - data: { - "sync-profile.jsonnet": importstr "sync-profile.jsonnet", - "sync-permission.jsonnet": importstr "sync-permission.jsonnet", + }, + serviceAccount:: serviceAccount, + + local roleBinding = { + apiVersion: "rbac.authorization.k8s.io/v1", + kind: "ClusterRoleBinding", + metadata: { + name: "profiles", + }, + roleRef: { + apiGroup: "rbac.authorization.k8s.io", + kind: "ClusterRole", + name: "profiles", }, + subjects: [ + { + kind: "ServiceAccount", + name: "profiles", + namespace: params.namespace, + }, + ], }, - profilesConfigMap:: profilesConfigMap, + roleBinding:: roleBinding, local profilesDeployment = { apiVersion: "apps/v1", @@ -299,116 +201,31 @@ }, }, spec: { + serviceAccountName: "profiles", containers: [ { - name: "hooks", - //freeze latest + name: "manager", image: params.image, imagePullPolicy: "Always", - workingDir: "/opt/profiles/hooks", - volumeMounts: [ - { - name: "hooks", - mountPath: "/opt/profiles/hooks", - }, + command: [ + "/manager", ], }, ], - volumes: [ - { - name: "hooks", - configMap: { - name: "profiles", - }, - }, - ], }, }, }, }, profilesDeployment:: profilesDeployment, - local profilesController = { - apiVersion: "metacontroller.k8s.io/v1alpha1", - kind: "CompositeController", - metadata: { - name: "profiles-controller", - }, - spec: { - generateSelector: true, - parentResource: { - apiVersion: "kubeflow.org/v1alpha1", - resource: "profiles", - }, - childResources: [ - { - apiVersion: "v1", - resource: "namespaces", - }, - { - apiVersion: "v1", - resource: "resourcequotas", - }, - { - apiVersion: "kubeflow.org/v1alpha1", - resource: "permissions", - }, - ], - hooks: { - sync: { - webhook: { - url: "http://profiles." + params.namespace + "/sync-profile", - }, - }, - }, - }, - }, - profilesController:: profilesController, - - local permissionsController = { - apiVersion: "metacontroller.k8s.io/v1alpha1", - kind: "CompositeController", - metadata: { - name: "permissions-controller", - annotations: params, - }, - spec: { - generateSelector: true, - parentResource: { - apiVersion: "kubeflow.org/v1alpha1", - resource: "permissions", - }, - childResources: [ - { - apiVersion: "rbac.authorization.k8s.io/v1", - resource: "roles", - }, - { - apiVersion: "rbac.authorization.k8s.io/v1", - resource: "rolebindings", - }, - ], - hooks: { - sync: { - webhook: { - url: "http://profiles." + params.namespace + "/sync-permission", - }, - }, - }, - }, - }, - permissionsController:: permissionsController, - parts:: self, local all = [ self.profilesCRD, - self.permissionsCRD, self.profilesService, self.profilesRole, - self.profilesConfigMap, self.profilesDeployment, - self.profilesController, - self.permissionsController, + self.serviceAccount, + self.roleBinding, ], all:: all, diff --git a/kubeflow/profiles/prototypes/profiles.jsonnet b/kubeflow/profiles/prototypes/profiles.jsonnet index accf3989875..b9e20695f06 100644 --- a/kubeflow/profiles/prototypes/profiles.jsonnet +++ b/kubeflow/profiles/prototypes/profiles.jsonnet @@ -3,7 +3,7 @@ // @description profiles Component // @shortDescription profiles Component // @param name string Name -// @optionalParam image string metacontroller/jsonnetd@sha256:25c25f217ad030a0f67e37078c33194785b494569b0c088d8df4f00da8fd15a0 The image to use for jsonnet +// @optionalParam image string gcr.io/kubeflow-images-public/notebook-controller:v20190222-v0.4.0-rc.1-150-gc64db592-dirty-001d20 The image to use for controller local profile = import "kubeflow/profiles/profiles.libsonnet"; local instance = profile.new(env, params); From e6406d93e30c3f50b594c3607a54f323e6299595 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Fri, 22 Feb 2019 16:13:28 -0800 Subject: [PATCH 06/13] fix --- .../config/rbac/rbac_role.yaml | 28 +++++++++++++---- .../pkg/apis/kubeflow/v1alpha1/register.go | 2 +- .../controller/profile/profile_controller.go | 30 ++++++++++++------- kubeflow/profiles/profiles.libsonnet | 24 ++++++++++++++- kubeflow/profiles/prototypes/profiles.jsonnet | 2 +- 5 files changed, 67 insertions(+), 19 deletions(-) diff --git a/components/profile-controller/config/rbac/rbac_role.yaml b/components/profile-controller/config/rbac/rbac_role.yaml index 5e8f324507b..3c0adf28596 100644 --- a/components/profile-controller/config/rbac/rbac_role.yaml +++ b/components/profile-controller/config/rbac/rbac_role.yaml @@ -5,9 +5,9 @@ metadata: name: manager-role rules: - apiGroups: - - apps + - "" resources: - - deployments + - namespaces verbs: - get - list @@ -17,15 +17,31 @@ rules: - patch - delete - apiGroups: - - apps + - rbac resources: - - deployments/status + - roles verbs: - get + - list + - watch + - create - update - patch + - delete +- apiGroups: + - rbac + resources: + - rolebindings + verbs: + - get + - list + - watch + - create + - update + - patch + - delete - apiGroups: - - kubeflow.kubeflow.org + - kubeflow.org resources: - profiles verbs: @@ -37,7 +53,7 @@ rules: - patch - delete - apiGroups: - - kubeflow.kubeflow.org + - kubeflow.org resources: - profiles/status verbs: diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go index e41344681bd..03475bbee88 100644 --- a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go @@ -31,7 +31,7 @@ import ( var ( // SchemeGroupVersion is group version used to register these objects - SchemeGroupVersion = schema.GroupVersion{Group: "kubeflow.kubeflow.org", Version: "v1alpha1"} + SchemeGroupVersion = schema.GroupVersion{Group: "kubeflow.org", Version: "v1alpha1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} diff --git a/components/profile-controller/pkg/controller/profile/profile_controller.go b/components/profile-controller/pkg/controller/profile/profile_controller.go index 35413eb39cc..184090df42c 100644 --- a/components/profile-controller/pkg/controller/profile/profile_controller.go +++ b/components/profile-controller/pkg/controller/profile/profile_controller.go @@ -21,7 +21,6 @@ import ( "reflect" kubeflowv1alpha1 "github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow/v1alpha1" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -65,9 +64,21 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return err } - // TODO(user): Modify this to be the types you create - // Uncomment watch a Deployment created by Profile - change this for objects you create - err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ + err = c.Watch(&source.Kind{Type: &corev1.Namespace{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &kubeflowv1alpha1.Profile{}, + }) + if err != nil { + return err + } + err = c.Watch(&source.Kind{Type: &rbacv1.Role{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &kubeflowv1alpha1.Profile{}, + }) + if err != nil { + return err + } + err = c.Watch(&source.Kind{Type: &rbacv1.RoleBinding{}}, &handler.EnqueueRequestForOwner{ IsController: true, OwnerType: &kubeflowv1alpha1.Profile{}, }) @@ -88,13 +99,12 @@ type ReconcileProfile struct { // Reconcile reads that state of the cluster for a Profile object and makes changes based on the state read // and what is in the Profile.Spec -// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes -// a Deployment as an example // Automatically generate RBAC rules to allow the Controller to read and write Deployments -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=kubeflow.kubeflow.org,resources=profiles,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=kubeflow.kubeflow.org,resources=profiles/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=rbac,resources=roles,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=rbac,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=kubeflow.org,resources=profiles,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=kubeflow.org,resources=profiles/status,verbs=get;update;patch func (r *ReconcileProfile) Reconcile(request reconcile.Request) (reconcile.Result, error) { // Fetch the Profile instance instance := &kubeflowv1alpha1.Profile{} diff --git a/kubeflow/profiles/profiles.libsonnet b/kubeflow/profiles/profiles.libsonnet index 2e4a1626672..727665c9b27 100644 --- a/kubeflow/profiles/profiles.libsonnet +++ b/kubeflow/profiles/profiles.libsonnet @@ -122,7 +122,7 @@ }, { apiGroups: [ - "rbac", + "rbac.authorization.k8s.io", ], resources: [ "roles", @@ -218,6 +218,27 @@ }, profilesDeployment:: profilesDeployment, + local profileClusterRoleBinding = { + apiVersion: "rbac.authorization.k8s.io/v1", + kind: "ClusterRoleBinding", + metadata: { + name: "profile-controller-cluster-role-binding", + }, + roleRef: { + kind: "ClusterRole", + name: "cluster-admin", + apiGroup: "rbac.authorization.k8s.io", + }, + subjects: [ + { + kind: "ServiceAccount", + name: "profiles", + namespace: params.namespace, + }, + ], + }, + profileClusterRoleBinding:: profileClusterRoleBinding, + parts:: self, local all = [ self.profilesCRD, @@ -226,6 +247,7 @@ self.profilesDeployment, self.serviceAccount, self.roleBinding, + self.profileClusterRoleBinding, ], all:: all, diff --git a/kubeflow/profiles/prototypes/profiles.jsonnet b/kubeflow/profiles/prototypes/profiles.jsonnet index b9e20695f06..11538b59f1a 100644 --- a/kubeflow/profiles/prototypes/profiles.jsonnet +++ b/kubeflow/profiles/prototypes/profiles.jsonnet @@ -3,7 +3,7 @@ // @description profiles Component // @shortDescription profiles Component // @param name string Name -// @optionalParam image string gcr.io/kubeflow-images-public/notebook-controller:v20190222-v0.4.0-rc.1-150-gc64db592-dirty-001d20 The image to use for controller +// @optionalParam image string gcr.io/kubeflow-images-public/notebook-controller:v20190222-v0.4.0-rc.1-151-g3d6f6656-dirty-4eb6ff The image to use for controller local profile = import "kubeflow/profiles/profiles.libsonnet"; local instance = profile.new(env, params); From c99152ac26b0496cabbb4b80fec06f75ed40106c Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Fri, 22 Feb 2019 16:49:54 -0800 Subject: [PATCH 07/13] fix test --- kubeflow/profiles/profiles.libsonnet | 8 +- kubeflow/profiles/tests/profiles_test.jsonnet | 297 +++--------------- 2 files changed, 41 insertions(+), 264 deletions(-) diff --git a/kubeflow/profiles/profiles.libsonnet b/kubeflow/profiles/profiles.libsonnet index 727665c9b27..9dd95ccf18b 100644 --- a/kubeflow/profiles/profiles.libsonnet +++ b/kubeflow/profiles/profiles.libsonnet @@ -104,9 +104,10 @@ local profilesRole = { apiVersion: "rbac.authorization.k8s.io/v1", - kind: "ClusterRole", + kind: "Role", metadata: { name: "profiles", + namespace: params.namespace, }, rules: [ { @@ -162,13 +163,14 @@ local roleBinding = { apiVersion: "rbac.authorization.k8s.io/v1", - kind: "ClusterRoleBinding", + kind: "RoleBinding", metadata: { name: "profiles", + namespace: params.namespace, }, roleRef: { apiGroup: "rbac.authorization.k8s.io", - kind: "ClusterRole", + kind: "Role", name: "profiles", }, subjects: [ diff --git a/kubeflow/profiles/tests/profiles_test.jsonnet b/kubeflow/profiles/tests/profiles_test.jsonnet index 2e3a54abf2f..07e1e93a5f5 100644 --- a/kubeflow/profiles/tests/profiles_test.jsonnet +++ b/kubeflow/profiles/tests/profiles_test.jsonnet @@ -2,7 +2,7 @@ local profiles = import "kubeflow/profiles/profiles.libsonnet"; local params = { name: "profiles", - image: "metacontroller/jsonnetd@sha256:25c25f217ad030a0f67e37078c33194785b494569b0c088d8df4f00da8fd15a0", + image: "gcr.io/kubeflow-images-public/notebook-controller:latest", }; local env = { namespace: "kf-001", @@ -24,7 +24,7 @@ std.assertEqual( kind: "Profile", plural: "profiles", shortNames: [ - "prj", + "prf", ], singular: "profile", }, @@ -42,139 +42,17 @@ std.assertEqual( type: "object", }, spec: { - properties: { - selector: { - type: "object", - }, - template: { - properties: { - metadata: { - properties: { - namespace: { - type: "string", - }, - quota: { - type: "object", - properties: { - name: { - type: "string", - }, - requests: { - type: "object", - properties: { - cpu: { - type: "string", - }, - memory: { - type: "string", - }, - gpu: { - type: "string", - }, - }, - }, - limits: { - type: "object", - properties: { - cpu: { - type: "string", - }, - memory: { - type: "string", - }, - gpu: { - type: "string", - }, - }, - }, - }, - }, - }, - type: "object", - }, - spec: { - properties: { - owner: { - properties: { - apiGroup: { - type: "string", - }, - kind: { - enum: [ - "ServiceAccount", - "User", - ], - }, - name: { - type: "string", - }, - namespace: { - type: "string", - }, - }, - required: [ - "kind", - "name", - ], - type: "object", - }, - }, - type: "object", - }, - }, - type: "object", - }, - }, type: "object", - }, - status: { properties: { - observedGeneration: { - type: "integer", - format: "int64", + namespace: { + type: "string", }, - }, - type: "object", - }, - }, - }, - }, - version: "v1alpha1", - }, - } -) && - -std.assertEqual( - instance.parts.permissionsCRD, - { - apiVersion: "apiextensions.k8s.io/v1beta1", - kind: "CustomResourceDefinition", - metadata: { - name: "permissions.kubeflow.org", - }, - spec: { - group: "kubeflow.org", - names: { - kind: "Permission", - plural: "permissions", - singular: "permission", - }, - scope: "Namespaced", - validation: { - openAPIV3Schema: { - properties: { - apiVersion: { - type: "string", - }, - kind: { - type: "string", - }, - metadata: { - type: "object", - }, - spec: { - properties: { owner: { + type: "object", + required: [ + "kind", + "name", + ], properties: { apiGroup: { type: "string", @@ -185,29 +63,21 @@ std.assertEqual( "User", ], }, - name: { + namespace: { type: "string", }, - namespace: { + name: { type: "string", }, }, - required: [ - "kind", - "name", - ], - type: "object", - }, - selector: { - type: "object", }, }, - type: "object", }, status: { properties: { observedGeneration: { - type: "int64", + type: "integer", + format: "int64", }, }, type: "object", @@ -232,8 +102,7 @@ std.assertEqual( spec: { ports: [ { - port: 80, - targetPort: 8080, + port: 443, }, ], selector: { @@ -249,19 +118,31 @@ std.assertEqual( apiVersion: "rbac.authorization.k8s.io/v1", kind: "Role", metadata: { - name: "view", + name: "profiles", namespace: "kf-001", }, rules: [ { apiGroups: [ - "kubeflow.org", + "", ], resources: [ - "profiles", + "namespaces", ], verbs: [ - "create", + "*", + ], + }, + { + apiGroups: [ + "rbac.authorization.k8s.io", + ], + resources: [ + "roles", + "rolebindings", + ], + verbs: [ + "*", ], }, { @@ -272,29 +153,13 @@ std.assertEqual( "profiles", ], verbs: [ - "get", + "*", ], }, ], } ) && -std.assertEqual( - instance.parts.profilesConfigMap, - { - apiVersion: "v1", - data: { - "sync-permission.jsonnet": importstr "../sync-permission.jsonnet", - "sync-profile.jsonnet": importstr "../sync-profile.jsonnet", - }, - kind: "ConfigMap", - metadata: { - name: "profiles", - namespace: "kf-001", - }, - } -) && - std.assertEqual( instance.parts.profilesDeployment, { @@ -317,108 +182,18 @@ std.assertEqual( }, }, spec: { + serviceAccountName: "profiles", containers: [ { - image: "metacontroller/jsonnetd@sha256:25c25f217ad030a0f67e37078c33194785b494569b0c088d8df4f00da8fd15a0", + name: "manager", + image: params.image, imagePullPolicy: "Always", - name: "hooks", - volumeMounts: [ - { - mountPath: "/opt/profiles/hooks", - name: "hooks", - }, + command: [ + "/manager", ], - workingDir: "/opt/profiles/hooks", }, ], - volumes: [ - { - configMap: { - name: "profiles", - }, - name: "hooks", - }, - ], - }, - }, - }, - } -) && - -std.assertEqual( - instance.parts.profilesController, - { - apiVersion: "metacontroller.k8s.io/v1alpha1", - kind: "CompositeController", - metadata: { - name: "profiles-controller", - }, - spec: { - childResources: [ - { - apiVersion: "v1", - resource: "namespaces", - }, - { - apiVersion: "v1", - resource: "resourcequotas", - }, - { - apiVersion: "kubeflow.org/v1alpha1", - resource: "permissions", - }, - ], - generateSelector: true, - hooks: { - sync: { - webhook: { - url: "http://profiles.kf-001/sync-profile", - }, - }, - }, - parentResource: { - apiVersion: "kubeflow.org/v1alpha1", - resource: "profiles", - }, - }, - } -) && - -std.assertEqual( - instance.parts.permissionsController, - { - apiVersion: "metacontroller.k8s.io/v1alpha1", - kind: "CompositeController", - metadata: { - annotations: { - image: "metacontroller/jsonnetd@sha256:25c25f217ad030a0f67e37078c33194785b494569b0c088d8df4f00da8fd15a0", - name: "profiles", - namespace: "kf-001", - }, - name: "permissions-controller", - }, - spec: { - childResources: [ - { - apiVersion: "rbac.authorization.k8s.io/v1", - resource: "roles", - }, - { - apiVersion: "rbac.authorization.k8s.io/v1", - resource: "rolebindings", }, - ], - generateSelector: true, - hooks: { - sync: { - webhook: { - url: "http://profiles.kf-001/sync-permission", - }, - }, - }, - parentResource: { - apiVersion: "kubeflow.org/v1alpha1", - resource: "permissions", }, }, } From a1facd64742828b8a5512c50ea1f666499e80f17 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Wed, 27 Feb 2019 12:03:36 -0800 Subject: [PATCH 08/13] address review --- .../config/crds/kubeflow_v1alpha1_profile.yaml | 3 --- .../profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go | 2 +- .../pkg/apis/kubeflow/v1alpha1/profile_types.go | 3 --- .../pkg/controller/profile/profile_controller.go | 6 +++--- kubeflow/profiles/profiles.libsonnet | 2 +- kubeflow/profiles/prototypes/profiles.jsonnet | 2 +- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml b/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml index f86e060fa39..d25c09dfc4f 100644 --- a/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml +++ b/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml @@ -28,9 +28,6 @@ spec: type: object spec: properties: - namespace: - description: The namespace for this user - type: string owner: description: The profile owner type: object diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go index bea9fb8522c..54469207e15 100644 --- a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/doc.go @@ -19,5 +19,5 @@ limitations under the License. // +k8s:deepcopy-gen=package,register // +k8s:conversion-gen=github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow // +k8s:defaulter-gen=TypeMeta -// +groupName=kubeflow.kubeflow.org +// +groupName=kubeflow.org package v1alpha1 diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go index 10d9fbe229b..31dd24cc542 100644 --- a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go @@ -23,9 +23,6 @@ import ( // ProfileSpec defines the desired state of Profile type ProfileSpec struct { - // The namespace for this user - Namespace string `json:"namespace,omitempty"` - // The profile owner Owner rbacv1.Subject `json:"owner,omitempty"` } diff --git a/components/profile-controller/pkg/controller/profile/profile_controller.go b/components/profile-controller/pkg/controller/profile/profile_controller.go index 184090df42c..46aef130737 100644 --- a/components/profile-controller/pkg/controller/profile/profile_controller.go +++ b/components/profile-controller/pkg/controller/profile/profile_controller.go @@ -121,7 +121,7 @@ func (r *ReconcileProfile) Reconcile(request reconcile.Request) (reconcile.Resul ns := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - Name: instance.Spec.Namespace, + Name: instance.Name, }, } if err := controllerutil.SetControllerReference(instance, ns, r.scheme); err != nil { @@ -167,7 +167,7 @@ func (r *ReconcileProfile) Reconcile(request reconcile.Request) (reconcile.Resul roleBinding := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "default", - Namespace: instance.Spec.Namespace, + Namespace: instance.Name, }, RoleRef: rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", @@ -208,7 +208,7 @@ func generateRole(instance *kubeflowv1alpha1.Profile) *rbacv1.Role { role := &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ Name: "edit", - Namespace: instance.Spec.Namespace, + Namespace: instance.Name, }, Rules: []rbacv1.PolicyRule{ { diff --git a/kubeflow/profiles/profiles.libsonnet b/kubeflow/profiles/profiles.libsonnet index 9dd95ccf18b..ddaeca74196 100644 --- a/kubeflow/profiles/profiles.libsonnet +++ b/kubeflow/profiles/profiles.libsonnet @@ -13,7 +13,7 @@ spec: { group: "kubeflow.org", version: "v1alpha1", - scope: "Namespaced", + scope: "Cluster", names: { plural: "profiles", singular: "profile", diff --git a/kubeflow/profiles/prototypes/profiles.jsonnet b/kubeflow/profiles/prototypes/profiles.jsonnet index 11538b59f1a..c7c0a8faa7e 100644 --- a/kubeflow/profiles/prototypes/profiles.jsonnet +++ b/kubeflow/profiles/prototypes/profiles.jsonnet @@ -3,7 +3,7 @@ // @description profiles Component // @shortDescription profiles Component // @param name string Name -// @optionalParam image string gcr.io/kubeflow-images-public/notebook-controller:v20190222-v0.4.0-rc.1-151-g3d6f6656-dirty-4eb6ff The image to use for controller +// @optionalParam image string gcr.io/kubeflow-images-public/notebook-controller:v20190227-v0.4.0-rc.1-168-gc99152ac-dirty-9de0df The image to use for controller local profile = import "kubeflow/profiles/profiles.libsonnet"; local instance = profile.new(env, params); From 61fa4703248f865d4625b6ab82e55be3b38f77c8 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Wed, 27 Feb 2019 15:17:02 -0800 Subject: [PATCH 09/13] fix test --- kubeflow/profiles/tests/profiles_test.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubeflow/profiles/tests/profiles_test.jsonnet b/kubeflow/profiles/tests/profiles_test.jsonnet index 07e1e93a5f5..14e6482339c 100644 --- a/kubeflow/profiles/tests/profiles_test.jsonnet +++ b/kubeflow/profiles/tests/profiles_test.jsonnet @@ -28,7 +28,7 @@ std.assertEqual( ], singular: "profile", }, - scope: "Namespaced", + scope: "Cluster", validation: { openAPIV3Schema: { properties: { From 74928458ab62ab73152c30da8cf824eae51951e5 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Thu, 28 Feb 2019 10:31:50 -0800 Subject: [PATCH 10/13] make it cluster scope --- .../config/crds/kubeflow_v1alpha1_profile.yaml | 6 +++--- .../config/samples/kubeflow_v1alpha1_profile.yaml | 2 +- .../pkg/apis/kubeflow/v1alpha1/profile_types.go | 1 + .../pkg/apis/kubeflow/v1alpha1/register.go | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml b/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml index d25c09dfc4f..c2f224e9966 100644 --- a/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml +++ b/components/profile-controller/config/crds/kubeflow_v1alpha1_profile.yaml @@ -4,13 +4,13 @@ metadata: creationTimestamp: null labels: controller-tools.k8s.io: "1.0" - name: profiles.kubeflow.kubeflow.org + name: profiles.kubeflow.org spec: - group: kubeflow.kubeflow.org + group: kubeflow.org names: kind: Profile plural: profiles - scope: Namespaced + scope: Cluster validation: openAPIV3Schema: properties: diff --git a/components/profile-controller/config/samples/kubeflow_v1alpha1_profile.yaml b/components/profile-controller/config/samples/kubeflow_v1alpha1_profile.yaml index dd530be2d01..d585ccca2b7 100644 --- a/components/profile-controller/config/samples/kubeflow_v1alpha1_profile.yaml +++ b/components/profile-controller/config/samples/kubeflow_v1alpha1_profile.yaml @@ -1,4 +1,4 @@ -apiVersion: kubeflow.kubeflow.org/v1alpha1 +apiVersion: kubeflow.org/v1alpha1 kind: Profile metadata: labels: diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go index 31dd24cc542..7d4fd2de464 100644 --- a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/profile_types.go @@ -35,6 +35,7 @@ type ProfileStatus struct { // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:nonNamespaced // Profile is the Schema for the profiles API // +k8s:openapi-gen=true diff --git a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go index 03475bbee88..0d021a583f8 100644 --- a/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go +++ b/components/profile-controller/pkg/apis/kubeflow/v1alpha1/register.go @@ -21,7 +21,7 @@ limitations under the License. // +k8s:deepcopy-gen=package,register // +k8s:conversion-gen=github.com/kubeflow/kubeflow/components/profile-controller/pkg/apis/kubeflow // +k8s:defaulter-gen=TypeMeta -// +groupName=kubeflow.kubeflow.org +// +groupName=kubeflow.org package v1alpha1 import ( From d6bc2d768ef0609b93c402a86f6b7a61436310b4 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Thu, 28 Feb 2019 17:20:42 -0800 Subject: [PATCH 11/13] fix test --- kubeflow/profiles/tests/sample_profile.yaml | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/kubeflow/profiles/tests/sample_profile.yaml b/kubeflow/profiles/tests/sample_profile.yaml index 3387ea97fb6..d728145d5c6 100644 --- a/kubeflow/profiles/tests/sample_profile.yaml +++ b/kubeflow/profiles/tests/sample_profile.yaml @@ -4,20 +4,7 @@ metadata: name: john namespace: kubeflow spec: - template: - metadata: - namespace: john - quota: - name: compute-quota - requests: - cpu: "1" - memory: "1Gi" - gpu: "1" - limits: - cpu: "2" - memory: "2Gi" - spec: - owner: - kind: User - apiGroup: rbac.authorization.k8s.io - name: john@foo.com + owner: + kind: User + apiGroup: rbac.authorization.k8s.io + name: john@foo.com From 1a80265657e50a29e7e92b078b549c6d1a822541 Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Thu, 28 Feb 2019 17:23:56 -0800 Subject: [PATCH 12/13] fix test --- kubeflow/profiles/tests/sample_profile.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/kubeflow/profiles/tests/sample_profile.yaml b/kubeflow/profiles/tests/sample_profile.yaml index d728145d5c6..dbe1ed92905 100644 --- a/kubeflow/profiles/tests/sample_profile.yaml +++ b/kubeflow/profiles/tests/sample_profile.yaml @@ -2,7 +2,6 @@ apiVersion: kubeflow.org/v1alpha1 kind: Profile metadata: name: john - namespace: kubeflow spec: owner: kind: User From b929f2527b8374195abe490931c207f28c4f219d Mon Sep 17 00:00:00 2001 From: Lun-Kai Hsu Date: Thu, 28 Feb 2019 18:14:21 -0800 Subject: [PATCH 13/13] fix --- components/profile-controller/Makefile | 2 +- kubeflow/profiles/prototypes/profiles.jsonnet | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/profile-controller/Makefile b/components/profile-controller/Makefile index 3ed57d02218..af52dfb1cff 100644 --- a/components/profile-controller/Makefile +++ b/components/profile-controller/Makefile @@ -1,6 +1,6 @@ # Image URL to use all building/pushing image targets -IMG ?= gcr.io/kubeflow-images-public/notebook-controller +IMG ?= gcr.io/kubeflow-images-public/profile-controller TAG ?= $(eval TAG := $(shell date +v%Y%m%d)-$(shell git describe --tags --always --dirty)-$(shell git diff | shasum -a256 | cut -c -6))$(TAG) GOLANG_VERSION ?= 1.11.5 diff --git a/kubeflow/profiles/prototypes/profiles.jsonnet b/kubeflow/profiles/prototypes/profiles.jsonnet index c7c0a8faa7e..67c61666bd8 100644 --- a/kubeflow/profiles/prototypes/profiles.jsonnet +++ b/kubeflow/profiles/prototypes/profiles.jsonnet @@ -3,7 +3,7 @@ // @description profiles Component // @shortDescription profiles Component // @param name string Name -// @optionalParam image string gcr.io/kubeflow-images-public/notebook-controller:v20190227-v0.4.0-rc.1-168-gc99152ac-dirty-9de0df The image to use for controller +// @optionalParam image string gcr.io/kubeflow-images-public/profile-controller:v20190228-v0.4.0-rc.1-192-g1a802656-dirty-f95773 The image to use for controller local profile = import "kubeflow/profiles/profiles.libsonnet"; local instance = profile.new(env, params);