diff --git a/bootstrap/.gitignore b/bootstrap/.gitignore index 2fad63c4cc7..7473463274c 100644 --- a/bootstrap/.gitignore +++ b/bootstrap/.gitignore @@ -2,3 +2,4 @@ /.ksonnet/registries /app.override.yaml /reg_tmp/** +/test diff --git a/bootstrap/Makefile b/bootstrap/Makefile index 8a8d8c2aa29..7dac1e4f4ad 100755 --- a/bootstrap/Makefile +++ b/bootstrap/Makefile @@ -40,7 +40,9 @@ vet: generate: $(GO) generate ./pkg/... ./cmd/... ./config/... - + +deepcopy: + @deepcopy-gen -i github.com/kubeflow/kubeflow/bootstrap/pkg/apis/... -O zz_generated.deepcopy build-bootstrap: generate fmt vet $(GO) build -gcflags 'all=-N -l' -o bin/bootstrapper cmd/bootstrap/main.go @@ -86,28 +88,6 @@ run-local-docker: --mount type=bind,source=${HOME}/kf_app,target=/home/kubeflow \ --entrypoint /bin/bash $(IMG):$(TAG) -test-known-platforms-init: install build-dockerfordesktop-plugin - @rm -rf $(HOME)/dockerfordesktop && \ - GOOGLE_APPLICATION_CREDENTIALS=$(GOOGLE_APPLICATION_CREDENTIALS) PLUGINS_ENVIRONMENT=$(PLUGINS_ENVIRONMENT) kfctl init $(HOME)/dockerfordesktop -V --platform docker-for-desktop && \ - rm -rf $(HOME)/ksonnet && \ - GOOGLE_APPLICATION_CREDENTIALS=$(GOOGLE_APPLICATION_CREDENTIALS) kfctl init $(HOME)/ksonnet -V --platform ksonnet && \ - rm -rf $(HOME)/minikube && \ - GOOGLE_APPLICATION_CREDENTIALS=$(GOOGLE_APPLICATION_CREDENTIALS) kfctl init $(HOME)/minikube -V --platform minikube && \ - rm -rf $(HOME)/gcp && \ - GOOGLE_APPLICATION_CREDENTIALS=$(GOOGLE_APPLICATION_CREDENTIALS) kfctl init $(HOME)/gcp -V --platform gcp --project $(GCLOUD_PROJECT) && \ - echo SUCCESS - -test-known-platforms-generate: test-known-platforms-init - @cd ~/dockerfordesktop && \ - GOOGLE_APPLICATION_CREDENTIALS=$(GOOGLE_APPLICATION_CREDENTIALS) PLUGINS_ENVIRONMENT=$(PLUGINS_ENVIRONMENT) kfctl generate all -V && \ - cd ~/ksonnet && \ - GOOGLE_APPLICATION_CREDENTIALS=$(GOOGLE_APPLICATION_CREDENTIALS) kfctl generate all -V && \ - cd ~/minikube && \ - GOOGLE_APPLICATION_CREDENTIALS=$(GOOGLE_APPLICATION_CREDENTIALS) kfctl generate all -V --mount-local && \ - cd ~/gcp && \ - GOOGLE_APPLICATION_CREDENTIALS=$(GOOGLE_APPLICATION_CREDENTIALS) kfctl generate all -V --email jsmith@acme.com && \ - echo SUCCESS - # static and plugins toogle whether we try and load a platform as a .so. # There is an example plugin 'dockerfordesktop' that can be loaded as a .so. # By default we disable loading plugins and link dockerfordesktop into the kfctl binary (static) @@ -118,3 +98,37 @@ static: plugins: @ex pkg/apis/apps/group.go . The <[path/]name> argument can either be a full path -or a name where the kubeflow application will be initialized in $PWD/name if is not a path or in the parent -directory is name is a path. +or a . If just a directory will be created in the current directory. Usage: kfctl init <[path/]name> [flags] Flags: - --debug debug debug default is false -h, --help help for init -n, --namespace string namespace where kubeflow will be deployed (default "kubeflow") - -p, --platform string one of 'gcp|minikube|ksonnet' (default=ksonnet) + -p, --platform string one of 'gcp|minikube' (default "none") --project string name of the gcp project if --platform gcp -r, --repo string local github kubeflow repo -V, --verbose verbose output default is false - -v, --version string desired version Kubeflow or latest tag if not provided by user (default "v0.4.1") + -v, --version string desired version Kubeflow or latest tag if not provided by user (default "master") ``` ### **generate** @@ -138,7 +134,7 @@ Flags: (kubeflow/bootstrap/cmd/kfctl/cmd/generate.go) ``` -Generate a kubeflow application where resources is one of 'platform | k8s | all'. +Generate a kubeflow application where resources is one of 'platform|k8s|all'. platform: non kubernetes resources (eg --platform gcp) k8s: kubernetes resources @@ -150,11 +146,13 @@ Usage: kfctl generate [all(=default)|k8s|platform] [flags] Flags: - --email string email if '--platform gcp' - -h, --help help for generate - --ipName string ipName if '--platform gcp' - --mount-local mount-local if '--platform minikube || --platform docker-for-desktop' - -V, --verbose verbose output default is false + --email string email if '--platform gcp' + -h, --help help for generate + --hostname string hostname if '--platform gcp' + --ipName string ipName if '--platform gcp' + --mount-local mount-local if '--platform minikube' + -V, --verbose verbose output default is false + --zone string zone if '--platform gcp' (default "us-east1-d") ``` ### **apply** @@ -205,7 +203,7 @@ where the return type implements the [KfApp Interface](#kfapp-interface). In this sample, running ``` -kfctl init ~/dockerfordesktop --platform dockerfordesktop +kfctl init ~/dockerfordesktop --platform docker-for-desktop ``` will result in kfctl loading $PLUGINS_ENVIRONMENT/dockerfordesktop.so and calling its methods that @@ -219,13 +217,19 @@ make build-dockerfordesktop-plugin ## Testing -### Testing init for all platforms including the `dockerfordesktop` platform plugin +### Testing kfctl (tests plugin functionality, `kfctl init`, `kfctl generate`) + +``` +make test-kfctl +``` + +### Testing `kfctl init` for all platforms ``` make test-known-platforms-init ``` -### Testing generate for all platforms including the `dockerfordesktop` platform plugin +### Testing `kfctl generate` for all platforms ``` make test-known-platforms-generate @@ -289,19 +293,19 @@ type KsonnetSpec struct { } ``` -#### app.yaml example for --platform ksonnet +#### app.yaml example for --platform minikube ``` apiVersion: ksonnet.apps.kubeflow.org/v1alpha1 kind: Ksonnet metadata: creationTimestamp: null - name: ksonnet + name: minikube namespace: kubeflow spec: - appdir: /Users/kdkasrav/ksonnet - platform: ksonnet - repo: /Users/kdkasrav/ksonnet/.cache/master/kubeflow + appdir: /Users/kdkasrav/go/src/github.com/kubeflow/kubeflow/bootstrap/ksonnet + platform: minikube + repo: /Users/kdkasrav/go/src/github.com/kubeflow/kubeflow/bootstrap/ksonnet/.cache/master/kubeflow version: master status: {} ``` diff --git a/bootstrap/cmd/kfctl/cmd/apply.go b/bootstrap/cmd/kfctl/cmd/apply.go index 41670b641bf..23b0eaeae28 100644 --- a/bootstrap/cmd/kfctl/cmd/apply.go +++ b/bootstrap/cmd/kfctl/cmd/apply.go @@ -16,6 +16,7 @@ package cmd import ( kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" + "github.com/kubeflow/kubeflow/bootstrap/pkg/client/coordinator" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -45,7 +46,7 @@ var applyCmd = &cobra.Command{ string(kftypes.OAUTH_ID): applyCfg.GetString(string(kftypes.OAUTH_ID)), string(kftypes.OAUTH_SECRET): applyCfg.GetString(string(kftypes.OAUTH_SECRET)), } - kfApp, kfAppErr := loadKfApp(options) + kfApp, kfAppErr := coordinator.LoadKfApp(options) if kfAppErr != nil { log.Errorf("couldn't load KfApp: %v", kfAppErr) return diff --git a/bootstrap/cmd/kfctl/cmd/delete.go b/bootstrap/cmd/kfctl/cmd/delete.go index 69e789d5e5a..3b48fe82af6 100644 --- a/bootstrap/cmd/kfctl/cmd/delete.go +++ b/bootstrap/cmd/kfctl/cmd/delete.go @@ -16,6 +16,7 @@ package cmd import ( kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" + "github.com/kubeflow/kubeflow/bootstrap/pkg/client/coordinator" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -42,7 +43,7 @@ var deleteCmd = &cobra.Command{ return } options := map[string]interface{}{} - kfApp, kfAppErr := loadKfApp(options) + kfApp, kfAppErr := coordinator.LoadKfApp(options) if kfAppErr != nil { log.Errorf("couldn't load KfApp: %v", kfAppErr) return diff --git a/bootstrap/cmd/kfctl/cmd/generate.go b/bootstrap/cmd/kfctl/cmd/generate.go index 93de63d07d6..5264ad47aad 100644 --- a/bootstrap/cmd/kfctl/cmd/generate.go +++ b/bootstrap/cmd/kfctl/cmd/generate.go @@ -16,6 +16,7 @@ package cmd import ( kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" + "github.com/kubeflow/kubeflow/bootstrap/pkg/client/coordinator" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -36,7 +37,6 @@ var generateCmd = &cobra.Command{ The default is 'all' for any selected platform.`, Run: func(cmd *cobra.Command, args []string) { log.SetLevel(log.InfoLevel) - log.Info("generating kubeflow application") if generateCfg.GetBool(string(kftypes.VERBOSE)) == true { log.SetLevel(log.InfoLevel) } else { @@ -59,13 +59,7 @@ The default is 'all' for any selected platform.`, string(kftypes.ZONE): zone, string(kftypes.MOUNT_LOCAL): mountLocal, } - if ipName != "" { - options[string(kftypes.IPNAME)] = ipName - } - if hostName != "" { - options[string(kftypes.HOSTNAME)] = hostName - } - kfApp, kfAppErr := loadKfApp(options) + kfApp, kfAppErr := coordinator.LoadKfApp(options) if kfAppErr != nil { log.Errorf("couldn't load KfApp: %v", kfAppErr) return @@ -122,7 +116,7 @@ func init() { // platforms minikube, docker-for-desktop generateCmd.Flags().Bool(string(kftypes.MOUNT_LOCAL), false, - string(kftypes.MOUNT_LOCAL)+" if '--platform minikube || --platform docker-for-desktop'") + string(kftypes.MOUNT_LOCAL)+" if '--platform minikube'") bindErr = generateCfg.BindPFlag(string(kftypes.MOUNT_LOCAL), generateCmd.Flags().Lookup(string(kftypes.MOUNT_LOCAL))) if bindErr != nil { log.Errorf("couldn't set flag --%v: %v", string(kftypes.MOUNT_LOCAL), bindErr) diff --git a/bootstrap/cmd/kfctl/cmd/init.go b/bootstrap/cmd/kfctl/cmd/init.go index 65356b2bde2..f3eae03d4ed 100644 --- a/bootstrap/cmd/kfctl/cmd/init.go +++ b/bootstrap/cmd/kfctl/cmd/init.go @@ -15,11 +15,11 @@ package cmd import ( - "github.com/spf13/viper" - kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" + "github.com/kubeflow/kubeflow/bootstrap/pkg/client/coordinator" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/viper" ) var initCfg = viper.New() @@ -29,10 +29,9 @@ var initCmd = &cobra.Command{ Use: "init <[path/]name>", Short: "Create a kubeflow application under <[path/]name>", Long: `Create a kubeflow application under <[path/]name>. The <[path/]name> argument can either be a full path -or a name where the kubeflow application will be initialized in the current directory.`, +or a . If just a directory will be created in the current directory.`, Run: func(cmd *cobra.Command, args []string) { log.SetLevel(log.InfoLevel) - log.Info("initializing kubeflow application") if initCfg.GetBool(string(kftypes.VERBOSE)) == true { log.SetLevel(log.InfoLevel) } else { @@ -47,7 +46,6 @@ or a name where the kubeflow application will be initialized in the current dire namespace := initCfg.GetString(string(kftypes.NAMESPACE)) version := initCfg.GetString(string(kftypes.VERSION)) repo := initCfg.GetString(string(kftypes.REPO)) - debug := initCfg.GetBool(string(kftypes.DEBUG)) project := initCfg.GetString(string(kftypes.PROJECT)) init_gcp := initCfg.GetBool(string(kftypes.SKIP_INIT_GCP_PROJECT)) basic_auth := initCfg.GetBool(string(kftypes.USE_BASIC_AUTH)) @@ -57,17 +55,16 @@ or a name where the kubeflow application will be initialized in the current dire string(kftypes.VERSION): version, string(kftypes.APPNAME): appName, string(kftypes.REPO): repo, - string(kftypes.DEBUG): debug, string(kftypes.PROJECT): project, string(kftypes.SKIP_INIT_GCP_PROJECT): init_gcp, string(kftypes.USE_BASIC_AUTH): basic_auth, } - kfApp, kfAppErr := newKfApp(options) + kfApp, kfAppErr := coordinator.NewKfApp(options) if kfAppErr != nil || kfApp == nil { log.Errorf("couldn't create KfApp: %v", kfAppErr) return } - initErr := kfApp.Init(options) + initErr := kfApp.Init(kftypes.ALL, options) if initErr != nil { log.Errorf("KfApp initialization failed: %v", initErr) return @@ -82,7 +79,7 @@ func init() { initCfg.SetConfigType("yaml") initCmd.Flags().StringP(string(kftypes.PLATFORM), "p", kftypes.DefaultPlatform, - "one of 'gcp|minikube|ksonnet'") + "one of 'gcp|minikube'") bindErr := initCfg.BindPFlag(string(kftypes.PLATFORM), initCmd.Flags().Lookup(string(kftypes.PLATFORM))) if bindErr != nil { log.Errorf("couldn't set flag --%v: %v", string(kftypes.PLATFORM), bindErr) @@ -148,12 +145,4 @@ func init() { log.Errorf("couldn't set flag --%v: %v", string(kftypes.USE_BASIC_AUTH), bindErr) return } - - // debug output - initCmd.Flags().Bool(string(kftypes.DEBUG), false, string(kftypes.DEBUG)+" debug default is false") - bindErr = initCfg.BindPFlag(string(kftypes.DEBUG), initCmd.Flags().Lookup(string(kftypes.DEBUG))) - if bindErr != nil { - log.Errorf("couldn't set flag --%v: %v", string(kftypes.DEBUG), bindErr) - return - } } diff --git a/bootstrap/cmd/kfctl/cmd/root.go b/bootstrap/cmd/kfctl/cmd/root.go index e4beab47b94..a1d7329280c 100644 --- a/bootstrap/cmd/kfctl/cmd/root.go +++ b/bootstrap/cmd/kfctl/cmd/root.go @@ -16,50 +16,14 @@ package cmd import ( "fmt" - "github.com/ghodss/yaml" - "github.com/ksonnet/ksonnet/pkg/app" kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" - kstypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/ksonnet/v1alpha1" - "github.com/kubeflow/kubeflow/bootstrap/pkg/client/gcp" - // STATIC - "github.com/kubeflow/kubeflow/bootstrap/pkg/client/dockerfordesktop" - // -STATIC // - "github.com/kubeflow/kubeflow/bootstrap/pkg/client/ksonnet" - "github.com/kubeflow/kubeflow/bootstrap/pkg/client/minikube" - "github.com/mitchellh/go-homedir" - log "github.com/sirupsen/logrus" - "github.com/spf13/afero" "github.com/spf13/cobra" - "io/ioutil" "os" - "path" - "path/filepath" - "regexp" - "strings" ) -func GetPlatform(options map[string]interface{}) (kftypes.KfApp, error) { - platform := options[string(kftypes.PLATFORM)].(string) - switch platform { - case "ksonnet": - return ksonnet.GetKfApp(options), nil - case "minikube": - return minikube.GetKfApp(options), nil - case "gcp": - return gcp.GetKfApp(options), nil - // STATIC - case "docker-for-desktop": - return dockerfordesktop.GetKfApp(options), nil - // -STATIC // - default: - log.Infof("** loading %v.so for platform %v **", platform, platform) - return kftypes.LoadPlatform(options) - } -} - func processResourceArg(args []string) (kftypes.ResourceEnum, error) { if len(args) > 1 { - return kftypes.NONE, fmt.Errorf("unknown extra args %v", args[1:]) + return kftypes.ALL, fmt.Errorf("unknown extra args %v", args[1:]) } resources := kftypes.ALL if len(args) == 1 { @@ -70,94 +34,12 @@ func processResourceArg(args []string) (kftypes.ResourceEnum, error) { case kftypes.PLATFORM: resources = kftypes.PLATFORM default: - return kftypes.NONE, fmt.Errorf("unknown argument %v", args[0]) + return kftypes.ALL, fmt.Errorf("unknown argument %v", args[0]) } } return resources, nil } -func newKfApp(options map[string]interface{}) (kftypes.KfApp, error) { - //appName can be a path - appName := options[string(kftypes.APPNAME)].(string) - appDir := path.Dir(appName) - if appDir == "" || appDir == "." { - cwd, err := os.Getwd() - if err != nil { - return nil, fmt.Errorf("could not get current directory %v", err) - } - appDir = path.Join(cwd, appName) - } else { - if appDir == "~" { - home, homeErr := homedir.Dir() - if homeErr != nil { - return nil, fmt.Errorf("could not get home directory %v", homeErr) - } - expanded, expandedErr := homedir.Expand(home) - if expandedErr != nil { - return nil, fmt.Errorf("could not expand home directory %v", homeErr) - } - appName = path.Base(appName) - appDir = path.Join(expanded, appName) - } else { - appName = path.Base(appName) - appDir = path.Join(appDir, appName) - } - } - re := regexp.MustCompile(`[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`) - validName := re.FindString(appName) - if strings.Compare(validName, appName) != 0 { - return nil, fmt.Errorf(`invalid name %v must consist of lower case alphanumeric characters, '-' or '.', -and must start and end with an alphanumeric character`, appName) - } - options[string(kftypes.APPNAME)] = appName - options[string(kftypes.APPDIR)] = appDir - platform := options[string(kftypes.PLATFORM)].(string) - pApp, pAppErr := GetPlatform(options) - if pAppErr != nil { - return nil, fmt.Errorf("unable to load platform %v Error: %v", platform, pAppErr) - } - return pApp, nil -} - -func loadKfApp(options map[string]interface{}) (kftypes.KfApp, error) { - appDir, err := os.Getwd() - if err != nil { - return nil, fmt.Errorf("could not get current directory %v", err) - } - appName := filepath.Base(appDir) - log.Infof("AppName %v AppDir %v", appName, appDir) - cfgfile := filepath.Join(appDir, kftypes.KfConfigFile) - log.Infof("reading from %v", cfgfile) - fs := afero.NewOsFs() - ksDir := path.Join(appDir, kstypes.KsName) - kApp, kAppErr := app.Load(fs, nil, ksDir) - if kAppErr != nil { - return nil, fmt.Errorf("there was a problem loading app %v. Error: %v", appName, kAppErr) - } - buf, bufErr := ioutil.ReadFile(cfgfile) - if bufErr != nil { - return nil, fmt.Errorf("couldn't read %v. Error: %v", cfgfile, bufErr) - } - var v interface{} - yaml.Unmarshal(buf, &v) - data := v.(map[string]interface{}) - metadata := data["metadata"].(map[string]interface{}) - spec := data["spec"].(map[string]interface{}) - platform := spec["platform"].(string) - appName = metadata["name"].(string) - appDir = spec["appdir"].(string) - options[string(kftypes.PLATFORM)] = platform - options[string(kftypes.APPNAME)] = appName - options[string(kftypes.APPDIR)] = appDir - options[string(kftypes.KAPP)] = kApp - options[string(kftypes.DATA)] = buf - pApp, pAppErr := GetPlatform(options) - if pAppErr != nil { - return nil, fmt.Errorf("unable to load platform %v Error: %v", platform, pAppErr) - } - return pApp, nil -} - // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "kfctl", diff --git a/bootstrap/cmd/kfctl/config/app.yaml b/bootstrap/cmd/kfctl/config/app.yaml deleted file mode 100644 index 51bbf90cfac..00000000000 --- a/bootstrap/cmd/kfctl/config/app.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: ksonnet.apps.kubeflow.org/v1alpha1 -kind: Ksonnet -metadata: - creationTimestamp: null - name: ksonnet - namespace: kubeflow -spec: - platform: ksonnet - repo: /Users/kdkasrav/ksonnet/.cache/master/kubeflow - version: master -status: {} diff --git a/bootstrap/cmd/plugins/gcp/gcp.go b/bootstrap/cmd/plugins/gcp/gcp.go deleted file mode 100644 index 554c92535c5..00000000000 --- a/bootstrap/cmd/plugins/gcp/gcp.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" - "github.com/kubeflow/kubeflow/bootstrap/pkg/client/gcp" -) - -func GetKfApp(options map[string]interface{}) kftypes.KfApp { - return gcp.GetKfApp(options) -} diff --git a/bootstrap/config/kfctl_default.yaml b/bootstrap/config/kfctl_default.yaml new file mode 100644 index 00000000000..3feff46d0aa --- /dev/null +++ b/bootstrap/config/kfctl_default.yaml @@ -0,0 +1,52 @@ +# Config entry used for deploying with no platform specified (or --platform none) and no basic auth enabled +# Load this file as object (KsonnetSpec)[https://github.com/kubeflow/kubeflow/blob/master/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/application_types.go#L201] +# All TODO fields need to be changed following user's input before apply +# TODO change repo on the fly: set it to local tmp dir containing kubeflow registry +repo: /path/to/local/tmp/containing/kubeflow +packages: + - argo + - application + - common + - examples + - gcp + - jupyter + - katib + - metacontroller + - modeldb + - mpi-job + - pipeline + - pytorch-job + - seldon + - tensorboard + - tf-serving + - tf-training +components: + - ambassador + - application + - argo + - centraldashboard + - jupyter + - jupyter-web-app + - katib + - metacontroller + - notebook-controller + - pipeline + - pytorch-operator + - tensorboard + - tf-job-operator +componentParams: + application: + - name: components + value: + jupyter: + - name: platform + value: none + ambassador: + - name: ambassadorServiceType + value: NodePort + pipeline: + - name: mysqlPd + value: -storage-metadata-store + - name: minioPd + value: -storage-artifact-store +platform: none diff --git a/bootstrap/go.sum b/bootstrap/go.sum index b8808e32b59..c86592b444e 100644 --- a/bootstrap/go.sum +++ b/bootstrap/go.sum @@ -1,13 +1,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= contrib.go.opencensus.io/exporter/ocagent v0.4.2/go.mod h1:YuG83h+XWwqWjvCqn7vK4KSyLKhThY3+gNGQ37iS2V0= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/Azure/go-autorest v9.1.0+incompatible h1:SJrqXnGlxS9FWlSsu3H9Cxcrvco2L4Gmn9p6AVugIEk= github.com/Azure/go-autorest v9.1.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/GeertJohan/go.rice v0.0.0-20181229193832-0af3f3b09a0a h1:QgnJzkfb29JXtLXJN8alxzPWZhiNcAYZOa06dU5O46w= github.com/GeertJohan/go.rice v0.0.0-20181229193832-0af3f3b09a0a/go.mod h1:DgrzXonpdQbfN3uYaGz1EG4Sbhyum/MMIn6Cphlh2bw= github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA= github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= @@ -16,24 +13,18 @@ github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Masterminds/sprig v2.17.1+incompatible h1:PChbxFGKTWsg9IWh+pSZRCSj3zQkVpL6Hd9uWsFwxtc= github.com/Masterminds/sprig v2.17.1+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/aokoli/goutils v1.1.0 h1:jy4ghdcYvs5EIoGssZNslIASX5m+KNMfyyKvRQ0TEVE= github.com/aokoli/goutils v1.1.0/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.15.78 h1:LaXy6lWR0YK7LKyuU0QWy2ws/LWTPfYV/UgfiBu4tvY= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= -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/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.1.0-0.20181214143942-ba49f56771b8/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= @@ -45,13 +36,10 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb h1:tUf55Po0vzOendQ7NWytcdK0VuzQmfAgvGBUOQvN0WA= github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb/go.mod h1:U0vRfAucUOohvdCxt5MWLF+TePIL0xbCkbKIiV8TQCE= -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/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/distribution v2.7.0+incompatible h1:neUDAlf3wX6Ml4HdqTrbcOHXtfRN0TFIwt6YFL7N9RU= github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -63,83 +51,52 @@ github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/emicklei/go-restful v2.8.0+incompatible h1:wN8GCRDPGHguIynsnBartv5GUgGUg1LAU7+xnSn1j7Q= github.com/emicklei/go-restful v2.8.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6 h1:V94anc0ZG3Pa/cAMwP2m1aQW3+/FF8Qmw/GsFyTJAp4= github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6/go.mod h1:qr0VowGBT4CS4Q8vFF8BSeKz34PuqKGxs/L0IAQA9DQ= -github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc= github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 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/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb h1:D4uzjWwKYQ5XnAvUbuvHW93esHg7F8N/OYeBBcJoTr0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0 h1:8JV+dzJJiK46XqGLqqLav8ZfEiJECp8jlOFhpiCdZ+0= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/errors v0.17.0 h1:g5DzIh94VpuR/dd6Ff8KqyHNnw7yBa2xSHIPPzjRDUo= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonreference v0.17.0 h1:yJW3HCkTHg7NOA+gZ83IPHzUSnUzGXhGmsdiCcMexbA= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/loads v0.17.0 h1:H22nMs3GDQk4SwAaFQ+jLNw+0xoFeCueawhZlv8MBYs= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9 h1:zXd+rkzHwMIYVTJ/j/v8zUQ9j3Ir32gC5Dn9DzZVvCk= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0 h1:aIjeyG5mo5/FrvDkpKKEGZPmF9MPHahS72mzfVqeQXQ= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0 h1:FqqmmVCKn3di+ilU/+1m957T1CnMz3IteVUcV3aGXWA= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/validate v0.18.0 h1:PVXYcP1GkTl+XIAJnyJxOmK6CSG5Q1UcvoCvNO++5Kg= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff h1:kOkM9whyQYodu09SJ6W3NCsHG7crFaJILQ22Gozp3lg= github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/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/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -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 h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-jsonnet v0.12.1 h1:v0iUm/b4SBz7lR/diMoz9tLAz8lqtnNRKIwMrmU2HEU= github.com/google/go-jsonnet v0.12.1/go.mod h1:gVu3UVSfOt5fRFq+dh9duBqXa5905QY8S1QvMNcEIVs= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= 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/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww= github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gophercloud/gophercloud v0.0.0-20190116032514-258a61a0642d h1:JtBAKU6kOLVtX8VR8ejAgqaHsxCCqr2Ry7zsiUPFT5U= github.com/gophercloud/gophercloud v0.0.0-20190116032514-258a61a0642d/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= -github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM= github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= @@ -153,59 +110,40 @@ github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PF github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 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/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c h1:kQWxfPIHVLbgLzphqk3QUflDy9QdksZR4ygR807bpy0= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -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/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= 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/ksonnet/ksonnet v0.13.1 h1:SoMiL8+ZkWBwyqOOQIt/9nh1Yus5d8oe7sczQCMXsAg= github.com/ksonnet/ksonnet v0.13.1/go.mod h1:T8FwyGOX8fMoDyp845QmYDnk8R7AF35pImyfWJ9fj7M= -github.com/ksonnet/ksonnet-lib v0.1.12 h1:dudu+eYkbWD1s8BlI6ShvHHJDRbOeF9Z+LEQqdcjmVU= github.com/ksonnet/ksonnet-lib v0.1.12/go.mod h1:2p66Npe1xOUtQGlGzD5aJ3UHEBjG1b6o3nbC1rVNvz4= -github.com/kubernetes/client-go v6.0.0+incompatible h1:SwoXgvkzu9X4zhj1JekPxu2nUTzJsQ9lotEQZ+ClnFs= github.com/kubernetes/client-go v6.0.0+incompatible/go.mod h1:kszVi2i+FeqECZHhjpkV5h5zM0GnURfJv897YzgoAQ8= github.com/kubernetes/code-generator v0.0.0-20181206115026-3a2206dd6a78/go.mod h1:GXXF2gdS/LDGLo7HilXGuIQfo5nLQDhB4eUn/2UMPnk= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -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/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -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 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onrik/logrus v0.2.1 h1:xEYR+opLvr+hNixPPAimuQppFYHaZ0XLO9hZ2G8WPLI= github.com/onrik/logrus v0.2.1/go.mod h1:qfe9NeZVAJfIxviw3cYkZo3kvBtLoPRJriAO8zl7qTk= 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= @@ -217,44 +155,28 @@ github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -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.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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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.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 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/russross/blackfriday v1.5.2-0.20180428102519-11635eb403ff h1:bxenFOpdnKzbA1dhcJpgiwjSw7yqvWWY6huCpmsBfv0= github.com/russross/blackfriday v1.5.2-0.20180428102519-11635eb403ff/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.0 h1:O9FblXGxoTc51M+cqr74Bm2Tmt4PvkA5iu/j8HrkNuY= github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.1 h1:5+8j8FTpnFV4nEImW/ofkzEt8VoOiLXxdYIDsB73T38= github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 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= @@ -263,10 +185,8 @@ github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.18.1-0.20181204023538-aab39bd6a98b h1:6ayHMBPtdP3jNuk+Sfhso+PTB7ZJQ5E1FBo403m2H8w= go.opencensus.io v0.18.1-0.20181204023538-aab39bd6a98b/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 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= @@ -279,11 +199,9 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190110200230-915654e7eabc h1:Yx9JGxI1SBhVLFjpAkWMaO1TF+xyqtHLjZpvQboJGiM= golang.org/x/net v0.0.0-20190110200230-915654e7eabc/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-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c h1:pcBdqVcrlT+A3i+tWsOROFONQyey9tisIQHI4xqVGLg= golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 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= @@ -294,12 +212,10 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06 h1:0oC8rFnE+74kEmuHZ46F6KHsMr5Gx2gUQPuNz28iQZM= golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.1.0 h1:K6z2u68e86TPdSdefXdzvXgR1zEMa+459vBSfWYAZkI= 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.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -307,18 +223,15 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 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-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= -google.golang.org/genproto v0.0.0-20190111180523-db91494dd46c h1:LZllHYjdJnynBfmwysp+s4yhMzfc+3BzhdqzAMvwjoc= google.golang.org/genproto v0.0.0-20190111180523-db91494dd46c/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 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/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.11.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -327,29 +240,23 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 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= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20180308224125-73d903622b73 h1:5Z+PFfTIOXwKmOhQtZ0WBykbpGBBOuvbDx2YNAqIoYc= k8s.io/api v0.0.0-20180308224125-73d903622b73/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/apiextensions-apiserver v0.0.0-20180426153726-e8ab413e0ae1 h1:7i7e3Zai1/Zxgf3Ang0Yr89hyd9/Nlrfx63jyP3blpI= k8s.io/apiextensions-apiserver v0.0.0-20180426153726-e8ab413e0ae1/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= -k8s.io/apimachinery v0.0.0-20180228050457-302974c03f7e h1:CsgbEA8905OlpVLNKWD4GacPex50kFbqhotVNPew+dU= k8s.io/apimachinery v0.0.0-20180228050457-302974c03f7e/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apiserver v0.0.0-20180426121757-0841753fc26e h1:Kx5WFa3bGbM4WoxVI4q+yQ21RVnq+nG5DDF+GMGLNqY= k8s.io/apiserver v0.0.0-20180426121757-0841753fc26e/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w= k8s.io/code-generator v0.0.0-20180601180426-9de8e796a74d/go.mod h1:MYiN+ZJZ9HkETbgVZdWw2AsuAi9PZ4V80cwfuf2axe8= k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/helm v2.12.3+incompatible h1:wo1cdYjOnr5Z+LFuhtwIJaeQnec6D4gcg2H5UAKzY6w= k8s.io/helm v2.12.3+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= k8s.io/klog v0.1.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/kube-openapi v0.0.0-20190115222348-ced9eb3070a5 h1:leiGEauB5/1TE6nQQ9flpPDz6oEEvPLVuj4B4J40dfA= k8s.io/kube-openapi v0.0.0-20190115222348-ced9eb3070a5/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kubernetes v1.10.2+incompatible h1:7HdUQB9WQUY4vNed/xJ7E14rpstEE6xIco9PrLbaMG4= k8s.io/kubernetes v1.10.2+incompatible/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20181221173059-8a16e7dd8fb6 h1:+jRzzMyx+I9J18BvwHYmZ5hpPwoZfh6g39WfNlsMCkY= k8s.io/utils v0.0.0-20181221173059-8a16e7dd8fb6/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= -sigs.k8s.io/controller-runtime v0.1.1 h1:CTtDLl99X1mAWrnasPxEEIdEsAMu9CeTDawAZtvVFCU= sigs.k8s.io/controller-runtime v0.1.1/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8= 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/bootstrap/pkg/apis/addtoscheme_apps_v1alpha1.go b/bootstrap/pkg/apis/addtoscheme_apps_v1alpha1.go index 2322c209538..c46fb4b906a 100644 --- a/bootstrap/pkg/apis/addtoscheme_apps_v1alpha1.go +++ b/bootstrap/pkg/apis/addtoscheme_apps_v1alpha1.go @@ -15,12 +15,15 @@ package apis import ( - gcptypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/ksonnet/v1alpha1" - ksonnettypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/ksonnet/v1alpha1" + client "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/client/v1alpha1" + gcp "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/gcp/v1alpha1" + ksonnet "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/ksonnet/v1alpha1" ) func init() { // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back - AddToSchemes = append(AddToSchemes, ksonnettypes.SchemeBuilder.AddToScheme) - AddToSchemes = append(AddToSchemes, gcptypes.SchemeBuilder.AddToScheme) + AddToSchemes = append(AddToSchemes, ksonnet.SchemeBuilder.AddToScheme) + AddToSchemes = append(AddToSchemes, gcp.SchemeBuilder.AddToScheme) + AddToSchemes = append(AddToSchemes, client.SchemeBuilder.AddToScheme) + } diff --git a/bootstrap/pkg/apis/apps/client/client.go b/bootstrap/pkg/apis/apps/client/client.go new file mode 100644 index 00000000000..3682aa54c71 --- /dev/null +++ b/bootstrap/pkg/apis/apps/client/client.go @@ -0,0 +1,16 @@ +// Copyright 2018 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 client contains client related types +package client diff --git a/bootstrap/pkg/apis/apps/client/v1alpha1/application_types.go b/bootstrap/pkg/apis/apps/client/v1alpha1/application_types.go new file mode 100644 index 00000000000..a97dad795ca --- /dev/null +++ b/bootstrap/pkg/apis/apps/client/v1alpha1/application_types.go @@ -0,0 +1,79 @@ +// Copyright 2018 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 ( + "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ClientSpec holds common attributes used by each platform +type ClientSpec struct { + AppDir string `json:"appdir,omitempty"` + Platform string `json:"platform,omitempty"` + Version string `json:"version,omitempty"` + Repo string `json:"repo,omitempty"` + Components []string `json:"components,omitempty"` + Packages []string `json:"packages,omitempty"` + Parameters map[string][]apps.NameValue `json:"parameters,omitempty"` +} + +// ClientStatus defines the observed state of Client +type ClientStatus struct { + Conditions []ClientCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"` +} + +type ClientConditionType string + +type ClientCondition struct { + // Type of deployment condition. + Type ClientConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=ClientConditionType"` + // Status of the condition, one of True, False, Unknown. + Status v1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"` + // The last time this condition was updated. + LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,6,opt,name=lastUpdateTime"` + // Last time the condition transitioned from one status to another. + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,7,opt,name=lastTransitionTime"` + // The reason for the condition's last transition. + Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"` + // A human readable message indicating details about the transition. + Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Client is the Schema for the applications API +// +k8s:openapi-gen=true +type Client struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ClientSpec `json:"spec,omitempty"` + Status ClientStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ClientList contains a list of Client +type ClientList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Client `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Client{}, &ClientList{}) +} diff --git a/bootstrap/pkg/apis/apps/client/v1alpha1/application_types_test.go b/bootstrap/pkg/apis/apps/client/v1alpha1/application_types_test.go new file mode 100644 index 00000000000..19d71a6c655 --- /dev/null +++ b/bootstrap/pkg/apis/apps/client/v1alpha1/application_types_test.go @@ -0,0 +1,56 @@ +// Copyright 2018 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 TestStorageApplication(t *testing.T) { + key := types.NamespacedName{ + Name: "foo", + Namespace: "default", + } + created := &Client{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }} + g := gomega.NewGomegaWithT(t) + + // Test Create + fetched := &Client{} + 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/bootstrap/pkg/apis/apps/client/v1alpha1/doc.go b/bootstrap/pkg/apis/apps/client/v1alpha1/doc.go new file mode 100644 index 00000000000..5018d9e3e82 --- /dev/null +++ b/bootstrap/pkg/apis/apps/client/v1alpha1/doc.go @@ -0,0 +1,22 @@ +// Copyright 2018 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 client v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/client +// +k8s:defaulter-gen=TypeMeta +// +groupName=client.apps.kubeflow.org + +package v1alpha1 diff --git a/bootstrap/pkg/apis/apps/client/v1alpha1/register.go b/bootstrap/pkg/apis/apps/client/v1alpha1/register.go new file mode 100644 index 00000000000..bd90086ed09 --- /dev/null +++ b/bootstrap/pkg/apis/apps/client/v1alpha1/register.go @@ -0,0 +1,44 @@ +// Copyright 2018 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 client v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/client +// +k8s:defaulter-gen=TypeMeta +// +groupName=client.apps.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: "client.apps.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/bootstrap/pkg/apis/apps/client/v1alpha1/v1alpha1_suite_test.go b/bootstrap/pkg/apis/apps/client/v1alpha1/v1alpha1_suite_test.go new file mode 100644 index 00000000000..598858167ee --- /dev/null +++ b/bootstrap/pkg/apis/apps/client/v1alpha1/v1alpha1_suite_test.go @@ -0,0 +1,53 @@ +// Copyright 2018 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/bootstrap/pkg/apis/apps/client/v1alpha1/zz_generated.deepcopy.go b/bootstrap/pkg/apis/apps/client/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..8d7dd6c22a3 --- /dev/null +++ b/bootstrap/pkg/apis/apps/client/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,169 @@ +// +build !ignore_autogenerated + +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apps "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" + 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 *Client) DeepCopyInto(out *Client) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Client. +func (in *Client) DeepCopy() *Client { + if in == nil { + return nil + } + out := new(Client) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Client) 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 *ClientCondition) DeepCopyInto(out *ClientCondition) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientCondition. +func (in *ClientCondition) DeepCopy() *ClientCondition { + if in == nil { + return nil + } + out := new(ClientCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClientList) DeepCopyInto(out *ClientList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Client, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientList. +func (in *ClientList) DeepCopy() *ClientList { + if in == nil { + return nil + } + out := new(ClientList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClientList) 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 *ClientSpec) DeepCopyInto(out *ClientSpec) { + *out = *in + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + *out = make(map[string][]apps.NameValue, len(*in)) + for key, val := range *in { + var outVal []apps.NameValue + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]apps.NameValue, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientSpec. +func (in *ClientSpec) DeepCopy() *ClientSpec { + if in == nil { + return nil + } + out := new(ClientSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClientStatus) DeepCopyInto(out *ClientStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ClientCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientStatus. +func (in *ClientStatus) DeepCopy() *ClientStatus { + if in == nil { + return nil + } + out := new(ClientStatus) + in.DeepCopyInto(out) + return out +} diff --git a/bootstrap/pkg/apis/apps/gcp/app.go b/bootstrap/pkg/apis/apps/gcp/gcp.go similarity index 100% rename from bootstrap/pkg/apis/apps/gcp/app.go rename to bootstrap/pkg/apis/apps/gcp/gcp.go diff --git a/bootstrap/pkg/apis/apps/gcp/v1alpha1/application_types.go b/bootstrap/pkg/apis/apps/gcp/v1alpha1/application_types.go index 222fb10e53d..635f8e9cae5 100644 --- a/bootstrap/pkg/apis/apps/gcp/v1alpha1/application_types.go +++ b/bootstrap/pkg/apis/apps/gcp/v1alpha1/application_types.go @@ -15,21 +15,21 @@ package v1alpha1 import ( - kstypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/ksonnet/v1alpha1" + client "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/client/v1alpha1" "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // GcpSpec defines the desired state of Gcp type GcpSpec struct { - kstypes.KsonnetSpec `json:",inline"` - Project string `json:"project,omitempty"` - Email string `json:"email,omitempty"` - IpName string `json:"ipName,omitempty"` - Hostname string `json:"hostname,omitempty"` - Zone string `json:"zone,omitempty"` - UseBasicAuth bool `json:"useBasicAuth"` - SkipInitProject bool `json:"skipInitProject,omitempty"` + client.ClientSpec `json:",inline"` + Project string `json:"project,omitempty"` + Email string `json:"email,omitempty"` + IpName string `json:"ipName,omitempty"` + Hostname string `json:"hostname,omitempty"` + Zone string `json:"zone,omitempty"` + UseBasicAuth bool `json:"useBasicAuth"` + SkipInitProject bool `json:"skipInitProject,omitempty"` } // GcpStatus defines the observed state of Gcp diff --git a/bootstrap/pkg/apis/apps/gcp/v1alpha1/zz_generated.deepcopy.go b/bootstrap/pkg/apis/apps/gcp/v1alpha1/zz_generated.deepcopy.go index b3db6844377..8dca8cb508c 100644 --- a/bootstrap/pkg/apis/apps/gcp/v1alpha1/zz_generated.deepcopy.go +++ b/bootstrap/pkg/apis/apps/gcp/v1alpha1/zz_generated.deepcopy.go @@ -1,18 +1,20 @@ // +build !ignore_autogenerated -// Copyright 2018 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. +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ // Code generated by deepcopy-gen. DO NOT EDIT. @@ -104,7 +106,7 @@ func (in *GcpList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GcpSpec) DeepCopyInto(out *GcpSpec) { *out = *in - in.KsonnetSpec.DeepCopyInto(&out.KsonnetSpec) + in.ClientSpec.DeepCopyInto(&out.ClientSpec) return } diff --git a/bootstrap/pkg/apis/apps/group.go b/bootstrap/pkg/apis/apps/group.go index 75948296e90..2b98695d428 100644 --- a/bootstrap/pkg/apis/apps/group.go +++ b/bootstrap/pkg/apis/apps/group.go @@ -27,10 +27,14 @@ import ( "google.golang.org/api/option" containerpb "google.golang.org/genproto/googleapis/container/v1" "io" + ext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + "math/rand" "os" "path/filepath" /* PLUGINS @@ -42,18 +46,19 @@ import ( const ( DefaultNamespace = "kubeflow" - DefaultPlatform = "ksonnet" + DefaultPlatform = "none" // TODO: find the latest tag dynamically - DefaultVersion = "master" - DefaultGitRepo = "https://github.com/kubeflow/kubeflow/tarball" - KfConfigFile = "app.yaml" - DefaultCacheDir = ".cache" - GcpConfigDir = "bootstrap/config" - GcpIapConfig = "kfctl_iap.yaml" - GcpBasicAuth = "kfctl_basic_auth.yaml" - DefaultZone = "us-east1-d" - DefaultConfig = "default_config" - DefaultGkeApiVer = "v1beta1" + DefaultVersion = "master" + DefaultGitRepo = "https://github.com/kubeflow/kubeflow/tarball" + KfConfigFile = "app.yaml" + DefaultCacheDir = ".cache" + DefaultConfigDir = "bootstrap/config" + DefaultConfigFile = "kfctl_default.yaml" + GcpIapConfig = "kfctl_iap.yaml" + GcpBasicAuth = "kfctl_basic_auth.yaml" + DefaultZone = "us-east1-d" + DefaultGkeApiVer = "v1beta1" + DefaultAppLabel = "app.kubernetes.io/name" ) type ResourceEnum string @@ -62,7 +67,6 @@ const ( ALL ResourceEnum = "all" K8S ResourceEnum = "k8s" PLATFORM ResourceEnum = "platform" - NONE ResourceEnum = "none" ) type CliOption string @@ -72,7 +76,6 @@ const ( IPNAME CliOption = "ipName" HOSTNAME CliOption = "hostname" MOUNT_LOCAL CliOption = "mount-local" - DEBUG CliOption = "debug" SKIP_INIT_GCP_PROJECT CliOption = "skip-init-gcp-project" VERBOSE CliOption = "verbose" NAMESPACE CliOption = "namespace" @@ -81,39 +84,118 @@ const ( PROJECT CliOption = "project" APPNAME CliOption = "appname" APPDIR CliOption = "appDir" - KAPP CliOption = "KApp" DATA CliOption = "Data" ZONE CliOption = "zone" USE_BASIC_AUTH CliOption = "use_basic_auth" OAUTH_ID CliOption = "oauth_id" OAUTH_SECRET CliOption = "oauth_secret" + DEFAULT_CONFIG CliOption = "default_config" ) +var DefaultPackages = []string{ + "application", + "argo", + "common", + "examples", + "jupyter", + "katib", + "metacontroller", + "modeldb", + "mpi-job", + "openvino", + "pipeline", + "profiles", + "pytorch-job", + "seldon", + "tensorboard", + "tf-serving", + "tf-training", +} +var DefaultComponents = []string{ + "ambassador", + "application", + "argo", + "centraldashboard", + "jupyter", + "jupyter-web-app", + "katib", + "metacontroller", + "notebooks", + "notebook-controller", + "openvino", + "pipeline", + "profiles", + "pytorch-operator", + "spartakus", + "tensorboard", + "tf-job-operator", +} + +var DefaultParameters = map[string][]NameValue{ + "spartakus": { + NameValue{ + Name: "usageId", + Value: fmt.Sprintf("%08d", 10000000+rand.Intn(90000000)), + }, + NameValue{ + Name: "reportUsage", + Value: "true", + }, + }, +} + +type NameValue struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` +} + // // KfApp provides a common -// API for platforms like ksonnet, gcp, minikube, docker-for-desktop, etc. +// API for platforms like gcp or minikube // They all implementation the API below // type KfApp interface { Apply(resources ResourceEnum, options map[string]interface{}) error Delete(resources ResourceEnum, options map[string]interface{}) error Generate(resources ResourceEnum, options map[string]interface{}) error - Init(options map[string]interface{}) error + Init(resources ResourceEnum, options map[string]interface{}) error } -type Platform string +func QuoteItems(items []string) []string { + var withQuotes []string + for _, item := range items { + withQuote := "\"" + item + "\"" + withQuotes = append(withQuotes, withQuote) + } + return withQuotes +} -const ( - DOCKER_FOR_DESKTOP Platform = "docker-for-desktop" - GCP Platform = "gcp" - KSONNET Platform = "ksonnet" - MINIKUBE Platform = "minikube" -) +func RemoveItem(defaults []string, name string) []string { + var pkgs []string + for _, pkg := range defaults { + if pkg != name { + pkgs = append(pkgs, pkg) + } + } + return pkgs +} -type FullKfApp struct { - Children map[Platform]KfApp +func RemoveItems(defaults []string, names ...string) []string { + pkgs := make([]string, len(defaults)) + copy(pkgs, defaults) + for _, name := range names { + pkgs = RemoveItem(pkgs, name) + } + return pkgs } +const ( + DOCKER_FOR_DESKTOP = "docker-for-desktop" + GCP = "gcp" + NONE = DefaultPlatform + MINIKUBE = "minikube" +) + func LoadPlatform(options map[string]interface{}) (KfApp, error) { /* PLUGINS platform := options[string(PLATFORM)].(string) @@ -262,19 +344,26 @@ func GetClientOutOfCluster() (kubernetes.Interface, error) { return clientset, nil } -func GetClientOutOfClusterWithConfig(config *rest.Config) (kubernetes.Interface, error) { - clientset, err := kubernetes.NewForConfig(config) +// Gets a client which can query for CRDs +func GetApiExtensionsClientOutOfCluster() (apiextensionsv1beta1.ApiextensionsV1beta1Interface, error) { + config, err := BuildOutOfClusterConfig() + if err != nil { + log.Fatalf("Can not get kubernetes config: %v", err) + } + v := ext.SchemeGroupVersion + config.GroupVersion = &v + crdClient, err := clientset.NewForConfig(config) if err != nil { - return nil, fmt.Errorf("Can not get kubernetes client: %v", err) + log.Fatalf("Can not get dynamic client: %v", err) } - return clientset, nil + return crdClient.ApiextensionsV1beta1(), nil } -// capture replaces os.Stdout with a writer that buffers any data written +// Capture replaces os.Stdout with a writer that buffers any data written // to os.Stdout. Call the returned function to cleanup and get the data // as a string. -func capture() func() (string, error) { +func Capture() func() (string, error) { r, w, err := os.Pipe() if err != nil { panic(err) diff --git a/bootstrap/pkg/apis/apps/ksonnet/app.go b/bootstrap/pkg/apis/apps/ksonnet/ksonnet.go similarity index 100% rename from bootstrap/pkg/apis/apps/ksonnet/app.go rename to bootstrap/pkg/apis/apps/ksonnet/ksonnet.go diff --git a/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/application_types.go b/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/application_types.go index cb7cdab11de..5ac2022e1f9 100644 --- a/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/application_types.go +++ b/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/application_types.go @@ -15,10 +15,9 @@ package v1alpha1 import ( - "fmt" + client "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/client/v1alpha1" "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "math/rand" ) const ( @@ -26,92 +25,12 @@ const ( KsEnvName = "default" ) -func QuoteItems(items []string) []string { - withQuotes := []string{} - for _, item := range items { - withQuote := "\"" + item + "\"" - withQuotes = append(withQuotes, withQuote) - } - return withQuotes -} - -func RemoveItem(defaults []string, name string) []string { - pkgs := []string{} - for _, pkg := range defaults { - if pkg != name { - pkgs = append(pkgs, pkg) - } - } - return pkgs -} - -func RemoveItems(defaults []string, names ...string) []string { - pkgs := make([]string, len(defaults)) - copy(pkgs, defaults) - for _, name := range names { - pkgs = RemoveItem(pkgs, name) - } - return pkgs -} - var DefaultRegistry = &RegistryConfig{ Name: "kubeflow", Repo: "https://github.com/kubeflow/kubeflow.git", Path: "kubeflow", } -var DefaultPackages = []string{ - "application", - "argo", - "common", - "examples", - "jupyter", - "katib", - "metacontroller", - "modeldb", - "mpi-job", - "openvino", - "pipeline", - "profiles", - "pytorch-job", - "seldon", - "tensorboard", - "tf-serving", - "tf-training", -} -var DefaultComponents = []string{ - "ambassador", - "application", - "argo", - "centraldashboard", - "jupyter", - "jupyter-web-app", - "katib", - "metacontroller", - "notebooks", - "notebook-controller", - "openvino", - "pipeline", - "profiles", - "pytorch-operator", - "spartakus", - "tensorboard", - "tf-job-operator", -} - -var DefaultParameters = map[string][]NameValue{ - "spartakus": { - NameValue{ - Name: "usageId", - Value: fmt.Sprintf("%08d", 10000000+rand.Intn(90000000)), - }, - NameValue{ - Name: "reportUsage", - Value: "true", - }, - }, -} - // RegistryConfig is used for two purposes: // 1. used during image build, to configure registries that should be baked into the bootstrapper docker image. // (See: https://github.com/kubeflow/kubeflow/blob/master/bootstrap/image_registries.yaml) @@ -188,28 +107,17 @@ type RegistriesConfigFile struct { } type AppConfig struct { - Registries []*RegistryConfig `json:"registries,omitempty"` - Packages []KsPackage `json:"packages,omitempty"` - Components []KsComponent `json:"components,omitempty"` - Parameters []KsParameter `json:"parameters,omitempty"` + Registries []*RegistryConfig `json:"registries,omitempty"` + Packages []KsPackage `json:"packages,omitempty"` + Components []KsComponent `json:"components,omitempty"` + Parameters []KsParameter `json:"parameters,omitempty"` // Parameters to apply when creating the ksonnet components - ApplyParameters []KsParameter `json:"applyParameters,omitempty"` -} - -type NameValue struct { - Name string `json:"name,omitempty"` - Value string `json:"value,omitempty"` + ApplyParameters []KsParameter `json:"applyParameters,omitempty"` } // KsonnetSpec defines the desired state of Ksonnet type KsonnetSpec struct { - AppDir string `json:"appdir,omitempty"` - Platform string `json:"platform,omitempty"` - Version string `json:"version,omitempty"` - Repo string `json:"repo,omitempty"` - Components []string `json:"components,omitempty"` - Packages []string `json:"packages,omitempty"` - Parameters map[string][]NameValue `json:"parameters,omitempty"` + client.ClientSpec `json:",inline"` } // KsonnetStatus defines the observed state of Ksonnet @@ -248,13 +156,13 @@ type Ksonnet struct { // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// KsAppList contains a list of Ksonnet -type KsAppList struct { +// KsonnetList contains a list of Ksonnet +type KsonnetList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []Ksonnet `json:"items"` + Items []Ksonnet `json:"items"` } func init() { - SchemeBuilder.Register(&Ksonnet{}, &KsAppList{}) + SchemeBuilder.Register(&Ksonnet{}, &KsonnetList{}) } diff --git a/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/zz_generated.deepcopy.go b/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/zz_generated.deepcopy.go index 6e5a479f421..bf81e65e095 100644 --- a/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/zz_generated.deepcopy.go +++ b/bootstrap/pkg/apis/apps/ksonnet/v1alpha1/zz_generated.deepcopy.go @@ -1,18 +1,20 @@ // +build !ignore_autogenerated -// Copyright 2018 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. +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ // Code generated by deepcopy-gen. DO NOT EDIT. @@ -64,39 +66,6 @@ func (in *AppConfig) DeepCopy() *AppConfig { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KsAppList) DeepCopyInto(out *KsAppList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Ksonnet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KsAppList. -func (in *KsAppList) DeepCopy() *KsAppList { - if in == nil { - return nil - } - out := new(KsAppList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *KsAppList) 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 *KsComponent) DeepCopyInto(out *KsComponent) { *out = *in @@ -269,33 +238,42 @@ func (in *KsonnetCondition) DeepCopy() *KsonnetCondition { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KsonnetSpec) DeepCopyInto(out *KsonnetSpec) { +func (in *KsonnetList) DeepCopyInto(out *KsonnetList) { *out = *in - if in.Components != nil { - in, out := &in.Components, &out.Components - *out = make([]string, len(*in)) - copy(*out, *in) + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Ksonnet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } - if in.Packages != nil { - in, out := &in.Packages, &out.Packages - *out = make([]string, len(*in)) - copy(*out, *in) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KsonnetList. +func (in *KsonnetList) DeepCopy() *KsonnetList { + if in == nil { + return nil } - if in.Parameters != nil { - in, out := &in.Parameters, &out.Parameters - *out = make(map[string][]NameValue, len(*in)) - for key, val := range *in { - var outVal []NameValue - if val == nil { - (*out)[key] = nil - } else { - in, out := &val, &outVal - *out = make([]NameValue, len(*in)) - copy(*out, *in) - } - (*out)[key] = outVal - } + out := new(KsonnetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KsonnetList) 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 *KsonnetSpec) DeepCopyInto(out *KsonnetSpec) { + *out = *in + in.ClientSpec.DeepCopyInto(&out.ClientSpec) return } @@ -348,22 +326,6 @@ func (in *LibrarySpec) DeepCopy() *LibrarySpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NameValue) DeepCopyInto(out *NameValue) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NameValue. -func (in *NameValue) DeepCopy() *NameValue { - if in == nil { - return nil - } - out := new(NameValue) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RegistriesConfigFile) DeepCopyInto(out *RegistriesConfigFile) { *out = *in diff --git a/bootstrap/pkg/client/client.go b/bootstrap/pkg/client/client.go new file mode 100644 index 00000000000..baa2e87ad6d --- /dev/null +++ b/bootstrap/pkg/client/client.go @@ -0,0 +1,16 @@ +// Copyright 2018 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 client +package client diff --git a/bootstrap/pkg/client/coordinator/coordinator.go b/bootstrap/pkg/client/coordinator/coordinator.go new file mode 100644 index 00000000000..abfbc3f503b --- /dev/null +++ b/bootstrap/pkg/client/coordinator/coordinator.go @@ -0,0 +1,324 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package coordinator + +import ( + "fmt" + "github.com/ghodss/yaml" + kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" + cltypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/client/v1alpha1" + "github.com/kubeflow/kubeflow/bootstrap/pkg/client/gcp" + "github.com/kubeflow/kubeflow/bootstrap/pkg/client/ksonnet" + "github.com/mitchellh/go-homedir" + "io/ioutil" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "os" + "path" + "path/filepath" + "regexp" + "strings" + // STATIC + "github.com/kubeflow/kubeflow/bootstrap/pkg/client/dockerfordesktop" + + "github.com/kubeflow/kubeflow/bootstrap/pkg/client/minikube" + log "github.com/sirupsen/logrus" +) + +// The common entry point used to retrieve an implementation of KfApp. +// In this case it returns a composite class (coordinator) which aggregates +// platform and ksonnet implementations in Children. +func GetKfApp(options map[string]interface{}) kftypes.KfApp { + _client := &coordinator{ + Children: make(map[string]kftypes.KfApp), + Client: &cltypes.Client{ + TypeMeta: metav1.TypeMeta{ + Kind: "Client", + APIVersion: "client.apps.kubeflow.org/v1alpha1", + }, + }, + } + _client.Children[kftypes.NONE] = ksonnet.GetKfApp(options) + platform := options[string(kftypes.PLATFORM)].(string) + if !(platform == "" || platform == kftypes.NONE) { + _platform, _platformErr := GetPlatform(options) + if _platformErr != nil { + log.Fatalf("could not get platform %v Error %v **", platform, _platformErr) + return nil + } + if _platform != nil { + _client.Children[platform] = _platform + } + } + _client.Client.Spec.Platform = options[string(kftypes.PLATFORM)].(string) + if options[string(kftypes.APPNAME)] != nil { + _client.Client.Name = options[string(kftypes.APPNAME)].(string) + } + if options[string(kftypes.APPDIR)] != nil { + _client.Client.Spec.AppDir = options[string(kftypes.APPDIR)].(string) + } + if options[string(kftypes.NAMESPACE)] != nil { + namespace := options[string(kftypes.NAMESPACE)].(string) + _client.Client.Namespace = namespace + } + if options[string(kftypes.REPO)] != nil { + kubeflowRepo := options[string(kftypes.REPO)].(string) + re := regexp.MustCompile(`(^\$GOPATH)(.*$)`) + goPathVar := os.Getenv("GOPATH") + if goPathVar != "" { + kubeflowRepo = re.ReplaceAllString(kubeflowRepo, goPathVar+`$2`) + } + _client.Client.Spec.Repo = path.Join(kubeflowRepo, "kubeflow") + } + if options[string(kftypes.VERSION)] != nil { + kubeflowVersion := options[string(kftypes.VERSION)].(string) + _client.Client.Spec.Version = kubeflowVersion + } + if options[string(kftypes.DATA)] != nil { + dat := options[string(kftypes.DATA)].([]byte) + specErr := yaml.Unmarshal(dat, _client.Client) + if specErr != nil { + log.Errorf("couldn't unmarshal Ksonnet. Error: %v", specErr) + } + } + return _client +} + +// GetPlatform will return an implementation of kftypes.KfApp that matches the platform string +// It looks for statically compiled-in implementations, otherwise it delegates to +// kftypes.LoadPlatform which will try and dynamically load a .so +func GetPlatform(options map[string]interface{}) (kftypes.KfApp, error) { + platform := options[string(kftypes.PLATFORM)].(string) + switch platform { + case string(kftypes.MINIKUBE): + return minikube.GetKfApp(options), nil + case string(kftypes.GCP): + return gcp.GetKfApp(options), nil + // STATIC + case string(kftypes.DOCKER_FOR_DESKTOP): + return dockerfordesktop.GetKfApp(options), nil + // -STATIC // + default: + log.Infof("** loading %v.so for platform %v **", platform, platform) + return kftypes.LoadPlatform(options) + } +} + +// NewKfApp is called from the Init subcommand and will create a directory based on +// the path/name argument given to the Init subcommand +func NewKfApp(options map[string]interface{}) (kftypes.KfApp, error) { + //appName can be a path + appName := options[string(kftypes.APPNAME)].(string) + appDir := path.Dir(appName) + if appDir == "" || appDir == "." { + cwd, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("could not get current directory %v", err) + } + appDir = path.Join(cwd, appName) + } else { + if appDir == "~" { + home, homeErr := homedir.Dir() + if homeErr != nil { + return nil, fmt.Errorf("could not get home directory %v", homeErr) + } + expanded, expandedErr := homedir.Expand(home) + if expandedErr != nil { + return nil, fmt.Errorf("could not expand home directory %v", homeErr) + } + appName = path.Base(appName) + appDir = path.Join(expanded, appName) + } else { + appName = path.Base(appName) + appDir = path.Join(appDir, appName) + } + } + re := regexp.MustCompile(`[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`) + validName := re.FindString(appName) + if strings.Compare(validName, appName) != 0 { + return nil, fmt.Errorf(`invalid name %v must consist of lower case alphanumeric characters, '-' or '.', +and must start and end with an alphanumeric character`, appName) + } + options[string(kftypes.APPNAME)] = appName + options[string(kftypes.APPDIR)] = appDir + pApp := GetKfApp(options) + return pApp, nil +} + +// LoadKfApp is called from subcommands Apply, Delete, Generate and assumes the existence of an app.yaml +// file which was created by the Init subcommand. It sets options needed by these subcommands +func LoadKfApp(options map[string]interface{}) (kftypes.KfApp, error) { + appDir, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("could not get current directory %v", err) + } + appName := filepath.Base(appDir) + cfgfile := filepath.Join(appDir, kftypes.KfConfigFile) + log.Infof("reading from %v", cfgfile) + buf, bufErr := ioutil.ReadFile(cfgfile) + if bufErr != nil { + return nil, fmt.Errorf("couldn't read %v. Error: %v", cfgfile, bufErr) + } + var v interface{} + err = yaml.Unmarshal(buf, &v) + if err != nil { + return nil, fmt.Errorf("could not unmarshal %v. Error: %v", cfgfile, err) + } + data := v.(map[string]interface{}) + metadata := data["metadata"].(map[string]interface{}) + spec := data["spec"].(map[string]interface{}) + platform := spec["platform"].(string) + appName = metadata["name"].(string) + appDir = spec["appdir"].(string) + options[string(kftypes.PLATFORM)] = platform + options[string(kftypes.APPNAME)] = appName + options[string(kftypes.APPDIR)] = appDir + options[string(kftypes.DATA)] = buf + pApp := GetKfApp(options) + return pApp, nil +} + +// this type holds platform implementations of KfApp and ksonnet (also an implementation of KfApp) +// eg Children[kftypes.GCP], Children[kftypes.MINIKUBE], Children[kftypes.NONE] (ksonnet) +// The data attributes in cltypes.Client are used by different KfApp implementations +type coordinator struct { + Children map[string]kftypes.KfApp + Client *cltypes.Client +} + +func (kfapp *coordinator) Apply(resources kftypes.ResourceEnum, options map[string]interface{}) error { + switch resources { + case kftypes.K8S: + fallthrough + case kftypes.PLATFORM: + fallthrough + case kftypes.ALL: + if !(kfapp.Client.Spec.Platform == "" || kfapp.Client.Spec.Platform == kftypes.NONE) { + platform := kfapp.Children[kfapp.Client.Spec.Platform] + if platform != nil { + platformErr := platform.Apply(resources, options) + if platformErr != nil { + return fmt.Errorf("coordinator Apply failed for %v: %v", kfapp.Client.Spec.Platform, platformErr) + } + } else { + return fmt.Errorf("%v not in Children", kfapp.Client.Spec.Platform) + } + } + none := kfapp.Children[kftypes.NONE] + if none != nil { + noneErr := none.Apply(kftypes.K8S, options) + if noneErr != nil { + return fmt.Errorf("coordinator Apply failed for %v: %v", string(kftypes.NONE), noneErr) + } + } else { + return fmt.Errorf("%v not in Children", string(kftypes.NONE)) + } + } + return nil +} + +func (kfapp *coordinator) Delete(resources kftypes.ResourceEnum, options map[string]interface{}) error { + switch resources { + case kftypes.K8S: + fallthrough + case kftypes.PLATFORM: + fallthrough + case kftypes.ALL: + if !(kfapp.Client.Spec.Platform == "" || kfapp.Client.Spec.Platform == kftypes.NONE) { + platform := kfapp.Children[kfapp.Client.Spec.Platform] + if platform != nil { + platformErr := platform.Delete(resources, options) + if platformErr != nil { + return fmt.Errorf("coordinator Delete failed for %v: %v", kfapp.Client.Spec.Platform, platformErr) + } + } else { + return fmt.Errorf("%v not in Children", kfapp.Client.Spec.Platform) + } + } + none := kfapp.Children[kftypes.NONE] + if none != nil { + noneErr := none.Delete(kftypes.K8S, options) + if noneErr != nil { + return fmt.Errorf("coordinator Init failed for %v: %v", string(kftypes.NONE), noneErr) + } + } else { + return fmt.Errorf("%v not in Children", string(kftypes.NONE)) + } + } + return nil +} + +func (kfapp *coordinator) Generate(resources kftypes.ResourceEnum, options map[string]interface{}) error { + switch resources { + case kftypes.K8S: + fallthrough + case kftypes.PLATFORM: + fallthrough + case kftypes.ALL: + if !(kfapp.Client.Spec.Platform == "" || kfapp.Client.Spec.Platform == kftypes.NONE) { + platform := kfapp.Children[kfapp.Client.Spec.Platform] + if platform != nil { + platformErr := platform.Generate(resources, options) + if platformErr != nil { + return fmt.Errorf("coordinator Generate failed for %v: %v", kfapp.Client.Spec.Platform, platformErr) + } + } else { + return fmt.Errorf("%v not in Children", kfapp.Client.Spec.Platform) + } + } + none := kfapp.Children[kftypes.NONE] + if none != nil { + noneGenerateErr := none.Generate(kftypes.K8S, options) + if noneGenerateErr != nil { + return fmt.Errorf("coordinator Generate failed for %v: %v", string(kftypes.NONE), noneGenerateErr) + } + } else { + return fmt.Errorf("%v not in Children", string(kftypes.NONE)) + } + } + return nil +} + +func (kfapp *coordinator) Init(resources kftypes.ResourceEnum, options map[string]interface{}) error { + switch resources { + case kftypes.K8S: + fallthrough + case kftypes.PLATFORM: + fallthrough + case kftypes.ALL: + none := kfapp.Children[kftypes.NONE] + if none != nil { + noneErr := none.Init(kftypes.K8S, options) + if noneErr != nil { + return fmt.Errorf("coordinator Init failed for %v: %v", string(kftypes.NONE), noneErr) + } + } else { + return fmt.Errorf("%v not in Children", string(kftypes.NONE)) + } + if !(kfapp.Client.Spec.Platform == "" || kfapp.Client.Spec.Platform == kftypes.NONE) { + platform := kfapp.Children[kfapp.Client.Spec.Platform] + if platform != nil { + platformErr := platform.Init(resources, options) + if platformErr != nil { + return fmt.Errorf("coordinator Init failed for %v: %v", kfapp.Client.Spec.Platform, platformErr) + } + } else { + return fmt.Errorf("%v not in Children", kfapp.Client.Spec.Platform) + } + } + } + return nil +} diff --git a/bootstrap/pkg/client/dockerfordesktop/dockerfordesktop.go b/bootstrap/pkg/client/dockerfordesktop/dockerfordesktop.go index c79eae13d25..2d726bfa7a3 100644 --- a/bootstrap/pkg/client/dockerfordesktop/dockerfordesktop.go +++ b/bootstrap/pkg/client/dockerfordesktop/dockerfordesktop.go @@ -19,76 +19,44 @@ package dockerfordesktop import ( "fmt" kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" - kstypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/ksonnet/v1alpha1" - "github.com/kubeflow/kubeflow/bootstrap/pkg/client/ksonnet" - log "github.com/sirupsen/logrus" "os/user" "strconv" "strings" ) // DockerForDesktop implements KfApp Interface -// It includes the Ksonnet along with functionality needed for dockerfordesktop +// It should include functionality needed for the docker-for-desktop platform type DockerForDesktop struct { - kftypes.FullKfApp - //TODO add additional types required for dockerfordesktop platform + //Add additional types required for dockerfordesktop platform } -func GetKfApp(options map[string]interface{}) kftypes.KfApp { - options[string(kftypes.PLATFORM)] = string(kftypes.KSONNET) - log.Infof("getting ksonnet platform in dockerfordesktop") - _ksonnet := ksonnet.GetKfApp(options) - options[string(kftypes.PLATFORM)] = string(kftypes.DOCKER_FOR_DESKTOP) - _dockerfordesktop := &DockerForDesktop{ - FullKfApp: kftypes.FullKfApp{ - Children: make(map[kftypes.Platform]kftypes.KfApp), - }, - } - _dockerfordesktop.Children[kftypes.KSONNET] = _ksonnet - return _dockerfordesktop +func GetKfApp(_ map[string]interface{}) kftypes.KfApp { + return &DockerForDesktop{} } func (dockerfordesktop *DockerForDesktop) Apply(resources kftypes.ResourceEnum, options map[string]interface{}) error { - ks := dockerfordesktop.Children[kftypes.KSONNET] - if ks != nil { - ksApplyErr := ks.Apply(resources, options) - if ksApplyErr != nil { - return fmt.Errorf("dockerfordesktop apply failed for ksonnet: %v", ksApplyErr) - } - } else { - return fmt.Errorf("ksonnet not in Children") - } //mount_local_fs //setup_tunnels return nil } func (dockerfordesktop *DockerForDesktop) Delete(resources kftypes.ResourceEnum, options map[string]interface{}) error { - ks := dockerfordesktop.Children[kftypes.KSONNET] - if ks != nil { - ksDeleteErr := ks.Delete(resources, options) - if ksDeleteErr != nil { - return fmt.Errorf("dockerfordesktop delete failed for ksonnet: %v", ksDeleteErr) - } - } else { - return fmt.Errorf("ksonnet not in Children") - } return nil } -func (dockerfordesktop *DockerForDesktop) generateKsApp(options map[string]interface{}) error { +func (dockerfordesktop *DockerForDesktop) generate(options map[string]interface{}) error { platform := options[string(kftypes.PLATFORM)].(string) mountLocal := false if options[string(kftypes.MOUNT_LOCAL)] != nil { mountLocal = options[string(kftypes.MOUNT_LOCAL)].(bool) } // remove Katib package and component - kstypes.DefaultPackages = kstypes.RemoveItem(kstypes.DefaultPackages, "katib") - kstypes.DefaultComponents = kstypes.RemoveItem(kstypes.DefaultComponents, "katib") - kstypes.DefaultParameters["application"] = []kstypes.NameValue{ + kftypes.DefaultPackages = kftypes.RemoveItem(kftypes.DefaultPackages, "katib") + kftypes.DefaultComponents = kftypes.RemoveItem(kftypes.DefaultComponents, "katib") + kftypes.DefaultParameters["application"] = []kftypes.NameValue{ { Name: "components", - Value: "[" + strings.Join(kstypes.QuoteItems(kstypes.DefaultComponents), ",") + "]", + Value: "[" + strings.Join(kftypes.QuoteItems(kftypes.DefaultComponents), ",") + "]", }, } usr, err := user.Current() @@ -97,7 +65,7 @@ func (dockerfordesktop *DockerForDesktop) generateKsApp(options map[string]inter } uid := usr.Uid gid := usr.Gid - kstypes.DefaultParameters["jupyter"] = []kstypes.NameValue{ + kftypes.DefaultParameters["jupyter"] = []kftypes.NameValue{ { Name: string(kftypes.PLATFORM), Value: platform, @@ -119,7 +87,7 @@ func (dockerfordesktop *DockerForDesktop) generateKsApp(options map[string]inter Value: gid, }, } - kstypes.DefaultParameters["ambassador"] = []kstypes.NameValue{ + kftypes.DefaultParameters["ambassador"] = []kftypes.NameValue{ { Name: string(kftypes.PLATFORM), Value: platform, @@ -129,41 +97,23 @@ func (dockerfordesktop *DockerForDesktop) generateKsApp(options map[string]inter Value: "1", }, } - ks := dockerfordesktop.Children[kftypes.KSONNET] - if ks != nil { - ksGenerateErr := ks.Generate(kftypes.ALL, options) - if ksGenerateErr != nil { - return fmt.Errorf("dockerfordesktop generate failed for ksonnet: %v", ksGenerateErr) - } - } else { - return fmt.Errorf("ksonnet not in Children") - } return nil } func (dockerfordesktop *DockerForDesktop) Generate(resources kftypes.ResourceEnum, options map[string]interface{}) error { switch resources { + case kftypes.K8S: case kftypes.ALL: fallthrough - case kftypes.K8S: - ksErr := dockerfordesktop.generateKsApp(options) - if ksErr != nil { - return fmt.Errorf("could not generate ksonnet under %v Error: %v", kstypes.KsName, ksErr) - } case kftypes.PLATFORM: + generateErr := dockerfordesktop.generate(options) + if generateErr != nil { + return fmt.Errorf("dockerfordesktop generate failed Error: %v", generateErr) + } } return nil } -func (dockerfordesktop *DockerForDesktop) Init(options map[string]interface{}) error { - ks := dockerfordesktop.Children["ksonnet"] - if ks != nil { - ksInitErr := ks.Init(options) - if ksInitErr != nil { - return fmt.Errorf("dockerfordesktop init failed for ksonnet: %v", ksInitErr) - } - } else { - return fmt.Errorf("ksonnet not in Children") - } +func (dockerfordesktop *DockerForDesktop) Init(resources kftypes.ResourceEnum, options map[string]interface{}) error { return nil } diff --git a/bootstrap/pkg/client/gcp/gcp.go b/bootstrap/pkg/client/gcp/gcp.go index 1024425ed16..432fde24337 100644 --- a/bootstrap/pkg/client/gcp/gcp.go +++ b/bootstrap/pkg/client/gcp/gcp.go @@ -26,9 +26,7 @@ import ( configtypes "github.com/kubeflow/kubeflow/bootstrap/config" kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" gcptypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/gcp/v1alpha1" - kstypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/ksonnet/v1alpha1" - "github.com/kubeflow/kubeflow/bootstrap/pkg/client/ksonnet" - kfctlutils "github.com/kubeflow/kubeflow/bootstrap/pkg/utils" + "github.com/kubeflow/kubeflow/bootstrap/pkg/utils" log "github.com/sirupsen/logrus" "golang.org/x/net/context" "golang.org/x/oauth2" @@ -72,19 +70,11 @@ const ( // Gcp implements KfApp Interface // It includes the KsApp along with additional Gcp types type Gcp struct { - kftypes.FullKfApp GcpApp *gcptypes.Gcp } func GetKfApp(options map[string]interface{}) kftypes.KfApp { - options[string(kftypes.PLATFORM)] = string(kftypes.KSONNET) - log.Infof("getting ksonnet platform in gcp") - _ksonnet := ksonnet.GetKfApp(options) - options[string(kftypes.PLATFORM)] = "gcp" _gcp := &Gcp{ - FullKfApp: kftypes.FullKfApp{ - Children: make(map[kftypes.Platform]kftypes.KfApp), - }, GcpApp: &gcptypes.Gcp{ TypeMeta: metav1.TypeMeta{ Kind: "Gcp", @@ -92,7 +82,6 @@ func GetKfApp(options map[string]interface{}) kftypes.KfApp { }, }, } - _gcp.Children[kftypes.KSONNET] = _ksonnet if options[string(kftypes.DATA)] != nil { dat := options[string(kftypes.DATA)].([]byte) specErr := yaml.Unmarshal(dat, _gcp.GcpApp) @@ -236,7 +225,7 @@ func generateTarget(configPath string) (*deploymentmanager.TargetConfiguration, Content: string(buf), }) } else { - return nil, fmt.Errorf("Erro reading import file: %v", err) + return nil, fmt.Errorf("error reading import file: %v", err) } } return targetConfig, nil @@ -246,11 +235,11 @@ func (gcp *Gcp) getK8sClientset(ctx context.Context) (*clientset.Clientset, erro cluster, err := kftypes.GetClusterInfo(ctx, gcp.GcpApp.Spec.Project, gcp.GcpApp.Spec.Zone, gcp.GcpApp.Name) if err != nil { - return nil, fmt.Errorf("Get Cluster error: %v", err) + return nil, fmt.Errorf("get Cluster error: %v", err) } config, err := kftypes.BuildConfigFromClusterInfo(ctx, cluster) if err != nil { - return nil, fmt.Errorf("Build ClientConfig error: %v", err) + return nil, fmt.Errorf("build ClientConfig error: %v", err) } return clientset.NewForConfig(config) @@ -415,19 +404,19 @@ func (gcp *Gcp) updateDM(resources kftypes.ResourceEnum, options map[string]inte } } - policy, policyErr := kfctlutils.GetIamPolicy(gcp.GcpApp.Spec.Project) + policy, policyErr := utils.GetIamPolicy(gcp.GcpApp.Spec.Project) if policyErr != nil { return fmt.Errorf("GetIamPolicy error: %v", policyErr) } appDir := gcp.GcpApp.Spec.AppDir gcpConfigDir := path.Join(appDir, GCP_CONFIG) - iamPolicy, iamPolicyErr := kfctlutils.ReadIamBindingsYAML( + iamPolicy, iamPolicyErr := utils.ReadIamBindingsYAML( filepath.Join(gcpConfigDir, "iam_bindings.yaml")) if iamPolicyErr != nil { return fmt.Errorf("Read IAM policy YAML error: %v", iamPolicyErr) } - kfctlutils.RewriteIamPolicy(policy, iamPolicy, nil) - if err := kfctlutils.SetIamPolicy(gcp.GcpApp.Spec.Project, policy); err != nil { + utils.RewriteIamPolicy(policy, iamPolicy, nil) + if err := utils.SetIamPolicy(gcp.GcpApp.Spec.Project, policy); err != nil { return fmt.Errorf("SetIamPolicy error: %v", err) } @@ -459,7 +448,7 @@ func (gcp *Gcp) updateDM(resources kftypes.ResourceEnum, options map[string]inte k8sSpecsDir := path.Join(appDir, K8S_SPECS) daemonsetPreloaded := filepath.Join(k8sSpecsDir, "daemonset-preloaded.yaml") - daemonsetPreloadedErr := kfctlutils.RunKubectlApply(daemonsetPreloaded) + daemonsetPreloadedErr := utils.RunKubectlApply(daemonsetPreloaded) if daemonsetPreloadedErr != nil { return fmt.Errorf("could not create resources in daemonset-preloaded.yaml %v", daemonsetPreloadedErr) } @@ -467,12 +456,12 @@ func (gcp *Gcp) updateDM(resources kftypes.ResourceEnum, options map[string]inte adminClient.Impersonate.UserName = "admin" adminClient.Impersonate.Groups = []string{"system:masters"} rbacSetup := filepath.Join(k8sSpecsDir, "rbac-setup.yaml") - rbacSetupErr := kfctlutils.RunKubectlApply(rbacSetup) + rbacSetupErr := utils.RunKubectlApply(rbacSetup) if rbacSetupErr != nil { return fmt.Errorf("could not create resources in rbac-setup.yaml %v", rbacSetupErr) } agents := filepath.Join(k8sSpecsDir, "agents.yaml") - agentsErr := kfctlutils.RunKubectlApply(agents) + agentsErr := utils.RunKubectlApply(agents) if agentsErr != nil { return fmt.Errorf("could not create resources in agents.yaml %v", agents) } @@ -488,28 +477,10 @@ func (gcp *Gcp) Apply(resources kftypes.ResourceEnum, options map[string]interfa if secretsErr != nil { return fmt.Errorf("gcp apply could not create secrets Error %v", secretsErr) } - ks := gcp.Children[kftypes.KSONNET] - if ks != nil { - ksApplyErr := ks.Apply(resources, options) - if ksApplyErr != nil { - return fmt.Errorf("gcp apply failed for %v: %v", string(kftypes.KSONNET), ksApplyErr) - } - } else { - return fmt.Errorf("%v not in Children", string(kftypes.KSONNET)) - } return nil } func (gcp *Gcp) Delete(resources kftypes.ResourceEnum, options map[string]interface{}) error { - ks := gcp.Children[kftypes.KSONNET] - if ks != nil { - ksDeleteErr := ks.Delete(resources, options) - if ksDeleteErr != nil { - return fmt.Errorf("gcp delete failed for %v: %v", string(kftypes.KSONNET), ksDeleteErr) - } - } else { - return fmt.Errorf("%v not in Children", string(kftypes.KSONNET)) - } return nil } @@ -547,25 +518,25 @@ func setNameVal(entries []configtypes.NameValue, name string, val string) { }) } -func (gcp *Gcp) generateKsonnet(options map[string]interface{}) error { +func (gcp *Gcp) generate(options map[string]interface{}) error { configPath := path.Join(gcp.GcpApp.Spec.AppDir, kftypes.DefaultCacheDir, gcp.GcpApp.Spec.Version, - kftypes.GcpConfigDir) + kftypes.DefaultConfigDir) if gcp.GcpApp.Spec.UseBasicAuth { configPath = path.Join(configPath, kftypes.GcpBasicAuth) } else { configPath = path.Join(configPath, kftypes.GcpIapConfig) } - if options[string(kftypes.DefaultConfig)] == nil { - options[string(kftypes.DefaultConfig)] = configPath + if options[string(kftypes.DEFAULT_CONFIG)] == nil { + options[string(kftypes.DEFAULT_CONFIG)] = configPath } if options[string(kftypes.EMAIL)] != nil && options[string(kftypes.EMAIL)].(string) != "" { gcp.GcpApp.Spec.Email = options[string(kftypes.EMAIL)].(string) } else if gcp.GcpApp.Spec.Email == "" { - return fmt.Errorf("Email is not set in default nor passed.") + return fmt.Errorf("email is not set in default nor passed.") } else { options[string(kftypes.EMAIL)] = gcp.GcpApp.Spec.Email } @@ -589,22 +560,10 @@ func (gcp *Gcp) generateKsonnet(options map[string]interface{}) error { gcp.GcpApp.Spec.Hostname = options[string(kftypes.HOSTNAME)].(string) } else if gcp.GcpApp.Spec.Hostname == "" { return fmt.Errorf("hostname is not set in default nor passed.") - } else { - log.Infof("Using default hostname: %v", gcp.GcpApp.Spec.Hostname) - options[string(kftypes.HOSTNAME)] = gcp.GcpApp.Spec.Hostname } if options[string(kftypes.ZONE)] != nil { gcp.GcpApp.Spec.Zone = options[string(kftypes.ZONE)].(string) } - ks := gcp.Children[kftypes.KSONNET] - if ks != nil { - ksGenerateErr := ks.Generate(kftypes.ALL, options) - if ksGenerateErr != nil { - return fmt.Errorf("gcp generate failed for %v: %v", string(kftypes.KSONNET), ksGenerateErr) - } - } else { - return fmt.Errorf("%v not in Children", string(kftypes.KSONNET)) - } return nil } @@ -848,9 +807,9 @@ func (gcp *Gcp) Generate(resources kftypes.ResourceEnum, options map[string]inte if generateK8sSpecsErr != nil { return fmt.Errorf("could not generate files under %v Error: %v", K8S_SPECS, generateK8sSpecsErr) } - ksonnetErr := gcp.generateKsonnet(options) - if ksonnetErr != nil { - return fmt.Errorf("could not generate kssonnet under %v Error: %v", kstypes.KsName, ksonnetErr) + generateErr := gcp.generate(options) + if generateErr != nil { + return fmt.Errorf("generate failed Error: %v", generateErr) } case kftypes.ALL: gcpConfigFilesErr := gcp.generateDMConfigs(options) @@ -861,18 +820,18 @@ func (gcp *Gcp) Generate(resources kftypes.ResourceEnum, options map[string]inte if generateK8sSpecsErr != nil { return fmt.Errorf("could not generate files under %v Error: %v", K8S_SPECS, generateK8sSpecsErr) } - ksonnetErr := gcp.generateKsonnet(options) - if ksonnetErr != nil { - return fmt.Errorf("could not generate kssonnet under %v Error: %v", kstypes.KsName, ksonnetErr) + generateErr := gcp.generate(options) + if generateErr != nil { + return fmt.Errorf("generate failed Error: %v", generateErr) } case kftypes.PLATFORM: gcpConfigFilesErr := gcp.generateDMConfigs(options) if gcpConfigFilesErr != nil { return fmt.Errorf("could not generate deployment manager configs under %v Error: %v", GCP_CONFIG, gcpConfigFilesErr) } - ksonnetErr := gcp.generateKsonnet(options) - if ksonnetErr != nil { - return fmt.Errorf("could not generate kssonnet under %v Error: %v", kstypes.KsName, ksonnetErr) + generateErr := gcp.generate(options) + if generateErr != nil { + return fmt.Errorf("generate failed Error: %v", generateErr) } } createConfigErr := gcp.writeConfigFile() @@ -883,11 +842,9 @@ func (gcp *Gcp) Generate(resources kftypes.ResourceEnum, options map[string]inte } func (gcp *Gcp) getServiceClient(ctx context.Context) (*http.Client, error) { - // See https://cloud.google.com/docs/authentication/. // Use GOOGLE_APPLICATION_CREDENTIALS environment variable to specify // a service account key file to authenticate to the API. - client, err := google.DefaultClient(ctx, gke.CloudPlatformScope) if err != nil { log.Fatalf("Could not authenticate client: %v", err) @@ -928,16 +885,7 @@ func (gcp *Gcp) gcpInitProject() error { return nil } -func (gcp *Gcp) Init(options map[string]interface{}) error { - ks := gcp.Children[kftypes.KSONNET] - if ks != nil { - ksInitErr := ks.Init(options) - if ksInitErr != nil { - return fmt.Errorf("gcp init failed for %v: %v", string(kftypes.KSONNET), ksInitErr) - } - } else { - return fmt.Errorf("%v not in Children", string(kftypes.KSONNET)) - } +func (gcp *Gcp) Init(resources kftypes.ResourceEnum, options map[string]interface{}) error { cacheDir := path.Join(gcp.GcpApp.Spec.AppDir, kftypes.DefaultCacheDir) newPath := filepath.Join(cacheDir, gcp.GcpApp.Spec.Version) gcp.GcpApp.Spec.Repo = path.Join(newPath, "kubeflow") diff --git a/bootstrap/pkg/client/ksonnet/ksonnet.go b/bootstrap/pkg/client/ksonnet/ksonnet.go index 09ce07fb90b..cee5606fed2 100644 --- a/bootstrap/pkg/client/ksonnet/ksonnet.go +++ b/bootstrap/pkg/client/ksonnet/ksonnet.go @@ -76,9 +76,15 @@ func GetKfApp(options map[string]interface{}) kftypes.KfApp { } if options[string(kftypes.APPDIR)] != nil { _kfapp.KsApp.Spec.AppDir = options[string(kftypes.APPDIR)].(string) - } - if options[string(kftypes.KAPP)] != nil { - _kfapp.KApp = options[string(kftypes.KAPP)].(app.App) + ksDir := path.Join(_kfapp.KsApp.Spec.AppDir, kstypes.KsName) + if _, err := os.Stat(ksDir); !os.IsNotExist(err) { + fs := afero.NewOsFs() + kApp, kAppErr := app.Load(fs, nil, ksDir) + if kAppErr != nil { + log.Fatalf("there was a problem loading ksonnet app from %v. Error: %v", ksDir, kAppErr) + } + _kfapp.KApp = kApp + } } if options[string(kftypes.NAMESPACE)] != nil { namespace := options[string(kftypes.NAMESPACE)].(string) @@ -146,7 +152,7 @@ func (ksApp *KsApp) Apply(resources kftypes.ResourceEnum, options map[string]int return fmt.Errorf("couldn't get server version: %v", err) } log.Infof("ServerVersion: %v", host) - cli, cliErr := kftypes.GetClientOutOfClusterWithConfig(config) + cli, cliErr := kftypes.GetClientOutOfCluster() if cliErr != nil { return fmt.Errorf("couldn't create client Error: %v", cliErr) } @@ -307,12 +313,57 @@ func (ksApp *KsApp) components() (map[string]*kstypes.KsComponent, error) { return comps, nil } +func (ksApp *KsApp) deleteGlobalResources() error { + crdClient, clientErr := kftypes.GetApiExtensionsClientOutOfCluster() + if clientErr != nil { + return fmt.Errorf("couldn't get client Error: %v", clientErr) + } + do := &metav1.DeleteOptions{} + lo := metav1.ListOptions{ + LabelSelector: kftypes.DefaultAppLabel + "=" + ksApp.KsApp.Name, + } + crdsErr := crdClient.CustomResourceDefinitions().DeleteCollection(do, lo) + if crdsErr != nil { + return fmt.Errorf("couldn't delete customresourcedefinitions Error: %v", crdsErr) + } + crdsByName := []string{ + "compositecontrollers.metacontroller.k8s.io", + "controllerrevisions.metacontroller.k8s.io", + "decoratorcontrollers.metacontroller.k8s.io", + "applications.app.k8s.io", + } + for _, crd := range crdsByName { + do := &metav1.DeleteOptions{} + dErr := crdClient.CustomResourceDefinitions().Delete(crd, do) + if dErr != nil { + log.Errorf("could not delete %v Error %v", crd, dErr) + } + } + cli, cliErr := kftypes.GetClientOutOfCluster() + if cliErr != nil { + return fmt.Errorf("couldn't create client Error: %v", cliErr) + } + crbsErr := cli.RbacV1().ClusterRoleBindings().DeleteCollection(do, lo) + if crbsErr != nil { + return fmt.Errorf("couldn't get list of clusterrolebindings Error: %v", crbsErr) + } + crbName := "meta-controller-cluster-role-binding" + dErr := cli.RbacV1().ClusterRoleBindings().Delete(crbName, do) + if dErr != nil { + log.Errorf("could not delete %v Error %v", crbName, dErr) + } + crsErr := cli.RbacV1().ClusterRoles().DeleteCollection(do, lo) + if crsErr != nil { + return fmt.Errorf("couldn't delete clusterroles Error: %v", crsErr) + } + return nil +} + func (ksApp *KsApp) Delete(resources kftypes.ResourceEnum, options map[string]interface{}) error { - //TODO not deleting the following - //clusterrolebinding.rbac.authorization.k8s.io "meta-controller-cluster-role-binding" deleted - //customresourcedefinition.apiextensions.k8s.io "compositecontrollers.metacontroller.k8s.io" deleted - //customresourcedefinition.apiextensions.k8s.io "controllerrevisions.metacontroller.k8s.io" deleted - //customresourcedefinition.apiextensions.k8s.io "decoratorcontrollers.metacontroller.k8s.io" deleted + err := ksApp.deleteGlobalResources() + if err != nil { + log.Errorf("there was a problem deleting global resources: %v", err) + } host, _, serverErr := kftypes.ServerVersion() if serverErr != nil { return fmt.Errorf("couldn't get server version: %v", serverErr) @@ -330,7 +381,7 @@ func (ksApp *KsApp) Delete(resources kftypes.ResourceEnum, options map[string]in return fmt.Errorf("couldn't load client config Error: %v", clientConfigErr) } components := []string{"application", "metacontroller"} - err := actions.RunDelete(map[string]interface{}{ + err = actions.RunDelete(map[string]interface{}{ actions.OptionApp: ksApp.KApp, actions.OptionClientConfig: &client.Config{ Overrides: &clientcmd.ConfigOverrides{}, @@ -352,6 +403,7 @@ func (ksApp *KsApp) Delete(resources kftypes.ResourceEnum, options map[string]in return fmt.Errorf("couldn't delete namespace %v Error: %v", namespace, nsErr) } } + name := "meta-controller-cluster-role-binding" crb, crbErr := cli.RbacV1().ClusterRoleBindings().Get(name, metav1.GetOptions{}) if crbErr == nil { @@ -382,7 +434,21 @@ func (ksApp *KsApp) Generate(resources kftypes.ResourceEnum, options map[string] log.Infof("Ksonnet.Generate Name %v AppDir %v Platform %v", ksApp.KsApp.Name, ksApp.KsApp.Spec.AppDir, ksApp.KsApp.Spec.Platform) - configPath := options[string(kftypes.DefaultConfig)].(string) + configPath := path.Join(ksApp.KsApp.Spec.AppDir, + kftypes.DefaultCacheDir, + ksApp.KsApp.Spec.Version, + kftypes.DefaultConfigDir) + + initErr := ksApp.initKs() + if initErr != nil { + return fmt.Errorf("couldn't initialize KfApi: %v", initErr) + } + if options[string(kftypes.DEFAULT_CONFIG)] == nil { + configPath = filepath.Join(configPath, kftypes.DefaultConfigFile) + options[string(kftypes.DEFAULT_CONFIG)] = configPath + } else { + configPath = options[string(kftypes.DEFAULT_CONFIG)].(string) + } config := &configtypes.ComponentConfig{} if buf, bufErr := ioutil.ReadFile(configPath); bufErr == nil { if readErr := yaml.Unmarshal(buf, config); readErr != nil { @@ -391,7 +457,6 @@ func (ksApp *KsApp) Generate(resources kftypes.ResourceEnum, options map[string] } else { return fmt.Errorf("Unable to read config %v: %v", configPath, bufErr) } - config.Repo = ksApp.KsApp.Spec.Repo email := options[string(kftypes.EMAIL)].(string) setNameVal(config.ComponentParams["cert-manager"], "acmeEmail", email) @@ -417,14 +482,6 @@ func (ksApp *KsApp) Generate(resources kftypes.ResourceEnum, options map[string] log.Infof("Configs for generation: %+v", config) - host, k8sSpec, err := kftypes.ServerVersion() - if err != nil { - return fmt.Errorf("couldn't get server version: %v", err) - } - initErr := ksApp.initKs("default", k8sSpec, host, ksApp.KsApp.Namespace) - if initErr != nil { - return fmt.Errorf("couldn't initialize KfApi: %v", initErr) - } ksRegistry := kstypes.DefaultRegistry ksRegistry.Version = ksApp.KsApp.Spec.Version ksRegistry.RegUri = ksApp.KsApp.Spec.Repo @@ -442,6 +499,7 @@ func (ksApp *KsApp) Generate(resources kftypes.ResourceEnum, options map[string] return fmt.Errorf("couldn't add package %v. Error: %v", pkg.Name, packageAddErr) } } + componentArray := ksApp.KsApp.Spec.Components for _, compName := range config.Components { comp := kstypes.KsComponent{ Name: compName, @@ -457,7 +515,15 @@ func (ksApp *KsApp) Generate(resources kftypes.ResourceEnum, options map[string] } } } - if componentAddErr := ksApp.componentAdd(comp, parameterArgs); componentAddErr != nil { + if compName == "application" { + parameterArgs = append(parameterArgs, "--components") + prunedArray := kftypes.RemoveItems(componentArray, "application", "metacontroller") + quotedArray := kftypes.QuoteItems(prunedArray) + arrayString := "[" + strings.Join(quotedArray, ",") + "]" + parameterArgs = append(parameterArgs, arrayString) + } + componentAddErr := ksApp.componentAdd(comp, parameterArgs) + if componentAddErr != nil { return fmt.Errorf("couldn't add comp %v. Error: %v", comp.Name, componentAddErr) } } @@ -479,10 +545,8 @@ func (ksApp *KsApp) Generate(resources kftypes.ResourceEnum, options map[string] return nil } -func (ksApp *KsApp) Init(options map[string]interface{}) error { +func (ksApp *KsApp) Init(resources kftypes.ResourceEnum, options map[string]interface{}) error { ksApp.KsApp.Spec.Platform = options[string(kftypes.PLATFORM)].(string) - log.Infof("Ksonnet.Init Name %v AppDir %v Platform %v", ksApp.KsApp.Name, - ksApp.KsApp.Spec.AppDir, ksApp.KsApp.Spec.Platform) err := os.Mkdir(ksApp.KsApp.Spec.AppDir, os.ModePerm) if err != nil { return fmt.Errorf("couldn't create directory %v, most likely it already exists", ksApp.KsApp.Spec.AppDir) @@ -521,20 +585,24 @@ func (ksApp *KsApp) Init(options map[string]interface{}) error { return nil } -func (ksApp *KsApp) initKs(envName string, k8sSpecFlag string, host string, namespace string) error { +func (ksApp *KsApp) initKs() error { newRoot := path.Join(ksApp.KsApp.Spec.AppDir, ksApp.KsName) - ksApp.KsEnvName = envName + ksApp.KsEnvName = kstypes.KsEnvName + host, k8sSpec, err := kftypes.ServerVersion() + if err != nil { + return fmt.Errorf("couldn't get server version: %v", err) + } options := map[string]interface{}{ actions.OptionFs: afero.NewOsFs(), actions.OptionName: ksApp.KsName, actions.OptionEnvName: ksApp.KsEnvName, actions.OptionNewRoot: newRoot, actions.OptionServer: host, - actions.OptionSpecFlag: k8sSpecFlag, - actions.OptionNamespace: namespace, + actions.OptionSpecFlag: k8sSpec, + actions.OptionNamespace: ksApp.KsApp.Namespace, actions.OptionSkipDefaultRegistries: true, } - err := actions.RunInit(options) + err = actions.RunInit(options) if err != nil { return fmt.Errorf("there was a problem initializing the app: %v", err) } diff --git a/bootstrap/pkg/client/minikube/minikube.go b/bootstrap/pkg/client/minikube/minikube.go index a5d36d5129e..14b787cc1fe 100644 --- a/bootstrap/pkg/client/minikube/minikube.go +++ b/bootstrap/pkg/client/minikube/minikube.go @@ -19,76 +19,43 @@ package minikube import ( "fmt" kftypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps" - kstypes "github.com/kubeflow/kubeflow/bootstrap/pkg/apis/apps/ksonnet/v1alpha1" - "github.com/kubeflow/kubeflow/bootstrap/pkg/client/ksonnet" - log "github.com/sirupsen/logrus" "os/user" "strconv" "strings" ) // Minikube implements KfApp Interface -// It includes the Ksonnet along with functionality needed for minikube type Minikube struct { - kftypes.FullKfApp //TODO add additional types required for minikube platform } func GetKfApp(options map[string]interface{}) kftypes.KfApp { - options[string(kftypes.PLATFORM)] = string(kftypes.KSONNET) - log.Infof("getting ksonnet platform in minikube") - _ksonnet := ksonnet.GetKfApp(options) - options[string(kftypes.PLATFORM)] = string(kftypes.MINIKUBE) - _minikube := &Minikube{ - FullKfApp: kftypes.FullKfApp{ - Children: make(map[kftypes.Platform]kftypes.KfApp), - }, - } - _minikube.Children[kftypes.KSONNET] = _ksonnet - return _minikube + return &Minikube{} } func (minikube *Minikube) Apply(resources kftypes.ResourceEnum, options map[string]interface{}) error { - ks := minikube.Children[kftypes.KSONNET] - if ks != nil { - ksApplyErr := ks.Apply(resources, options) - if ksApplyErr != nil { - return fmt.Errorf("minikube apply failed for %v: %v", string(kftypes.KSONNET), ksApplyErr) - } - } else { - return fmt.Errorf("%v not in Children", string(kftypes.KSONNET)) - } //mount_local_fs //setup_tunnels return nil } func (minikube *Minikube) Delete(resources kftypes.ResourceEnum, options map[string]interface{}) error { - ks := minikube.Children[kftypes.KSONNET] - if ks != nil { - ksDeleteErr := ks.Delete(resources, options) - if ksDeleteErr != nil { - return fmt.Errorf("minikube delete failed for %v: %v", string(kftypes.KSONNET), ksDeleteErr) - } - } else { - return fmt.Errorf("%v not in Children", string(kftypes.KSONNET)) - } return nil } -func (minikube *Minikube) generateKsonnet(options map[string]interface{}) error { +func (minikube *Minikube) generate(options map[string]interface{}) error { platform := options[string(kftypes.PLATFORM)].(string) mountLocal := false if options[string(kftypes.MOUNT_LOCAL)] != nil { mountLocal = options[string(kftypes.MOUNT_LOCAL)].(bool) } // remove Katib package and component - kstypes.DefaultPackages = kstypes.RemoveItem(kstypes.DefaultPackages, "katib") - kstypes.DefaultComponents = kstypes.RemoveItem(kstypes.DefaultComponents, "katib") - kstypes.DefaultParameters["application"] = []kstypes.NameValue{ + kftypes.DefaultPackages = kftypes.RemoveItem(kftypes.DefaultPackages, "katib") + kftypes.DefaultComponents = kftypes.RemoveItem(kftypes.DefaultComponents, "katib") + kftypes.DefaultParameters["application"] = []kftypes.NameValue{ { Name: "components", - Value: "[" + strings.Join(kstypes.QuoteItems(kstypes.DefaultComponents), ",") + "]", + Value: "[" + strings.Join(kftypes.QuoteItems(kftypes.DefaultComponents), ",") + "]", }, } usr, err := user.Current() @@ -97,7 +64,7 @@ func (minikube *Minikube) generateKsonnet(options map[string]interface{}) error } uid := usr.Uid gid := usr.Gid - kstypes.DefaultParameters["jupyter"] = []kstypes.NameValue{ + kftypes.DefaultParameters["jupyter"] = []kftypes.NameValue{ { Name: string(kftypes.PLATFORM), Value: platform, @@ -119,7 +86,7 @@ func (minikube *Minikube) generateKsonnet(options map[string]interface{}) error Value: gid, }, } - kstypes.DefaultParameters["ambassador"] = []kstypes.NameValue{ + kftypes.DefaultParameters["ambassador"] = []kftypes.NameValue{ { Name: string(kftypes.PLATFORM), Value: platform, @@ -129,41 +96,23 @@ func (minikube *Minikube) generateKsonnet(options map[string]interface{}) error Value: "1", }, } - ks := minikube.Children[kftypes.KSONNET] - if ks != nil { - ksGenerateErr := ks.Generate(kftypes.ALL, options) - if ksGenerateErr != nil { - return fmt.Errorf("minikube generate failed for %v: %v", string(kftypes.KSONNET), ksGenerateErr) - } - } else { - return fmt.Errorf("%v not in Children", string(kftypes.KSONNET)) - } return nil } func (minikube *Minikube) Generate(resources kftypes.ResourceEnum, options map[string]interface{}) error { switch resources { + case kftypes.K8S: case kftypes.ALL: fallthrough - case kftypes.K8S: - ksErr := minikube.generateKsonnet(options) - if ksErr != nil { - return fmt.Errorf("could not generate ksonnet under %v Error: %v", kstypes.KsName, ksErr) - } case kftypes.PLATFORM: + generateErr := minikube.generate(options) + if generateErr != nil { + return fmt.Errorf("minikube generate failed Error: %v", generateErr) + } } return nil } -func (minikube *Minikube) Init(options map[string]interface{}) error { - ks := minikube.Children[kftypes.KSONNET] - if ks != nil { - ksInitErr := ks.Init(options) - if ksInitErr != nil { - return fmt.Errorf("minikube init failed for %v: %v", string(kftypes.KSONNET), ksInitErr) - } - } else { - return fmt.Errorf("%v not in Children", string(kftypes.KSONNET)) - } +func (minikube *Minikube) Init(kftypes.ResourceEnum, map[string]interface{}) error { return nil } diff --git a/components/centraldashboard/public/.eslintrc.json b/components/centraldashboard/public/.eslintrc.json new file mode 100644 index 00000000000..c2592d9d841 --- /dev/null +++ b/components/centraldashboard/public/.eslintrc.json @@ -0,0 +1,22 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "extends": ["eslint:recommended", "google"], + "globals": { + "VERSION": true, + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "impliedStrict": true + } + }, + "rules": { + "indent": ["error", 4], + "require-jsdoc": "off" + } +} diff --git a/components/centraldashboard/public/components/main-page.css b/components/centraldashboard/public/components/main-page.css index 208eac57642..6bc71f558ee 100644 --- a/components/centraldashboard/public/components/main-page.css +++ b/components/centraldashboard/public/components/main-page.css @@ -129,4 +129,4 @@ a[href] { a[href]:hover { color: var(--paper-blue-700); text-decoration: underline; -} \ No newline at end of file +} diff --git a/scripts/kfctl.sh b/scripts/kfctl.sh index 2936b63b4f2..b85af50f1a2 100755 --- a/scripts/kfctl.sh +++ b/scripts/kfctl.sh @@ -532,6 +532,26 @@ main() { fi fi set +e + pushd ${KUBEFLOW_KS_DIR} + appname=$(ks param list application | grep '^application name'|awk '{print $NF}'|tr -d "'") + popd + for i in $(kubectl get crds -lapp.kubernetes.io/name=$appname -oname); do + crd=${i#*/} + kubectl delete crd $crd + done + for i in $(kubectl get clusterroles -lapp.kubernetes.io/name=$appname -oname); do + clusterrole=${i#*/} + kubectl delete clusterrole $clusterrole + done + for i in $(kubectl get clusterrolebindings -lapp.kubernetes.io/name=$appname -oname); do + clusterrolebinding=${i#*/} + kubectl delete clusterrolebinding $clusterrolebinding + done + kubectl delete clusterrolebinding meta-controller-cluster-role-binding + kubectl delete crd compositecontrollers.metacontroller.k8s.io + kubectl delete crd controllerrevisions.metacontroller.k8s.io + kubectl delete crd decoratorcontrollers.metacontroller.k8s.io + kubectl delete crd applications.app.k8s.io kubectl delete ns/${K8S_NAMESPACE} while kubectl get ns/${K8S_NAMESPACE}; do echo "namespace ${K8S_NAMESPACE} not yet deleted. sleeping 10 seconds..." diff --git a/testing/workflows/components/kfctl_test.jsonnet b/testing/workflows/components/kfctl_test.jsonnet index 01f00c4cadf..48ad53869bb 100644 --- a/testing/workflows/components/kfctl_test.jsonnet +++ b/testing/workflows/components/kfctl_test.jsonnet @@ -314,7 +314,6 @@ local dagTemplates = [ "default", "-c", "spark-operator", - "--verbose", ], working_dir=appDir + "/ks_app" ),