├── .gitignore ├── .travis.yml ├── ADOPTERS.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── OWNERS ├── README.md ├── RELEASE.md ├── ROADMAP.md ├── cmd ├── mxnet-operator.v1 │ ├── app │ │ ├── options │ │ │ └── options.go │ │ └── server.go │ └── main.go └── mxnet-operator.v1beta1 │ ├── app │ ├── options │ │ └── options.go │ └── server.go │ └── main.go ├── examples ├── train │ ├── Dockerfile │ ├── byteps_dist_gpu_v1.yaml │ ├── byteps_dist_gpu_v1beta1.yaml │ ├── mx_job_dist_gpu_v1.yaml │ └── mx_job_dist_gpu_v1beta1.yaml └── tune │ ├── Dockerfile │ ├── README.md │ ├── auto-tuning.py │ ├── mx_job_tune_gpu_v1.yaml │ ├── mx_job_tune_gpu_v1beta1.yaml │ └── start-job.py ├── go.mod ├── go.sum ├── hack ├── boilerplate │ └── boilerplate.go.txt ├── scripts │ └── cleanup_clusters.sh ├── update-codegen.sh └── verify-codegen.sh ├── linter_config.yaml ├── manifests ├── base │ ├── cluster-role-binding.yaml │ ├── cluster-role.yaml │ ├── deployment.yaml │ ├── kustomization.yaml │ ├── podgroup.yaml │ ├── service-account.yaml │ └── user-cluster-roles.yaml └── overlays │ ├── kubeflow │ └── kustomization.yaml │ ├── v1 │ ├── crd-v1.yaml │ ├── deployment.yaml │ └── kustomization.yaml │ └── v1beta1 │ ├── crd-v1beta1.yaml │ └── kustomization.yaml ├── pkg ├── apis │ └── mxnet │ │ ├── v1 │ │ ├── constants.go │ │ ├── defaults.go │ │ ├── defaults_test.go │ │ ├── doc.go │ │ ├── register.go │ │ ├── types.go │ │ ├── util.go │ │ ├── util_test.go │ │ ├── zz_generated.deepcopy.go │ │ └── zz_generated.defaults.go │ │ ├── v1beta1 │ │ ├── constants.go │ │ ├── defaults.go │ │ ├── doc.go │ │ ├── register.go │ │ ├── types.go │ │ ├── util.go │ │ ├── util_test.go │ │ ├── zz_generated.deepcopy.go │ │ └── zz_generated.defaults.go │ │ └── validation │ │ ├── validation.go │ │ └── validation_test.go ├── client │ ├── clientset │ │ └── versioned │ │ │ ├── clientset.go │ │ │ ├── doc.go │ │ │ ├── fake │ │ │ ├── clientset_generated.go │ │ │ ├── doc.go │ │ │ └── register.go │ │ │ ├── scheme │ │ │ ├── doc.go │ │ │ └── register.go │ │ │ └── typed │ │ │ └── mxnet │ │ │ ├── v1 │ │ │ ├── doc.go │ │ │ ├── fake │ │ │ │ ├── doc.go │ │ │ │ ├── fake_mxjob.go │ │ │ │ └── fake_mxnet_client.go │ │ │ ├── generated_expansion.go │ │ │ ├── mxjob.go │ │ │ └── mxnet_client.go │ │ │ └── v1beta1 │ │ │ ├── doc.go │ │ │ ├── fake │ │ │ ├── doc.go │ │ │ ├── fake_mxjob.go │ │ │ └── fake_mxnet_client.go │ │ │ ├── generated_expansion.go │ │ │ ├── mxjob.go │ │ │ └── mxnet_client.go │ ├── informers │ │ └── externalversions │ │ │ ├── factory.go │ │ │ ├── generic.go │ │ │ ├── internalinterfaces │ │ │ └── factory_interfaces.go │ │ │ └── mxnet │ │ │ ├── interface.go │ │ │ ├── v1 │ │ │ ├── interface.go │ │ │ └── mxjob.go │ │ │ └── v1beta1 │ │ │ ├── interface.go │ │ │ └── mxjob.go │ └── listers │ │ └── mxnet │ │ ├── v1 │ │ ├── expansion_generated.go │ │ └── mxjob.go │ │ └── v1beta1 │ │ ├── expansion_generated.go │ │ └── mxjob.go ├── common │ └── util │ │ ├── v1 │ │ ├── testutil │ │ │ ├── const.go │ │ │ ├── mxjob.go │ │ │ ├── pod.go │ │ │ ├── service.go │ │ │ └── util.go │ │ └── unstructured │ │ │ └── informer.go │ │ └── v1beta1 │ │ ├── testutil │ │ ├── const.go │ │ ├── mxjob.go │ │ ├── pod.go │ │ ├── service.go │ │ └── util.go │ │ └── unstructured │ │ └── informer.go ├── controller.v1 │ └── mxnet │ │ ├── controller.go │ │ ├── controller_test.go │ │ ├── informer.go │ │ ├── job.go │ │ ├── job_test.go │ │ ├── mxnet.go │ │ ├── pod.go │ │ ├── pod_test.go │ │ ├── service.go │ │ ├── status.go │ │ ├── util.go │ │ └── util_test.go ├── controller.v1beta1 │ └── mxnet │ │ ├── controller.go │ │ ├── controller_test.go │ │ ├── informer.go │ │ ├── job.go │ │ ├── job_test.go │ │ ├── mxnet.go │ │ ├── pod.go │ │ ├── pod_test.go │ │ ├── service.go │ │ ├── service_test.go │ │ ├── status.go │ │ ├── status_test.go │ │ ├── util.go │ │ └── util_test.go ├── util │ ├── k8sutil │ │ ├── client.go │ │ └── k8sutil.go │ └── util.go └── version │ └── version.go └── prow_config.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries 2 | mxnet-operator.v1beta1 3 | mxnet-operator.v1 4 | 5 | # IDEs 6 | .idea/ 7 | .vscode/ 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.13" 5 | 6 | go_import_path: github.com/kubeflow/mxnet-operator 7 | 8 | install: 9 | # get coveralls.io support 10 | - go get github.com/mattn/goveralls 11 | # Install golangci-lint 12 | - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.23.7 13 | 14 | script: 15 | - hack/verify-codegen.sh 16 | - go build -o mxnet-operator.v1beta1 github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1beta1 17 | - go build -o mxnet-operator.v1 github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1 18 | - golangci-lint run --config=linter_config.yaml ./... 19 | # We customize the build step because by default 20 | # Travis runs go test -v ./... which will include the vendor 21 | # directory. 22 | # With go 1.9 vendor will be automatically excluded. 23 | # For now though we just run all tests in pkg. 24 | # And we can not use ** because goveralls uses filepath.Match 25 | # to match ignore files and it does not support it. 26 | - goveralls -service=travis-ci -v -package ./pkg/... -ignore "pkg/client/*/*.go,pkg/client/*/*/*.go,pkg/client/*/*/*/*.go,pkg/client/*/*/*/*/*.go,pkg/client/*/*/*/*/*/*.go,pkg/client/*/*/*/*/*/*/*.go,pkg/apis/mxnet/*/zz_generated.*.go" 27 | 28 | -------------------------------------------------------------------------------- /ADOPTERS.md: -------------------------------------------------------------------------------- 1 | # Adopters of MXNet Operator 2 | 3 | This page contains a list of organizations who are using MXNet Operator. If you'd like to be included here, please send a pull request which modifies this file. Please keep the list in alphabetical order. 4 | 5 | | Organization | Contact | 6 | | ------------ | ------- | 7 | | [Amazon Web Services](https://aws.amazon.com/) | [Jiaxin Shan](https://github.com/Jeffwan) | 8 | | [Caicloud](https://caicloud.io/) | [Ce Gao](https://github.com/gaocegege) | 9 | | [Huawei](https://www.huawei.com/) | [Lei Su](https://github.com/suleisl2000) | 10 | | [Qihoo 360](https://www.360.cn/) | [Xigang Wang](https://github.com/xigang) | 11 | | [TuSimple](https://www.tusimple.com/) | [Hengliang He](https://github.com/henglianghe) | 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | mxnet-operator uses go modules and supports both v1beta1 and v1. We suggest to use golang 1.13.x for development. 4 | Make sure you enable `GO111MODULE`. 5 | 6 | ### Setup development environment 7 | 8 | ```shell 9 | mkdir -p ${GOPATH}/src/github.com/kubeflow 10 | cd ${GOPATH}/src/github.com/kubeflow 11 | git clone https://github.com/${GITHUB_USER}/mxnet-operator.git 12 | ``` 13 | 14 | ### Download go mods 15 | 16 | Some utility modules like `code-generator` will be used in hack scripts, 17 | it's better to download all dependencies for the first time. 18 | 19 | ```shell 20 | go mod download 21 | ``` 22 | 23 | ### Build the operator locally 24 | 25 | ```shell 26 | go build -o mxnet-operator.v1beta1 github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1beta1 27 | go build -o mxnet-operator.v1 github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1 28 | ``` 29 | 30 | ### Build container image 31 | 32 | ```shell 33 | # It requires you to build binary locally first. 34 | docker build -t ${your_dockerhub_username}/mxnet-operator:v1 . 35 | ``` 36 | 37 | ### Test Binaries locally 38 | 39 | ```shell 40 | ./mxnet-operator.v1beta1 --kubeconfig=$HOME/.kube/config 41 | ``` 42 | 43 | ### Before code check-in 44 | 45 | There're several steps to follow before you submit PR. 46 | 47 | ```shell 48 | # Verify codegen in case you change api but for get to generate new packages. 49 | ./hack/verify-codegen.sh 50 | 51 | # Lint codes 52 | golangci-lint run --config=linter_config.yaml ./... 53 | ``` 54 | 55 | ### Regenerate clients and apis 56 | 57 | If you make changes under `/pkg/apis`, you probably need to regenerate clients and apis. 58 | 59 | ```shell 60 | ./hack/update-codegen.sh 61 | ``` -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.13.8 2 | 3 | RUN mkdir -p /opt/kubeflow 4 | COPY mxnet-operator.v1beta1 /opt/kubeflow 5 | COPY mxnet-operator.v1 /opt/kubeflow 6 | 7 | RUN chmod a+x /opt/kubeflow/mxnet-operator.v1beta1 8 | RUN chmod a+x /opt/kubeflow/mxnet-operator.v1 9 | 10 | CMD ["/opt/kubeflow/mxnet-operator.v1"] 11 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | approvers: 2 | - suleisl2000 3 | - wackxu 4 | - terrytangyuan 5 | - Jeffwan 6 | reviewers: 7 | - gaocegege 8 | - jzp1025 9 | - KingOnTheStar 10 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # MXNet Operator Releases 2 | 3 | ## Release v1.0.0 4 | 5 | * Remove Travis buddy webhook ([#77](https://github.com/kubeflow/mxnet-operator/pull/77), [@terrytangyuan](https://github.com/terrytangyuan)) 6 | * Fix the reconcile flow ([#74](https://github.com/kubeflow/mxnet-operator/pull/74), [@ChanYiLin](https://github.com/ChanYiLin)) 7 | * Remove go.mod suffix when grabbing code-generator version ([#73](https://github.com/kubeflow/mxnet-operator/pull/73), [@terrytangyuan](https://github.com/terrytangyuan)) 8 | * Add Kustomize package deployable on its own ([#71](https://github.com/kubeflow/mxnet-operator/pull/71), [@Jeffwan](https://github.com/Jeffwan) 9 | * Create separate clusterrole for mxnet-operator ([#70](https://github.com/kubeflow/mxnet-operator/pull/70), [@Jeffwan](https://github.com/Jeffwan)) 10 | * Fix Python script name and add links ([#69](https://github.com/kubeflow/mxnet-operator/pull/69), [@terrytangyuan](https://github.com/terrytangyuan)) 11 | * Add mxnet-operator v1 examples ([#68](https://github.com/kubeflow/mxnet-operator/pull/68), [@Jeffwan](https://github.com/Jeffwan)) 12 | * Add initial list of adopters ([#63](https://github.com/kubeflow/mxnet-operator/pull/63), [@terrytangyuan](https://github.com/terrytangyuan)) 13 | * Enhancements on README.md ([#61](https://github.com/kubeflow/mxnet-operator/pull/61), [@terrytangyuan](https://github.com/terrytangyuan)) 14 | * Update Contributing docs for recent go changes ([#58](https://github.com/kubeflow/mxnet-operator/pull/58), [@Jeffwan](https://github.com/Jeffwan)) 15 | * Remove vendor directory ([#57](https://github.com/kubeflow/mxnet-operator/pull/57), [@Jeffwan](https://github.com/Jeffwan)) 16 | * Upgrade Golang version to 1.13.8 and Kubernetes version to 1.15.9 ([#53](https://github.com/kubeflow/mxnet-operator/pull/53), [@Jeffwan](https://github.com/Jeffwan)) 17 | * Deprecate gometalinter and use golangcli-lint instead ([#56](https://github.com/kubeflow/mxnet-operator/pull/56), [@Jeffwan](https://github.com/Jeffwan)) 18 | 19 | ## Release v0.7.0 20 | 21 | * Implementation of mxnet operator API v1 ([#39](https://github.com/kubeflow/mxnet-operator/pull/39), [@wackxu](https://github.com/wackxu)) 22 | * Implement ActiveDeadlineSeconds and BackoffLimit ([#40](https://github.com/kubeflow/mxnet-operator/pull/40), [@wackxu](https://github.com/wackxu)) 23 | * Sync with tf-operator ([#41](https://github.com/kubeflow/mxnet-operator/pull/41), [@wackxu](https://github.com/wackxu)) 24 | * Add wackxu to OWNERS ([#42](https://github.com/kubeflow/mxnet-operator/pull/42), [@wackxu](https://github.com/wackxu)) 25 | * Add uuid to id for leader election ([#43](https://github.com/kubeflow/mxnet-operator/pull/43), [@fisherxu](https://github.com/fisherxu)) 26 | * Skip condition update when succeeded and bump tf-operator to v0.5.3 version ([#44](https://github.com/kubeflow/mxnet-operator/pull/44), [@wackxu](https://github.com/wackxu)) 27 | * Fix bug for check PodPending ([#45](https://github.com/kubeflow/mxnet-operator/pull/45), [@wackxu](https://github.com/wackxu)) 28 | * Fix wrong api version when delete mxjob ([#46](https://github.com/kubeflow/mxnet-operator/pull/46), [@wackxu](https://github.com/wackxu)) 29 | * Renaming labels to consistent format ([#47](https://github.com/kubeflow/mxnet-operator/pull/47), [@wackxu](https://github.com/wackxu)) 30 | * Set annotation automatically when EnableGangScheduling is set to true ([#48](https://github.com/kubeflow/mxnet-operator/pull/48), [@wackxu](https://github.com/wackxu)) 31 | * Add kubeconfig flag ([#49](https://github.com/kubeflow/mxnet-operator/pull/49), [@yeya24](https://github.com/yeya24)) 32 | 33 | ## Release v0.1.0 34 | 35 | Initial release of the MXNet Operator. 36 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | This document defines a high level roadmap for mxnet operator development. 4 | 5 | 6 | ### 2018 7 | 8 | #### Features 9 | 10 | - Better workload scheduling 11 | - Latest Gang scheduling 12 | - [GPU topology aware scheduling](https://github.com/kubernetes-incubator/kube-arbitrator/issues/236) 13 | 14 | - Other training mode if any 15 | - [allreduce](https://github.com/apache/incubator-mxnet/pull/10696) 16 | 17 | - Usability 18 | - Integrate with MXBoard if necessary 19 | 20 | #### Stability/Reliability 21 | 22 | - end-to-end testing 23 | - unit tests 24 | - CI 25 | -------------------------------------------------------------------------------- /cmd/mxnet-operator.v1/app/options/options.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package options 16 | 17 | import ( 18 | "flag" 19 | "time" 20 | 21 | "k8s.io/api/core/v1" 22 | ) 23 | 24 | const DefaultResyncPeriod = 12 * time.Hour 25 | 26 | // ServerOption is the main context object for the controller manager. 27 | type ServerOption struct { 28 | Kubeconfig string 29 | MasterURL string 30 | Threadiness int 31 | PrintVersion bool 32 | JSONLogFormat bool 33 | EnableGangScheduling bool 34 | Namespace string 35 | ResyncPeriod time.Duration 36 | } 37 | 38 | // NewServerOption creates a new CMServer with a default config. 39 | func NewServerOption() *ServerOption { 40 | s := ServerOption{} 41 | return &s 42 | } 43 | 44 | // AddFlags adds flags for a specific CMServer to the specified FlagSet. 45 | func (s *ServerOption) AddFlags(fs *flag.FlagSet) { 46 | fs.StringVar(&s.Kubeconfig, "kubeconfig", "", "The path of kubeconfig file") 47 | 48 | fs.StringVar(&s.MasterURL, "master", "", 49 | `The url of the Kubernetes API server, 50 | will overrides any value in kubeconfig, only required if out-of-cluster.`) 51 | 52 | fs.StringVar(&s.Namespace, "namespace", v1.NamespaceAll, 53 | `The namespace to monitor mxjobs. If unset, it monitors all namespaces cluster-wide. 54 | If set, it only monitors mxjobs in the given namespace.`) 55 | 56 | fs.IntVar(&s.Threadiness, "threadiness", 1, 57 | `How many threads to process the main logic`) 58 | 59 | fs.BoolVar(&s.PrintVersion, "version", false, "Show version and quit") 60 | 61 | fs.BoolVar(&s.JSONLogFormat, "json-log-format", true, 62 | "Set true to use json style log format. Set false to use plaintext style log format") 63 | fs.BoolVar(&s.EnableGangScheduling, "enable-gang-scheduling", false, "Set true to enable gang scheduling by kube-arbitrator.") 64 | 65 | fs.DurationVar(&s.ResyncPeriod, "resyc-period", DefaultResyncPeriod, "Resync interval of the tf-operator") 66 | } 67 | -------------------------------------------------------------------------------- /cmd/mxnet-operator.v1/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | 20 | "github.com/onrik/logrus/filename" 21 | log "github.com/sirupsen/logrus" 22 | 23 | "github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1/app" 24 | "github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1/app/options" 25 | ) 26 | 27 | func init() { 28 | // Add filename as one of the fields of the structured log message. 29 | filenameHook := filename.NewHook() 30 | filenameHook.Field = "filename" 31 | log.AddHook(filenameHook) 32 | } 33 | 34 | func main() { 35 | s := options.NewServerOption() 36 | s.AddFlags(flag.CommandLine) 37 | 38 | flag.Parse() 39 | 40 | if s.JSONLogFormat { 41 | // Output logs in a json format so that it can be parsed by services like Stackdriver. 42 | log.SetFormatter(&log.JSONFormatter{}) 43 | } 44 | 45 | if err := app.Run(s); err != nil { 46 | log.Fatalf("%v\n", err) 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /cmd/mxnet-operator.v1beta1/app/options/options.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package options 16 | 17 | import ( 18 | "flag" 19 | 20 | v1 "k8s.io/api/core/v1" 21 | ) 22 | 23 | // ServerOption is the main context object for the controller manager. 24 | type ServerOption struct { 25 | Kubeconfig string 26 | MasterURL string 27 | Threadiness int 28 | PrintVersion bool 29 | JSONLogFormat bool 30 | EnableGangScheduling bool 31 | Namespace string 32 | } 33 | 34 | // NewServerOption creates a new CMServer with a default config. 35 | func NewServerOption() *ServerOption { 36 | s := ServerOption{} 37 | return &s 38 | } 39 | 40 | // AddFlags adds flags for a specific CMServer to the specified FlagSet. 41 | func (s *ServerOption) AddFlags(fs *flag.FlagSet) { 42 | fs.StringVar(&s.Kubeconfig, "kubeconfig", "", "The path of kubeconfig file") 43 | 44 | fs.StringVar(&s.MasterURL, "master", "", 45 | `The url of the Kubernetes API server, 46 | will overrides any value in kubeconfig, only required if out-of-cluster.`) 47 | 48 | fs.StringVar(&s.Namespace, "namespace", v1.NamespaceAll, 49 | `The namespace to monitor mxjobs. If unset, it monitors all namespaces cluster-wide. 50 | If set, it only monitors mxjobs in the given namespace.`) 51 | 52 | fs.IntVar(&s.Threadiness, "threadiness", 1, 53 | `How many threads to process the main logic`) 54 | 55 | fs.BoolVar(&s.PrintVersion, "version", false, "Show version and quit") 56 | 57 | fs.BoolVar(&s.JSONLogFormat, "json-log-format", true, 58 | "Set true to use json style log format. Set false to use plaintext style log format") 59 | fs.BoolVar(&s.EnableGangScheduling, "enable-gang-scheduling", false, "Set true to enable gang scheduling by kube-arbitrator.") 60 | } 61 | -------------------------------------------------------------------------------- /cmd/mxnet-operator.v1beta1/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | 20 | "github.com/onrik/logrus/filename" 21 | log "github.com/sirupsen/logrus" 22 | 23 | "github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1beta1/app" 24 | "github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1beta1/app/options" 25 | ) 26 | 27 | func init() { 28 | // Add filename as one of the fields of the structured log message. 29 | filenameHook := filename.NewHook() 30 | filenameHook.Field = "filename" 31 | log.AddHook(filenameHook) 32 | } 33 | 34 | func main() { 35 | s := options.NewServerOption() 36 | s.AddFlags(flag.CommandLine) 37 | 38 | flag.Parse() 39 | 40 | if s.JSONLogFormat { 41 | // Output logs in a json format so that it can be parsed by services like Stackdriver. 42 | log.SetFormatter(&log.JSONFormatter{}) 43 | } 44 | 45 | if err := app.Run(s); err != nil { 46 | log.Fatalf("%v\n", err) 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /examples/train/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mxnet/python:gpu 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y git && \ 5 | git clone https://github.com/apache/incubator-mxnet.git -b v1.6.x 6 | 7 | ENTRYPOINT ["python", "/incubator-mxnet/example/image-classification/train_mnist.py"] -------------------------------------------------------------------------------- /examples/train/byteps_dist_gpu_v1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "kubeflow.org/v1" 2 | kind: "MXJob" 3 | metadata: 4 | name: "byteps-mxnet-job" 5 | spec: 6 | jobMode: MXTrain 7 | cleanPodPolicy: Running 8 | successPolicy: AllWorkers 9 | mxReplicaSpecs: 10 | Scheduler: 11 | replicas: 1 12 | restartPolicy: Never 13 | template: 14 | spec: 15 | containers: 16 | - name: mxnet 17 | image: bytepsimage/mxnet 18 | command: ["bpslaunch"] 19 | Server: 20 | replicas: 2 21 | restartPolicy: Never 22 | template: 23 | spec: 24 | containers: 25 | - name: mxnet 26 | image: bytepsimage/mxnet 27 | command: ["bpslaunch"] 28 | Worker: 29 | replicas: 2 30 | restartPolicy: Never 31 | template: 32 | spec: 33 | containers: 34 | - name: mxnet 35 | image: bytepsimage/mxnet 36 | command: ["bpslaunch"] 37 | args: ["python3", "/usr/local/byteps/example/mxnet/train_imagenet_byteps.py", "--benchmark", "1", "--batch-size=32"] 38 | volumeMounts: 39 | - mountPath: /dev/shm 40 | name: dshm 41 | resources: 42 | limits: 43 | nvidia.com/gpu: 8 44 | volumes: 45 | - name: dshm 46 | emptyDir: 47 | medium: Memory 48 | -------------------------------------------------------------------------------- /examples/train/byteps_dist_gpu_v1beta1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "kubeflow.org/v1beta1" 2 | kind: "MXJob" 3 | metadata: 4 | name: "byteps-mxnet-job" 5 | spec: 6 | jobMode: MXTrain 7 | cleanPodPolicy: Running 8 | successPolicy: AllWorkers 9 | mxReplicaSpecs: 10 | Scheduler: 11 | replicas: 1 12 | restartPolicy: Never 13 | template: 14 | spec: 15 | containers: 16 | - name: mxnet 17 | image: bytepsimage/mxnet 18 | command: ["bpslaunch"] 19 | Server: 20 | replicas: 2 21 | restartPolicy: Never 22 | template: 23 | spec: 24 | containers: 25 | - name: mxnet 26 | image: bytepsimage/mxnet 27 | command: ["bpslaunch"] 28 | Worker: 29 | replicas: 2 30 | restartPolicy: Never 31 | template: 32 | spec: 33 | containers: 34 | - name: mxnet 35 | image: bytepsimage/mxnet 36 | command: ["bpslaunch"] 37 | args: ["python3", "/usr/local/byteps/example/mxnet/train_imagenet_byteps.py", "--benchmark", "1", "--batch-size=32"] 38 | volumeMounts: 39 | - mountPath: /dev/shm 40 | name: dshm 41 | resources: 42 | limits: 43 | nvidia.com/gpu: 8 44 | volumes: 45 | - name: dshm 46 | emptyDir: 47 | medium: Memory 48 | -------------------------------------------------------------------------------- /examples/train/mx_job_dist_gpu_v1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "kubeflow.org/v1" 2 | kind: "MXJob" 3 | metadata: 4 | name: "mxnet-job" 5 | spec: 6 | jobMode: MXTrain 7 | mxReplicaSpecs: 8 | Scheduler: 9 | replicas: 1 10 | restartPolicy: Never 11 | template: 12 | spec: 13 | containers: 14 | - name: mxnet 15 | image: mxjob/mxnet:gpu 16 | Server: 17 | replicas: 1 18 | restartPolicy: Never 19 | template: 20 | spec: 21 | containers: 22 | - name: mxnet 23 | image: mxjob/mxnet:gpu 24 | Worker: 25 | replicas: 1 26 | restartPolicy: Never 27 | template: 28 | spec: 29 | containers: 30 | - name: mxnet 31 | image: mxjob/mxnet:gpu 32 | command: ["python"] 33 | args: ["/incubator-mxnet/example/image-classification/train_mnist.py","--num-epochs","10","--num-layers","2","--kv-store","dist_device_sync","--gpus","0"] 34 | resources: 35 | limits: 36 | nvidia.com/gpu: 1 37 | -------------------------------------------------------------------------------- /examples/train/mx_job_dist_gpu_v1beta1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "kubeflow.org/v1beta1" 2 | kind: "MXJob" 3 | metadata: 4 | name: "mxnet-job" 5 | spec: 6 | jobMode: MXTrain 7 | mxReplicaSpecs: 8 | Scheduler: 9 | replicas: 1 10 | restartPolicy: Never 11 | template: 12 | spec: 13 | containers: 14 | - name: mxnet 15 | image: mxjob/mxnet:gpu 16 | Server: 17 | replicas: 1 18 | restartPolicy: Never 19 | template: 20 | spec: 21 | containers: 22 | - name: mxnet 23 | image: mxjob/mxnet:gpu 24 | Worker: 25 | replicas: 1 26 | restartPolicy: Never 27 | template: 28 | spec: 29 | containers: 30 | - name: mxnet 31 | image: mxjob/mxnet:gpu 32 | command: ["python"] 33 | args: ["/incubator-mxnet/example/image-classification/train_mnist.py","--num-epochs","10","--num-layers","2","--kv-store","dist_device_sync","--gpus","0"] 34 | resources: 35 | limits: 36 | nvidia.com/gpu: 1 37 | -------------------------------------------------------------------------------- /examples/tune/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvidia/cuda:10.0-cudnn7-devel-ubuntu16.04 2 | 3 | # Download usefull tools and mxnet, tvm 4 | WORKDIR /home/scripts 5 | RUN apt-get update && apt-get install -y git vim cmake wget sed && \ 6 | git clone --recursive https://github.com/dmlc/tvm && \ 7 | git clone --recursive https://github.com/apache/incubator-mxnet mxnet 8 | 9 | # Download necessary dependence 10 | RUN apt-get update && \ 11 | apt-get install -y python3 python3-dev python3-setuptools gcc libtinfo-dev zlib1g-dev && \ 12 | apt-get install -y python3-pip && \ 13 | apt-get install -y build-essential 14 | 15 | # mxnet dependence 16 | RUN apt-get install -y libopenblas-dev liblapack-dev && \ 17 | apt-get install -y libopencv-dev 18 | 19 | # tvm dependence 20 | RUN pip3 install --user numpy decorator && \ 21 | pip3 install --user tornado psutil xgboost 22 | 23 | # get llvm 4.0.0 for tvm 24 | RUN wget http://releases.llvm.org/4.0.0/clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz && \ 25 | tar -xf clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz && \ 26 | mv clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-16.04 llvm && \ 27 | rm clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz 28 | 29 | # Compile mxnet 30 | RUN cd mxnet && \ 31 | make clean && \ 32 | make -j $(nproc) USE_OPENCV=1 USE_BLAS=openblas USE_DIST_KVSTORE=1 USE_CUDA=1 USE_CUDA_PATH=/usr/local/cuda USE_CUDNN=1 33 | 34 | # Install mxnet 35 | RUN cd mxnet/python && \ 36 | pip3 install -e . 37 | 38 | # Compile tvm 39 | RUN cd tvm && \ 40 | mkdir build && \ 41 | cp cmake/config.cmake build && \ 42 | cd build && \ 43 | sed -i 's/set(USE_CUDA OFF)/set(USE_CUDA ON)/g' config.cmake && \ 44 | sed -i 's/set(USE_CUDNN OFF)/set(USE_CUDNN ON)/g' config.cmake && \ 45 | sed -i 's/set(USE_CUBLAS OFF)/set(USE_CUBLAS ON)/g' config.cmake && \ 46 | sed -i 's/set(USE_LLVM OFF)/set(USE_LLVM ..\/..\/llvm\/bin\/llvm-config)/g' config.cmake && \ 47 | cmake .. && \ 48 | make -j $(nproc) 49 | 50 | # Install tvm 51 | RUN cd tvm && \ 52 | cd python; python3 setup.py install --user; cd .. && \ 53 | cd topi/python; python3 setup.py install --user; cd ../.. && \ 54 | cd nnvm/python; python3 setup.py install --user; cd ../.. 55 | 56 | # COPY custom code to container 57 | COPY start-job.py . 58 | COPY auto-tuning.py . 59 | 60 | # Change working path 61 | WORKDIR /home/log 62 | -------------------------------------------------------------------------------- /examples/tune/README.md: -------------------------------------------------------------------------------- 1 | [mx_job_tune_gpu_v1beta1.yaml](mx_job_tune_gpu_v1beta1.yaml) and [mx_job_tune_gpu_v1.yaml](mx_job_tune_gpu_v1.yaml) will pull sample image and run it. 2 | 3 | In the sample image, [Apache TVM](https://tvm.apache.org/) and [Apache MXNet](https://mxnet.apache.org/) are pre-installed, you can check out the [Dockerfile](Dockerfile) to get some information. 4 | 5 | There two customized scripts in the sample image, [start-job.py](start-job.py) and [auto-tuning.py](auto-tuning.py). 6 | * [start-job.py](start-job.py) is a script tell you how to read the environment variable MX_CONFIG. 7 | * [auto-tuning.py](auto-tuning.py) is a sample script of autotvm, which will tune a `resnet-18` network. 8 | -------------------------------------------------------------------------------- /examples/tune/mx_job_tune_gpu_v1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "kubeflow.org/v1" 2 | kind: "MXJob" 3 | metadata: 4 | name: "auto-tuning-job" 5 | spec: 6 | jobMode: MXTune 7 | mxReplicaSpecs: 8 | TunerTracker: 9 | replicas: 1 10 | restartPolicy: Never 11 | template: 12 | spec: 13 | containers: 14 | - name: mxnet 15 | image: mxjob/auto-tuning:gpu 16 | command: ["python3"] 17 | args: ["/home/scripts/start-job.py"] 18 | TunerServer: 19 | label: 2080ti 20 | replicas: 1 21 | restartPolicy: Never 22 | template: 23 | spec: 24 | containers: 25 | - name: mxnet 26 | image: mxjob/auto-tuning:gpu 27 | command: ["python3"] 28 | args: ["/home/scripts/start-job.py"] 29 | resources: 30 | limits: 31 | nvidia.com/gpu: 1 32 | Tuner: 33 | replicas: 1 34 | restartPolicy: Never 35 | template: 36 | spec: 37 | containers: 38 | - name: mxnet 39 | image: mxjob/auto-tuning:gpu 40 | command: ["python3"] 41 | args: ["/home/scripts/start-job.py"] 42 | -------------------------------------------------------------------------------- /examples/tune/mx_job_tune_gpu_v1beta1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "kubeflow.org/v1beta1" 2 | kind: "MXJob" 3 | metadata: 4 | name: "auto-tuning-job" 5 | spec: 6 | jobMode: MXTune 7 | mxReplicaSpecs: 8 | TunerTracker: 9 | replicas: 1 10 | restartPolicy: Never 11 | template: 12 | spec: 13 | containers: 14 | - name: mxnet 15 | image: mxjob/auto-tuning:gpu 16 | command: ["python3"] 17 | args: ["/home/scripts/start-job.py"] 18 | TunerServer: 19 | label: 2080ti 20 | replicas: 1 21 | restartPolicy: Never 22 | template: 23 | spec: 24 | containers: 25 | - name: mxnet 26 | image: mxjob/auto-tuning:gpu 27 | command: ["python3"] 28 | args: ["/home/scripts/start-job.py"] 29 | resources: 30 | limits: 31 | nvidia.com/gpu: 1 32 | Tuner: 33 | replicas: 1 34 | restartPolicy: Never 35 | template: 36 | spec: 37 | containers: 38 | - name: mxnet 39 | image: mxjob/auto-tuning:gpu 40 | command: ["python3"] 41 | args: ["/home/scripts/start-job.py"] 42 | -------------------------------------------------------------------------------- /examples/tune/start-job.py: -------------------------------------------------------------------------------- 1 | # Befor running this script, make sure tvm is install in your cluster 2 | 3 | import os 4 | import time 5 | import json 6 | 7 | if __name__ == '__main__': 8 | mx_config = json.loads(os.environ.get('MX_CONFIG') or '{}') 9 | cluster_config = mx_config.get('cluster', {}) 10 | labels_config = mx_config.get('labels', {}) 11 | task_config = mx_config.get('task', {}) 12 | task_type = task_config.get('type') 13 | task_index = task_config.get('index') 14 | 15 | if task_type == "": 16 | print("No task_type, Error") 17 | elif task_type == "tunertracker": 18 | addr = cluster_config["tunertracker"][0] 19 | command = "python3 -m tvm.exec.rpc_tracker --port={0}".format(addr.get('port')) 20 | print("DO: " + command) 21 | os.system(command) 22 | elif task_type == "tunerserver": 23 | time.sleep(5) 24 | addr = cluster_config["tunertracker"][0] 25 | label = labels_config["tunerserver"] 26 | command = "python3 -m tvm.exec.rpc_server --tracker={0}:{1} --key={2}".format(addr.get('url'), addr.get('port'), label) 27 | print("DO: " + command) 28 | os.system(command) 29 | elif task_type == "tuner": 30 | time.sleep(5) 31 | addr = cluster_config["tunertracker"][0] 32 | label = labels_config["tunerserver"] 33 | command = "python3 /home/scripts/auto-tuning.py --tracker {0} --tracker_port {1} --server_key {2}".format(addr.get('url'), addr.get('port'), label) 34 | print("DO: " + command) 35 | os.system(command) 36 | else: 37 | print("Unknow task type! Error") 38 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubeflow/mxnet-operator 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/golang/protobuf v1.3.2 7 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect 8 | github.com/grpc-ecosystem/grpc-gateway v1.5.0 // indirect 9 | github.com/kubeflow/common v0.3.1 10 | github.com/kubeflow/tf-operator v0.5.3 11 | github.com/kubernetes-sigs/kube-batch v0.0.0-20200414051246-2e934d1c8860 12 | github.com/onrik/logrus v0.0.0-20180801161715-ca0a758702be 13 | github.com/sirupsen/logrus v1.4.2 14 | github.com/soheilhy/cmux v0.1.4 // indirect 15 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect 16 | go.uber.org/multierr v1.1.0 // indirect 17 | go.uber.org/zap v1.10.0 // indirect 18 | gopkg.in/square/go-jose.v2 v2.3.1 // indirect 19 | k8s.io/api v0.16.9 20 | k8s.io/apiextensions-apiserver v0.0.0 21 | k8s.io/apimachinery v0.16.9 22 | k8s.io/client-go v10.0.0+incompatible 23 | k8s.io/kubernetes v1.16.9 24 | k8s.io/utils v0.0.0-20191114184206-e782cd3c129f // indirect 25 | volcano.sh/volcano v0.4.0 26 | ) 27 | 28 | replace ( 29 | k8s.io/api => k8s.io/api v0.16.9 30 | k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.16.9 31 | k8s.io/apimachinery => k8s.io/apimachinery v0.16.10-beta.0 32 | k8s.io/apiserver => k8s.io/apiserver v0.16.9 33 | k8s.io/cli-runtime => k8s.io/cli-runtime v0.16.9 34 | k8s.io/client-go => k8s.io/client-go v0.16.9 35 | k8s.io/cloud-provider => k8s.io/cloud-provider v0.16.9 36 | k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.16.9 37 | k8s.io/code-generator => k8s.io/code-generator v0.16.10-beta.0 38 | k8s.io/component-base => k8s.io/component-base v0.16.9 39 | k8s.io/cri-api => k8s.io/cri-api v0.16.10-beta.0 40 | k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.16.9 41 | k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.16.9 42 | k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.16.9 43 | k8s.io/kube-proxy => k8s.io/kube-proxy v0.16.9 44 | k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.16.9 45 | k8s.io/kubectl => k8s.io/kubectl v0.16.9 46 | k8s.io/kubelet => k8s.io/kubelet v0.16.9 47 | k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.16.9 48 | k8s.io/metrics => k8s.io/metrics v0.16.9 49 | k8s.io/node-api => k8s.io/node-api v0.16.9 50 | k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.16.9 51 | k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.16.9 52 | k8s.io/sample-controller => k8s.io/sample-controller v0.16.9 53 | ) 54 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // Copyright YEAR The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | -------------------------------------------------------------------------------- /hack/scripts/cleanup_clusters.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Helper script to remove all resources in a kubernetes cluster created by the CRD. 4 | 5 | kubectl delete service --selector='kubeflow.org=' 6 | kubectl delete jobs --selector='kubeflow.org=' 7 | kubectl delete pods --selector='kubeflow.org=' 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /hack/update-codegen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This shell is used to auto generate some useful tools for k8s, such as lister, 18 | # informer, deepcopy, defaulter and so on. 19 | 20 | set -o errexit 21 | set -o nounset 22 | set -o pipefail 23 | 24 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 25 | ROOT_PKG=github.com/kubeflow/mxnet-operator 26 | 27 | # Grab code-generator version from go.sum 28 | CODEGEN_VERSION=$(grep 'k8s.io/code-generator' go.sum | awk '{print $2}' | sed 's/\/go.mod//g' | head -1) 29 | CODEGEN_PKG=$(echo `go env GOPATH`"/pkg/mod/k8s.io/code-generator@${CODEGEN_VERSION}") 30 | 31 | if [[ ! -d ${CODEGEN_PKG} ]]; then 32 | echo "${CODEGEN_PKG} is missing. Running 'go mod download'." 33 | go mod download 34 | fi 35 | 36 | echo ">> Using ${CODEGEN_PKG}" 37 | 38 | # code-generator does work with go.mod but makes assumptions about 39 | # the project living in `$GOPATH/src`. To work around this and support 40 | # any location; create a temporary directory, use this as an output 41 | # base, and copy everything back once generated. 42 | TEMP_DIR=$(mktemp -d) 43 | cleanup() { 44 | echo ">> Removing ${TEMP_DIR}" 45 | rm -rf ${TEMP_DIR} 46 | } 47 | trap "cleanup" EXIT SIGINT 48 | 49 | echo ">> Temporary output directory ${TEMP_DIR}" 50 | 51 | # Ensure we can execute. 52 | chmod +x ${CODEGEN_PKG}/generate-groups.sh 53 | 54 | # generate the code with: 55 | # --output-base because this script should also be able to run inside the vendor dir of 56 | # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir 57 | # instead of the $GOPATH directly. For normal projects this can be dropped. 58 | cd ${SCRIPT_ROOT} 59 | ${CODEGEN_PKG}/generate-groups.sh "defaulter,deepcopy,client,informer,lister" \ 60 | github.com/kubeflow/mxnet-operator/pkg/client github.com/kubeflow/mxnet-operator/pkg/apis \ 61 | mxnet:v1beta1,v1 \ 62 | --output-base "${TEMP_DIR}" \ 63 | --go-header-file hack/boilerplate/boilerplate.go.txt 64 | 65 | # Notice: The code in code-generator does not generate defaulter by default. 66 | # We need to build binary from vendor cmd folder. 67 | echo "Building defaulter-gen" 68 | go build -o defaulter-gen ${CODEGEN_PKG}/cmd/defaulter-gen 69 | 70 | echo "Generating defaulters for v1beta1" 71 | ./defaulter-gen --input-dirs github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1 \ 72 | -O zz_generated.defaults \ 73 | --go-header-file hack/boilerplate/boilerplate.go.txt \ 74 | --output-package github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1 75 | 76 | echo "Generating defaulters for v1" 77 | ./defaulter-gen --input-dirs github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1 \ 78 | -O zz_generated.defaults \ 79 | --go-header-file hack/boilerplate/boilerplate.go.txt \ 80 | --output-package github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1 81 | 82 | # Copy everything back. 83 | cp -a "${TEMP_DIR}/${ROOT_PKG}/." "${SCRIPT_ROOT}/" 84 | # Clean up binaries we build for update codegen 85 | rm ./defaulter-gen 86 | -------------------------------------------------------------------------------- /hack/verify-codegen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 22 | 23 | DIFFROOT="${SCRIPT_ROOT}/pkg" 24 | TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg" 25 | _tmp="${SCRIPT_ROOT}/_tmp" 26 | 27 | cleanup() { 28 | rm -rf "${_tmp}" 29 | } 30 | trap "cleanup" EXIT SIGINT 31 | 32 | cleanup 33 | 34 | mkdir -p "${TMP_DIFFROOT}" 35 | cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" 36 | 37 | "${SCRIPT_ROOT}/hack/update-codegen.sh" 38 | echo "diffing ${DIFFROOT} against freshly generated codegen" 39 | ret=0 40 | diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? 41 | cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}" 42 | if [[ $ret -eq 0 ]] 43 | then 44 | echo "${DIFFROOT} up to date." 45 | else 46 | echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh" 47 | exit 1 48 | fi 49 | -------------------------------------------------------------------------------- /linter_config.yaml: -------------------------------------------------------------------------------- 1 | # This file contains golangci-lint configurations 2 | 3 | run: 4 | # default concurrency is a available CPU number 5 | concurrency: 4 6 | 7 | # timeout for analysis, e.g. 30s, 5m, default is 1m 8 | timeout: 300s 9 | 10 | # exit code when at least one issue was found, default is 1 11 | issues-exit-code: 1 12 | 13 | # include test files or not, default is true 14 | tests: true 15 | 16 | # which dirs to skip: issues from them won't be reported; 17 | # skip-dirs: 18 | # - pkg/client 19 | # - pkg/apis/mxnet/v1beta1/zz_generated.deepcopy.go 20 | # - pkg/apis/mxnet/v1beta1/zz_generated.defaults.go 21 | 22 | # default is true. Enables skipping of directories: 23 | # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ 24 | skip-dirs-use-default: true 25 | 26 | linters: 27 | # please, do not use `enable-all`: it's deprecated and will be removed soon. 28 | # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint 29 | disable-all: true 30 | enable: 31 | - bodyclose 32 | - deadcode 33 | - errcheck 34 | - misspell 35 | - lll 36 | - typecheck 37 | - unconvert 38 | - unused 39 | - varcheck 40 | - govet 41 | - staticcheck 42 | linters-settings: 43 | lll: 44 | # max line length, lines longer will be reported. Default is 120. 45 | line-length: 240 46 | 47 | # 48 | # "redundant return statement", 49 | # "comment or be unexported", 50 | # "comment on exported", 51 | -------------------------------------------------------------------------------- /manifests/base/cluster-role-binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: mxnet-operator 5 | labels: 6 | app: mxnet-operator 7 | roleRef: 8 | apiGroup: rbac.authorization.k8s.io 9 | kind: ClusterRole 10 | name: mxnet-operator 11 | subjects: 12 | - kind: ServiceAccount 13 | name: mxnet-operator 14 | namespace: default 15 | -------------------------------------------------------------------------------- /manifests/base/cluster-role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRole 3 | metadata: 4 | name: mxnet-operator 5 | labels: 6 | app: mxnet-operator 7 | rules: 8 | - apiGroups: 9 | - kubeflow.org 10 | resources: 11 | - mxjobs 12 | - mxjobs/status 13 | verbs: 14 | - '*' 15 | - apiGroups: 16 | - apiextensions.k8s.io 17 | resources: 18 | - customresourcedefinitions 19 | verbs: 20 | - '*' 21 | - apiGroups: 22 | - storage.k8s.io 23 | resources: 24 | - storageclasses 25 | verbs: 26 | - '*' 27 | - apiGroups: 28 | - batch 29 | resources: 30 | - jobs 31 | verbs: 32 | - '*' 33 | - apiGroups: 34 | - "" 35 | resources: 36 | - configmaps 37 | - pods 38 | - services 39 | - endpoints 40 | - persistentvolumeclaims 41 | - events 42 | verbs: 43 | - '*' 44 | - apiGroups: 45 | - apps 46 | - extensions 47 | resources: 48 | - deployments 49 | verbs: 50 | - '*' 51 | -------------------------------------------------------------------------------- /manifests/base/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: mxnet-operator 5 | labels: 6 | app: mxnet-operator 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: mxnet-operator 12 | template: 13 | metadata: 14 | labels: 15 | app: mxnet-operator 16 | annotations: 17 | sidecar.istio.io/inject: "false" 18 | spec: 19 | serviceAccountName: mxnet-operator 20 | containers: 21 | - name: mxnet-operator 22 | image: mxjob/mxnet-operator:v1beta1 23 | imagePullPolicy: Always 24 | env: 25 | - name: MY_POD_NAMESPACE 26 | valueFrom: 27 | fieldRef: 28 | fieldPath: metadata.namespace 29 | - name: MY_POD_NAME 30 | valueFrom: 31 | fieldRef: 32 | fieldPath: metadata.name 33 | -------------------------------------------------------------------------------- /manifests/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - service-account.yaml 6 | - cluster-role.yaml 7 | - cluster-role-binding.yaml 8 | - deployment.yaml 9 | - user-cluster-roles.yaml 10 | 11 | commonLabels: 12 | app: mxnet-operator 13 | app.kubernetes.io/component: mxnet 14 | app.kubernetes.io/name: mxnet-operator 15 | kustomize.component: mxnet-operator 16 | 17 | images: 18 | - name: kubeflow/mxnet-operator 19 | newTag: v1.1.0 20 | -------------------------------------------------------------------------------- /manifests/base/podgroup.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: podgroups.scheduling.incubator.k8s.io 5 | spec: 6 | group: scheduling.incubator.k8s.io 7 | names: 8 | kind: PodGroup 9 | plural: podgroups 10 | scope: Namespaced 11 | validation: 12 | openAPIV3Schema: 13 | properties: 14 | apiVersion: 15 | type: string 16 | kind: 17 | type: string 18 | metadata: 19 | type: object 20 | spec: 21 | properties: 22 | minMember: 23 | format: int32 24 | type: integer 25 | type: object 26 | status: 27 | properties: 28 | succeeded: 29 | format: int32 30 | type: integer 31 | failed: 32 | format: int32 33 | type: integer 34 | running: 35 | format: int32 36 | type: integer 37 | type: object 38 | type: object 39 | version: v1alpha1 40 | -------------------------------------------------------------------------------- /manifests/base/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: mxnet-operator 5 | labels: 6 | app: mxnet-operator -------------------------------------------------------------------------------- /manifests/base/user-cluster-roles.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kubeflow-mxjobs-admin 5 | labels: 6 | rbac.authorization.kubeflow.org/aggregate-to-kubeflow-admin: "true" 7 | aggregationRule: 8 | clusterRoleSelectors: 9 | - matchLabels: 10 | rbac.authorization.kubeflow.org/aggregate-to-kubeflow-mxjobs-admin: "true" 11 | rules: [] 12 | 13 | --- 14 | 15 | apiVersion: rbac.authorization.k8s.io/v1 16 | kind: ClusterRole 17 | metadata: 18 | name: kubeflow-mxjobs-edit 19 | labels: 20 | rbac.authorization.kubeflow.org/aggregate-to-kubeflow-edit: "true" 21 | rbac.authorization.kubeflow.org/aggregate-to-kubeflow-mxjobs-admin: "true" 22 | rules: 23 | - apiGroups: 24 | - kubeflow.org 25 | resources: 26 | - mxjobs 27 | - mxjobs/status 28 | verbs: 29 | - get 30 | - list 31 | - watch 32 | - create 33 | - delete 34 | - deletecollection 35 | - patch 36 | - update 37 | 38 | --- 39 | 40 | apiVersion: rbac.authorization.k8s.io/v1 41 | kind: ClusterRole 42 | metadata: 43 | name: kubeflow-mxjobs-view 44 | labels: 45 | rbac.authorization.kubeflow.org/aggregate-to-kubeflow-view: "true" 46 | rules: 47 | - apiGroups: 48 | - kubeflow.org 49 | resources: 50 | - mxjobs 51 | - mxjobs/status 52 | verbs: 53 | - get 54 | - list 55 | - watch -------------------------------------------------------------------------------- /manifests/overlays/kubeflow/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ../v1 6 | 7 | namespace: kubeflow 8 | 9 | commonLabels: 10 | app: mxnet-operator 11 | app.kubernetes.io/component: mxnet 12 | app.kubernetes.io/name: mxnet-operator 13 | kustomize.component: mxnet-operator 14 | -------------------------------------------------------------------------------- /manifests/overlays/v1/crd-v1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: mxjobs.kubeflow.org 5 | spec: 6 | group: kubeflow.org 7 | version: v1 8 | scope: Namespaced 9 | names: 10 | kind: MXJob 11 | singular: mxjob 12 | plural: mxjobs 13 | subresources: 14 | status: {} 15 | validation: 16 | openAPIV3Schema: 17 | properties: 18 | spec: 19 | properties: 20 | mxReplicaSpecs: 21 | properties: 22 | # The validation works when the configuration contains 23 | # `Worker`, `Server`, `Scheduler`, 24 | # `TunerTracker`, `TunerServer`, `Tuner`, 25 | # Otherwise it will not be validated. 26 | Scheduler: 27 | properties: 28 | replicas: 29 | type: integer 30 | minimum: 1 31 | maximum: 1 32 | Worker: 33 | properties: 34 | replicas: 35 | type: integer 36 | minimum: 1 37 | Server: 38 | properties: 39 | replicas: 40 | type: integer 41 | minimum: 1 42 | TunerTracker: 43 | properties: 44 | replicas: 45 | type: integer 46 | minimum: 1 47 | maximum: 1 48 | TunerServer: 49 | properties: 50 | replicas: 51 | type: integer 52 | minimum: 1 53 | Tuner: 54 | properties: 55 | replicas: 56 | type: integer 57 | minimum: 1 58 | maximum: 1 59 | -------------------------------------------------------------------------------- /manifests/overlays/v1/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: mxnet-operator 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: mxnet-operator 10 | image: kubeflow/mxnet-operator:v1.1.0 11 | command: 12 | - /opt/kubeflow/mxnet-operator.v1 13 | 14 | -------------------------------------------------------------------------------- /manifests/overlays/v1/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | bases: 5 | - ../../base 6 | 7 | commonLabels: 8 | app: mxnet-operator 9 | app.kubernetes.io/component: mxnet 10 | app.kubernetes.io/name: mxnet-operator 11 | kustomize.component: mxnet-operator 12 | 13 | resources: 14 | - crd-v1.yaml 15 | 16 | patchesStrategicMerge: 17 | - deployment.yaml 18 | -------------------------------------------------------------------------------- /manifests/overlays/v1beta1/crd-v1beta1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: mxjobs.kubeflow.org 5 | spec: 6 | group: kubeflow.org 7 | version: v1beta1 8 | scope: Namespaced 9 | names: 10 | kind: MXJob 11 | singular: mxjob 12 | plural: mxjobs 13 | validation: 14 | openAPIV3Schema: 15 | properties: 16 | spec: 17 | properties: 18 | mxReplicaSpecs: 19 | properties: 20 | # The validation works when the configuration contains 21 | # `Worker`, `Server`, `Scheduler`, 22 | # `TunerTracker`, `TunerServer`, `Tuner`, 23 | # Otherwise it will not be validated. 24 | Scheduler: 25 | properties: 26 | replicas: 27 | type: integer 28 | minimum: 1 29 | maximum: 1 30 | Worker: 31 | properties: 32 | replicas: 33 | type: integer 34 | minimum: 1 35 | Server: 36 | properties: 37 | replicas: 38 | type: integer 39 | minimum: 1 40 | TunerTracker: 41 | properties: 42 | replicas: 43 | type: integer 44 | minimum: 1 45 | maximum: 1 46 | TunerServer: 47 | properties: 48 | replicas: 49 | type: integer 50 | minimum: 1 51 | Tuner: 52 | properties: 53 | replicas: 54 | type: integer 55 | minimum: 1 56 | maximum: 1 57 | -------------------------------------------------------------------------------- /manifests/overlays/v1beta1/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | bases: 5 | - ../../base 6 | resources: 7 | - crd-v1beta1.yaml 8 | 9 | commonLabels: 10 | app: mxnet-operator 11 | app.kubernetes.io/component: mxnet 12 | app.kubernetes.io/name: mxnet-operator 13 | kustomize.component: mxnet-operator 14 | 15 | images: 16 | - name: mxjob/mxnet-operator 17 | newTag: v1beta1 18 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1 16 | 17 | import commonv1 "github.com/kubeflow/common/pkg/apis/common/v1" 18 | 19 | const ( 20 | // EnvKubeflowNamespace is ENV for kubeflow namespace specified by user. 21 | EnvKubeflowNamespace = "KUBEFLOW_NAMESPACE" 22 | 23 | // DefaultPortName is name of the port used to communicate between scheduler and 24 | // servers & workers. 25 | DefaultPortName = "mxjob-port" 26 | // DefaultContainerName is the name of the MXJob container. 27 | DefaultContainerName = "mxnet" 28 | // DefaultPort is default value of the port. 29 | DefaultPort = 9091 30 | // DefaultRestartPolicy is default RestartPolicy for MXReplicaSpec. 31 | DefaultRestartPolicy = commonv1.RestartPolicyNever 32 | ) 33 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/defaults.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1 16 | 17 | import ( 18 | commonv1 "github.com/kubeflow/common/pkg/apis/common/v1" 19 | "strings" 20 | 21 | "k8s.io/api/core/v1" 22 | "k8s.io/apimachinery/pkg/runtime" 23 | ) 24 | 25 | // Int32 is a helper routine that allocates a new int32 value 26 | // to store v and returns a pointer to it. 27 | func Int32(v int32) *int32 { 28 | return &v 29 | } 30 | 31 | func addDefaultingFuncs(scheme *runtime.Scheme) error { 32 | return RegisterDefaults(scheme) 33 | } 34 | 35 | // setDefaultPort sets the default ports for mxnet container. 36 | func setDefaultPort(spec *v1.PodSpec) { 37 | index := 0 38 | for i, container := range spec.Containers { 39 | if container.Name == DefaultContainerName { 40 | index = i 41 | break 42 | } 43 | } 44 | 45 | hasMXJobPort := false 46 | for _, port := range spec.Containers[index].Ports { 47 | if port.Name == DefaultPortName { 48 | hasMXJobPort = true 49 | break 50 | } 51 | } 52 | if !hasMXJobPort { 53 | spec.Containers[index].Ports = append(spec.Containers[index].Ports, v1.ContainerPort{ 54 | Name: DefaultPortName, 55 | ContainerPort: DefaultPort, 56 | }) 57 | } 58 | } 59 | 60 | func setDefaultReplicas(spec *commonv1.ReplicaSpec) { 61 | if spec.Replicas == nil { 62 | spec.Replicas = Int32(1) 63 | } 64 | if spec.RestartPolicy == "" { 65 | spec.RestartPolicy = DefaultRestartPolicy 66 | } 67 | } 68 | 69 | // setTypeNamesToCamelCase sets the name of all replica types from any case to correct case. 70 | func setTypeNamesToCamelCase(mxJob *MXJob) { 71 | setTypeNameToCamelCase(mxJob, MXReplicaTypeScheduler) 72 | setTypeNameToCamelCase(mxJob, MXReplicaTypeServer) 73 | setTypeNameToCamelCase(mxJob, MXReplicaTypeWorker) 74 | } 75 | 76 | // setTypeNameToCamelCase sets the name of the replica type from any case to correct case. 77 | // E.g. from server to Server; from WORKER to Worker. 78 | func setTypeNameToCamelCase(mxJob *MXJob, typ commonv1.ReplicaType) { 79 | for t := range mxJob.Spec.MXReplicaSpecs { 80 | if strings.EqualFold(string(t), string(typ)) && t != typ { 81 | spec := mxJob.Spec.MXReplicaSpecs[t] 82 | delete(mxJob.Spec.MXReplicaSpecs, t) 83 | mxJob.Spec.MXReplicaSpecs[typ] = spec 84 | return 85 | } 86 | } 87 | } 88 | 89 | // SetDefaults_MXJob sets any unspecified values to defaults. 90 | func SetDefaults_MXJob(mxjob *MXJob) { 91 | // Set default cleanpod policy to All. 92 | if mxjob.Spec.RunPolicy.CleanPodPolicy == nil { 93 | all := commonv1.CleanPodPolicyAll 94 | mxjob.Spec.RunPolicy.CleanPodPolicy = &all 95 | } 96 | 97 | // Update the key of MXReplicaSpecs to camel case. 98 | setTypeNamesToCamelCase(mxjob) 99 | 100 | for _, spec := range mxjob.Spec.MXReplicaSpecs { 101 | // Set default replicas to 1. 102 | setDefaultReplicas(spec) 103 | // Set default port to mxnet container. 104 | setDefaultPort(&spec.Template.Spec) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +k8s:deepcopy-gen=package,register 16 | // +k8s:defaulter-gen=TypeMeta 17 | // +k8s:openapi-gen=true 18 | 19 | // Package v1 is the v1 version of the API. 20 | // +groupName=kubeflow.org 21 | package v1 22 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/register.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1 16 | 17 | import ( 18 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 19 | "k8s.io/apimachinery/pkg/runtime" 20 | "k8s.io/apimachinery/pkg/runtime/schema" 21 | ) 22 | 23 | var ( 24 | // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. 25 | // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. 26 | SchemeBuilder runtime.SchemeBuilder 27 | localSchemeBuilder = &SchemeBuilder 28 | AddToScheme = localSchemeBuilder.AddToScheme 29 | ) 30 | 31 | const ( 32 | // GroupName is the group name use in this package. 33 | GroupName = "kubeflow.org" 34 | // Kind is the kind name. 35 | Kind = "MXJob" 36 | // GroupVersion is the version. 37 | GroupVersion = "v1" 38 | // Plural is the Plural for MXJob. 39 | Plural = "mxjobs" 40 | // Singular is the singular for MXJob. 41 | Singular = "mxjob" 42 | // MXCRD is the CRD name for MXJob. 43 | MXCRD = "mxjobs.kubeflow.org" 44 | ) 45 | 46 | var ( 47 | // SchemeGroupVersion is the group version used to register these objects. 48 | SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion} 49 | // SchemeGroupVersionKind is the GroupVersionKind of the resource. 50 | SchemeGroupVersionKind = SchemeGroupVersion.WithKind(Kind) 51 | ) 52 | 53 | func init() { 54 | // We only register manually written functions here. The registration of the 55 | // generated functions takes place in the generated files. The separation 56 | // makes the code compile even when the generated files are missing. 57 | localSchemeBuilder.Register(addKnownTypes) 58 | localSchemeBuilder.Register(addDefaultingFuncs) 59 | } 60 | 61 | // Resource takes an unqualified resource and returns a Group-qualified GroupResource. 62 | func Resource(resource string) schema.GroupResource { 63 | return SchemeGroupVersion.WithResource(resource).GroupResource() 64 | } 65 | 66 | // addKnownTypes adds the set of types defined in this package to the supplied scheme. 67 | func addKnownTypes(scheme *runtime.Scheme) error { 68 | scheme.AddKnownTypes(SchemeGroupVersion, 69 | &MXJob{}, 70 | &MXJobList{}, 71 | ) 72 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1 16 | 17 | import ( 18 | common "github.com/kubeflow/common/pkg/apis/common/v1" 19 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | ) 21 | 22 | // +genclient 23 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 24 | // +resource:path=mxjob 25 | 26 | // MXJob represents the configuration of signal MXJob 27 | type MXJob struct { 28 | metav1.TypeMeta `json:",inline"` 29 | 30 | // Standard object's metadata. 31 | metav1.ObjectMeta `json:"metadata,omitempty"` 32 | 33 | // Specification of the desired behavior of the MXJob. 34 | Spec MXJobSpec `json:"spec,omitempty"` 35 | 36 | // Most recently observed status of the MXJob. 37 | // This data may not be up to date. 38 | // Populated by the system. 39 | // Read-only. 40 | Status common.JobStatus `json:"status,omitempty"` 41 | } 42 | 43 | // MXJobSpec is a desired state description of the MXJob. 44 | type MXJobSpec struct { 45 | // RunPolicy encapsulates various runtime policies of the distributed training 46 | // job, for example how to clean up resources and how long the job can stay 47 | // active. 48 | RunPolicy common.RunPolicy `json:",inline"` 49 | 50 | // JobMode specify the kind of MXjob to do. Different mode may have 51 | // different MXReplicaSpecs request 52 | JobMode JobModeType `json:"jobMode"` 53 | 54 | // MXReplicaSpecs is map of common.ReplicaType and common.ReplicaSpec 55 | // specifies the MX replicas to run. 56 | // For example, 57 | // { 58 | // "Scheduler": common.ReplicaSpec, 59 | // "Server": common.ReplicaSpec, 60 | // "Worker": common.ReplicaSpec, 61 | // } 62 | MXReplicaSpecs map[common.ReplicaType]*common.ReplicaSpec `json:"mxReplicaSpecs"` 63 | } 64 | 65 | // JobModeType id the type for JobMode 66 | type JobModeType string 67 | 68 | const ( 69 | // Train Mode, in this mode requested MXReplicaSpecs need 70 | // has Server, Scheduler, Worker 71 | MXTrain JobModeType = "MXTrain" 72 | 73 | // Tune Mode, in this mode requested MXReplicaSpecs need 74 | // has Tuner 75 | MXTune JobModeType = "MXTune" 76 | ) 77 | 78 | const ( 79 | // MXReplicaTypeScheduler is the type for scheduler replica in MXNet. 80 | MXReplicaTypeScheduler common.ReplicaType = "Scheduler" 81 | 82 | // MXReplicaTypeServer is the type for parameter servers of distributed MXNet. 83 | MXReplicaTypeServer common.ReplicaType = "Server" 84 | 85 | // MXReplicaTypeWorker is the type for workers of distributed MXNet. 86 | // This is also used for non-distributed MXNet. 87 | MXReplicaTypeWorker common.ReplicaType = "Worker" 88 | 89 | // MXReplicaTypeTunerTracker 90 | // This the auto-tuning tracker e.g. autotvm tracker, it will dispatch tuning task to TunerServer 91 | MXReplicaTypeTunerTracker common.ReplicaType = "TunerTracker" 92 | 93 | // MXReplicaTypeTunerServer 94 | MXReplicaTypeTunerServer common.ReplicaType = "TunerServer" 95 | 96 | // MXReplicaTuner is the type for auto-tuning of distributed MXNet. 97 | // This is also used for non-distributed MXNet. 98 | MXReplicaTypeTuner common.ReplicaType = "Tuner" 99 | ) 100 | 101 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 102 | // +resource:path=mxjobs 103 | 104 | // MXJobList is a list of MXJobs. 105 | type MXJobList struct { 106 | metav1.TypeMeta `json:",inline"` 107 | 108 | // Standard list metadata. 109 | metav1.ListMeta `json:"metadata,omitempty"` 110 | 111 | // List of MXJobs. 112 | Items []MXJob `json:"items"` 113 | } 114 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1 16 | 17 | import commonv1 "github.com/kubeflow/common/pkg/apis/common/v1" 18 | 19 | // IsScheduler returns true if the type is Scheduler. 20 | func IsScheduler(typ commonv1.ReplicaType) bool { 21 | return typ == MXReplicaTypeScheduler 22 | } 23 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1 16 | 17 | import ( 18 | commonv1 "github.com/kubeflow/common/pkg/apis/common/v1" 19 | "testing" 20 | ) 21 | 22 | func TestIsScheduler(t *testing.T) { 23 | tc := []struct { 24 | Type commonv1.ReplicaType 25 | Expected bool 26 | }{ 27 | { 28 | Type: MXReplicaTypeScheduler, 29 | Expected: true, 30 | }, 31 | { 32 | Type: MXReplicaTypeServer, 33 | Expected: false, 34 | }, 35 | { 36 | Type: MXReplicaTypeWorker, 37 | Expected: false, 38 | }, 39 | } 40 | 41 | for _, c := range tc { 42 | actual := IsScheduler(c.Type) 43 | if actual != c.Expected { 44 | t.Errorf("Expected %v; Got %v", c.Expected, actual) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | // +build !ignore_autogenerated 2 | 3 | // Copyright 2021 The Kubeflow Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // Code generated by deepcopy-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | commonv1 "github.com/kubeflow/common/pkg/apis/common/v1" 23 | runtime "k8s.io/apimachinery/pkg/runtime" 24 | ) 25 | 26 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 27 | func (in *MXJob) DeepCopyInto(out *MXJob) { 28 | *out = *in 29 | out.TypeMeta = in.TypeMeta 30 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 31 | in.Spec.DeepCopyInto(&out.Spec) 32 | in.Status.DeepCopyInto(&out.Status) 33 | return 34 | } 35 | 36 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MXJob. 37 | func (in *MXJob) DeepCopy() *MXJob { 38 | if in == nil { 39 | return nil 40 | } 41 | out := new(MXJob) 42 | in.DeepCopyInto(out) 43 | return out 44 | } 45 | 46 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 47 | func (in *MXJob) DeepCopyObject() runtime.Object { 48 | if c := in.DeepCopy(); c != nil { 49 | return c 50 | } 51 | return nil 52 | } 53 | 54 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 55 | func (in *MXJobList) DeepCopyInto(out *MXJobList) { 56 | *out = *in 57 | out.TypeMeta = in.TypeMeta 58 | in.ListMeta.DeepCopyInto(&out.ListMeta) 59 | if in.Items != nil { 60 | in, out := &in.Items, &out.Items 61 | *out = make([]MXJob, len(*in)) 62 | for i := range *in { 63 | (*in)[i].DeepCopyInto(&(*out)[i]) 64 | } 65 | } 66 | return 67 | } 68 | 69 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MXJobList. 70 | func (in *MXJobList) DeepCopy() *MXJobList { 71 | if in == nil { 72 | return nil 73 | } 74 | out := new(MXJobList) 75 | in.DeepCopyInto(out) 76 | return out 77 | } 78 | 79 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 80 | func (in *MXJobList) DeepCopyObject() runtime.Object { 81 | if c := in.DeepCopy(); c != nil { 82 | return c 83 | } 84 | return nil 85 | } 86 | 87 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 88 | func (in *MXJobSpec) DeepCopyInto(out *MXJobSpec) { 89 | *out = *in 90 | in.RunPolicy.DeepCopyInto(&out.RunPolicy) 91 | if in.MXReplicaSpecs != nil { 92 | in, out := &in.MXReplicaSpecs, &out.MXReplicaSpecs 93 | *out = make(map[commonv1.ReplicaType]*commonv1.ReplicaSpec, len(*in)) 94 | for key, val := range *in { 95 | var outVal *commonv1.ReplicaSpec 96 | if val == nil { 97 | (*out)[key] = nil 98 | } else { 99 | in, out := &val, &outVal 100 | *out = new(commonv1.ReplicaSpec) 101 | (*in).DeepCopyInto(*out) 102 | } 103 | (*out)[key] = outVal 104 | } 105 | } 106 | return 107 | } 108 | 109 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MXJobSpec. 110 | func (in *MXJobSpec) DeepCopy() *MXJobSpec { 111 | if in == nil { 112 | return nil 113 | } 114 | out := new(MXJobSpec) 115 | in.DeepCopyInto(out) 116 | return out 117 | } 118 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1/zz_generated.defaults.go: -------------------------------------------------------------------------------- 1 | // +build !ignore_autogenerated 2 | 3 | // Copyright 2021 The Kubeflow Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // Code generated by defaulter-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | runtime "k8s.io/apimachinery/pkg/runtime" 23 | ) 24 | 25 | // RegisterDefaults adds defaulters functions to the given scheme. 26 | // Public to allow building arbitrary schemes. 27 | // All generated defaulters are covering - they call all nested defaulters. 28 | func RegisterDefaults(scheme *runtime.Scheme) error { 29 | scheme.AddTypeDefaultingFunc(&MXJob{}, func(obj interface{}) { SetObjectDefaults_MXJob(obj.(*MXJob)) }) 30 | scheme.AddTypeDefaultingFunc(&MXJobList{}, func(obj interface{}) { SetObjectDefaults_MXJobList(obj.(*MXJobList)) }) 31 | return nil 32 | } 33 | 34 | func SetObjectDefaults_MXJob(in *MXJob) { 35 | SetDefaults_MXJob(in) 36 | } 37 | 38 | func SetObjectDefaults_MXJobList(in *MXJobList) { 39 | for i := range in.Items { 40 | a := &in.Items[i] 41 | SetObjectDefaults_MXJob(a) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1beta1/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1beta1 16 | 17 | const ( 18 | // EnvKubeflowNamespace is ENV for kubeflow namespace specified by user. 19 | EnvKubeflowNamespace = "KUBEFLOW_NAMESPACE" 20 | 21 | // DefaultPortName is name of the port used to communicate between scheduler and 22 | // servers & workers. 23 | DefaultPortName = "mxjob-port" 24 | // DefaultContainerName is the name of the MXJob container. 25 | DefaultContainerName = "mxnet" 26 | // DefaultPort is default value of the port. 27 | DefaultPort = 9091 28 | // DefaultRestartPolicy is default RestartPolicy for MXReplicaSpec. 29 | DefaultRestartPolicy = RestartPolicyNever 30 | ) 31 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1beta1/defaults.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1beta1 16 | 17 | import ( 18 | "strings" 19 | 20 | v1 "k8s.io/api/core/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | ) 23 | 24 | // Int32 is a helper routine that allocates a new int32 value 25 | // to store v and returns a pointer to it. 26 | func Int32(v int32) *int32 { 27 | return &v 28 | } 29 | 30 | func addDefaultingFuncs(scheme *runtime.Scheme) error { 31 | return RegisterDefaults(scheme) 32 | } 33 | 34 | // setDefaultPort sets the default ports for mxnet container. 35 | func setDefaultPort(spec *v1.PodSpec) { 36 | index := 0 37 | for i, container := range spec.Containers { 38 | if container.Name == DefaultContainerName { 39 | index = i 40 | break 41 | } 42 | } 43 | 44 | hasMXJobPort := false 45 | for _, port := range spec.Containers[index].Ports { 46 | if port.Name == DefaultPortName { 47 | hasMXJobPort = true 48 | break 49 | } 50 | } 51 | if !hasMXJobPort { 52 | spec.Containers[index].Ports = append(spec.Containers[index].Ports, v1.ContainerPort{ 53 | Name: DefaultPortName, 54 | ContainerPort: DefaultPort, 55 | }) 56 | } 57 | } 58 | 59 | func setDefaultReplicas(spec *MXReplicaSpec) { 60 | if spec.Replicas == nil { 61 | spec.Replicas = Int32(1) 62 | } 63 | if spec.RestartPolicy == "" { 64 | spec.RestartPolicy = DefaultRestartPolicy 65 | } 66 | } 67 | 68 | // setTypeNamesToCamelCase sets the name of all replica types from any case to correct case. 69 | func setTypeNamesToCamelCase(mxJob *MXJob) { 70 | setTypeNameToCamelCase(mxJob, MXReplicaTypeScheduler) 71 | setTypeNameToCamelCase(mxJob, MXReplicaTypeServer) 72 | setTypeNameToCamelCase(mxJob, MXReplicaTypeWorker) 73 | } 74 | 75 | // setTypeNameToCamelCase sets the name of the replica type from any case to correct case. 76 | // E.g. from server to Server; from WORKER to Worker. 77 | func setTypeNameToCamelCase(mxJob *MXJob, typ MXReplicaType) { 78 | for t := range mxJob.Spec.MXReplicaSpecs { 79 | if strings.EqualFold(string(t), string(typ)) && t != typ { 80 | spec := mxJob.Spec.MXReplicaSpecs[t] 81 | delete(mxJob.Spec.MXReplicaSpecs, t) 82 | mxJob.Spec.MXReplicaSpecs[typ] = spec 83 | return 84 | } 85 | } 86 | } 87 | 88 | // SetDefaults_MXJob sets any unspecified values to defaults. 89 | func SetDefaults_MXJob(mxjob *MXJob) { 90 | // Set default cleanpod policy to All. 91 | if mxjob.Spec.CleanPodPolicy == nil { 92 | all := CleanPodPolicyAll 93 | mxjob.Spec.CleanPodPolicy = &all 94 | } 95 | 96 | // Set default success policy to "". 97 | if mxjob.Spec.SuccessPolicy == nil { 98 | defaultPolicy := SuccessPolicyDefault 99 | mxjob.Spec.SuccessPolicy = &defaultPolicy 100 | } 101 | 102 | // Update the key of MXReplicaSpecs to camel case. 103 | setTypeNamesToCamelCase(mxjob) 104 | 105 | for _, spec := range mxjob.Spec.MXReplicaSpecs { 106 | // Set default replicas to 1. 107 | setDefaultReplicas(spec) 108 | // Set default port to mxnet container. 109 | setDefaultPort(&spec.Template.Spec) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1beta1/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +k8s:deepcopy-gen=package,register 16 | // +k8s:defaulter-gen=TypeMeta 17 | // +k8s:openapi-gen=true 18 | 19 | // Package v1alpha2 is the v1alpha2 version of the API. 20 | // +groupName=kubeflow.org 21 | package v1beta1 22 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1beta1/register.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1beta1 16 | 17 | import ( 18 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 19 | "k8s.io/apimachinery/pkg/runtime" 20 | "k8s.io/apimachinery/pkg/runtime/schema" 21 | ) 22 | 23 | var ( 24 | // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. 25 | // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. 26 | SchemeBuilder runtime.SchemeBuilder 27 | localSchemeBuilder = &SchemeBuilder 28 | AddToScheme = localSchemeBuilder.AddToScheme 29 | ) 30 | 31 | const ( 32 | // GroupName is the group name use in this package. 33 | GroupName = "kubeflow.org" 34 | // Kind is the kind name. 35 | Kind = "MXJob" 36 | // GroupVersion is the version. 37 | GroupVersion = "v1beta1" 38 | // Plural is the Plural for MXJob. 39 | Plural = "mxjobs" 40 | // Singular is the singular for MXJob. 41 | Singular = "mxjob" 42 | // MXCRD is the CRD name for MXJob. 43 | MXCRD = "mxjobs.kubeflow.org" 44 | ) 45 | 46 | var ( 47 | // SchemeGroupVersion is the group version used to register these objects. 48 | SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion} 49 | // SchemeGroupVersionKind is the GroupVersionKind of the resource. 50 | SchemeGroupVersionKind = SchemeGroupVersion.WithKind(Kind) 51 | ) 52 | 53 | func init() { 54 | // We only register manually written functions here. The registration of the 55 | // generated functions takes place in the generated files. The separation 56 | // makes the code compile even when the generated files are missing. 57 | localSchemeBuilder.Register(addKnownTypes) 58 | localSchemeBuilder.Register(addDefaultingFuncs) 59 | } 60 | 61 | // Resource takes an unqualified resource and returns a Group-qualified GroupResource. 62 | func Resource(resource string) schema.GroupResource { 63 | return SchemeGroupVersion.WithResource(resource).GroupResource() 64 | } 65 | 66 | // addKnownTypes adds the set of types defined in this package to the supplied scheme. 67 | func addKnownTypes(scheme *runtime.Scheme) error { 68 | scheme.AddKnownTypes(SchemeGroupVersion, 69 | &MXJob{}, 70 | &MXJobList{}, 71 | ) 72 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1beta1/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1beta1 16 | 17 | // IsScheduler returns true if the type is Scheduler. 18 | func IsScheduler(typ MXReplicaType) bool { 19 | return typ == MXReplicaTypeScheduler 20 | } 21 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1beta1/util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package v1beta1 16 | 17 | import "testing" 18 | 19 | func TestIsScheduler(t *testing.T) { 20 | tc := []struct { 21 | Type MXReplicaType 22 | Expected bool 23 | }{ 24 | { 25 | Type: MXReplicaTypeScheduler, 26 | Expected: true, 27 | }, 28 | { 29 | Type: MXReplicaTypeServer, 30 | Expected: false, 31 | }, 32 | { 33 | Type: MXReplicaTypeWorker, 34 | Expected: false, 35 | }, 36 | } 37 | 38 | for _, c := range tc { 39 | actual := IsScheduler(c.Type) 40 | if actual != c.Expected { 41 | t.Errorf("Expected %v; Got %v", c.Expected, actual) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/v1beta1/zz_generated.defaults.go: -------------------------------------------------------------------------------- 1 | // +build !ignore_autogenerated 2 | 3 | // Copyright 2021 The Kubeflow Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // Code generated by defaulter-gen. DO NOT EDIT. 18 | 19 | package v1beta1 20 | 21 | import ( 22 | runtime "k8s.io/apimachinery/pkg/runtime" 23 | ) 24 | 25 | // RegisterDefaults adds defaulters functions to the given scheme. 26 | // Public to allow building arbitrary schemes. 27 | // All generated defaulters are covering - they call all nested defaulters. 28 | func RegisterDefaults(scheme *runtime.Scheme) error { 29 | scheme.AddTypeDefaultingFunc(&MXJob{}, func(obj interface{}) { SetObjectDefaults_MXJob(obj.(*MXJob)) }) 30 | scheme.AddTypeDefaultingFunc(&MXJobList{}, func(obj interface{}) { SetObjectDefaults_MXJobList(obj.(*MXJobList)) }) 31 | return nil 32 | } 33 | 34 | func SetObjectDefaults_MXJob(in *MXJob) { 35 | SetDefaults_MXJob(in) 36 | } 37 | 38 | func SetObjectDefaults_MXJobList(in *MXJobList) { 39 | for i := range in.Items { 40 | a := &in.Items[i] 41 | SetObjectDefaults_MXJob(a) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pkg/apis/mxnet/validation/validation.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package validation 16 | 17 | import ( 18 | "fmt" 19 | commonv1 "github.com/kubeflow/common/pkg/apis/common/v1" 20 | 21 | log "github.com/sirupsen/logrus" 22 | 23 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 24 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 25 | ) 26 | 27 | // ValidateBetaOneMXJobSpec checks that the v1beta1.MXJobSpec is valid. 28 | func ValidateBetaOneMXJobSpec(c *mxv1beta1.MXJobSpec) error { 29 | return validateBetaOneReplicaSpecs(c.MXReplicaSpecs) 30 | } 31 | 32 | func validateBetaOneReplicaSpecs(specs map[mxv1beta1.MXReplicaType]*mxv1beta1.MXReplicaSpec) error { 33 | if specs == nil { 34 | return fmt.Errorf("MXJobSpec is not valid") 35 | } 36 | foundScheduler := 0 37 | for rType, value := range specs { 38 | if value == nil || len(value.Template.Spec.Containers) == 0 { 39 | return fmt.Errorf("MXJobSpec is not valid") 40 | } 41 | if mxv1beta1.IsScheduler(rType) { 42 | foundScheduler++ 43 | } 44 | // Make sure the image is defined in the container. 45 | numNamedMXNet := 0 46 | for _, container := range value.Template.Spec.Containers { 47 | if container.Image == "" { 48 | log.Warn("Image is undefined in the container") 49 | return fmt.Errorf("MXJobSpec is not valid") 50 | } 51 | if container.Name == mxv1beta1.DefaultContainerName { 52 | numNamedMXNet++ 53 | } 54 | } 55 | // Make sure there has at least one container named "mxnet". 56 | if numNamedMXNet == 0 { 57 | log.Warnf("There is no container named mxnet in %v", rType) 58 | return fmt.Errorf("MXJobSpec is not valid") 59 | } 60 | } 61 | if foundScheduler > 1 { 62 | return fmt.Errorf("more than 1 scheduler found") 63 | } 64 | return nil 65 | } 66 | 67 | // ValidateV1MXJobSpec checks that the v1.MXJobSpec is valid. 68 | func ValidateV1MXJobSpec(c *mxv1.MXJobSpec) error { 69 | return validateV1ReplicaSpecs(c.MXReplicaSpecs) 70 | } 71 | 72 | func validateV1ReplicaSpecs(specs map[commonv1.ReplicaType]*commonv1.ReplicaSpec) error { 73 | if specs == nil { 74 | return fmt.Errorf("MXJobSpec is not valid") 75 | } 76 | foundScheduler := 0 77 | for rType, value := range specs { 78 | if value == nil || len(value.Template.Spec.Containers) == 0 { 79 | return fmt.Errorf("MXJobSpec is not valid") 80 | } 81 | if mxv1.IsScheduler(rType) { 82 | foundScheduler++ 83 | } 84 | // Make sure the image is defined in the container. 85 | numNamedMXNet := 0 86 | for _, container := range value.Template.Spec.Containers { 87 | if container.Image == "" { 88 | log.Warn("Image is undefined in the container") 89 | return fmt.Errorf("MXJobSpec is not valid") 90 | } 91 | if container.Name == mxv1beta1.DefaultContainerName { 92 | numNamedMXNet++ 93 | } 94 | } 95 | // Make sure there has at least one container named "mxnet". 96 | if numNamedMXNet == 0 { 97 | log.Warnf("There is no container named mxnet in %v", rType) 98 | return fmt.Errorf("MXJobSpec is not valid") 99 | } 100 | } 101 | if foundScheduler > 1 { 102 | return fmt.Errorf("more than 1 scheduler found") 103 | } 104 | return nil 105 | } 106 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/clientset.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package versioned 18 | 19 | import ( 20 | "fmt" 21 | 22 | kubeflowv1 "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/typed/mxnet/v1" 23 | kubeflowv1beta1 "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/typed/mxnet/v1beta1" 24 | discovery "k8s.io/client-go/discovery" 25 | rest "k8s.io/client-go/rest" 26 | flowcontrol "k8s.io/client-go/util/flowcontrol" 27 | ) 28 | 29 | type Interface interface { 30 | Discovery() discovery.DiscoveryInterface 31 | KubeflowV1beta1() kubeflowv1beta1.KubeflowV1beta1Interface 32 | KubeflowV1() kubeflowv1.KubeflowV1Interface 33 | } 34 | 35 | // Clientset contains the clients for groups. Each group has exactly one 36 | // version included in a Clientset. 37 | type Clientset struct { 38 | *discovery.DiscoveryClient 39 | kubeflowV1beta1 *kubeflowv1beta1.KubeflowV1beta1Client 40 | kubeflowV1 *kubeflowv1.KubeflowV1Client 41 | } 42 | 43 | // KubeflowV1beta1 retrieves the KubeflowV1beta1Client 44 | func (c *Clientset) KubeflowV1beta1() kubeflowv1beta1.KubeflowV1beta1Interface { 45 | return c.kubeflowV1beta1 46 | } 47 | 48 | // KubeflowV1 retrieves the KubeflowV1Client 49 | func (c *Clientset) KubeflowV1() kubeflowv1.KubeflowV1Interface { 50 | return c.kubeflowV1 51 | } 52 | 53 | // Discovery retrieves the DiscoveryClient 54 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 55 | if c == nil { 56 | return nil 57 | } 58 | return c.DiscoveryClient 59 | } 60 | 61 | // NewForConfig creates a new Clientset for the given config. 62 | // If config's RateLimiter is not set and QPS and Burst are acceptable, 63 | // NewForConfig will generate a rate-limiter in configShallowCopy. 64 | func NewForConfig(c *rest.Config) (*Clientset, error) { 65 | configShallowCopy := *c 66 | if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { 67 | if configShallowCopy.Burst <= 0 { 68 | return nil, fmt.Errorf("Burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") 69 | } 70 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) 71 | } 72 | var cs Clientset 73 | var err error 74 | cs.kubeflowV1beta1, err = kubeflowv1beta1.NewForConfig(&configShallowCopy) 75 | if err != nil { 76 | return nil, err 77 | } 78 | cs.kubeflowV1, err = kubeflowv1.NewForConfig(&configShallowCopy) 79 | if err != nil { 80 | return nil, err 81 | } 82 | 83 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) 84 | if err != nil { 85 | return nil, err 86 | } 87 | return &cs, nil 88 | } 89 | 90 | // NewForConfigOrDie creates a new Clientset for the given config and 91 | // panics if there is an error in the config. 92 | func NewForConfigOrDie(c *rest.Config) *Clientset { 93 | var cs Clientset 94 | cs.kubeflowV1beta1 = kubeflowv1beta1.NewForConfigOrDie(c) 95 | cs.kubeflowV1 = kubeflowv1.NewForConfigOrDie(c) 96 | 97 | cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) 98 | return &cs 99 | } 100 | 101 | // New creates a new Clientset for the given RESTClient. 102 | func New(c rest.Interface) *Clientset { 103 | var cs Clientset 104 | cs.kubeflowV1beta1 = kubeflowv1beta1.New(c) 105 | cs.kubeflowV1 = kubeflowv1.New(c) 106 | 107 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c) 108 | return &cs 109 | } 110 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | // This package has the automatically generated clientset. 18 | package versioned 19 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/fake/clientset_generated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package fake 18 | 19 | import ( 20 | clientset "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned" 21 | kubeflowv1 "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/typed/mxnet/v1" 22 | fakekubeflowv1 "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/typed/mxnet/v1/fake" 23 | kubeflowv1beta1 "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/typed/mxnet/v1beta1" 24 | fakekubeflowv1beta1 "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/typed/mxnet/v1beta1/fake" 25 | "k8s.io/apimachinery/pkg/runtime" 26 | "k8s.io/apimachinery/pkg/watch" 27 | "k8s.io/client-go/discovery" 28 | fakediscovery "k8s.io/client-go/discovery/fake" 29 | "k8s.io/client-go/testing" 30 | ) 31 | 32 | // NewSimpleClientset returns a clientset that will respond with the provided objects. 33 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, 34 | // without applying any validations and/or defaults. It shouldn't be considered a replacement 35 | // for a real clientset and is mostly useful in simple unit tests. 36 | func NewSimpleClientset(objects ...runtime.Object) *Clientset { 37 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) 38 | for _, obj := range objects { 39 | if err := o.Add(obj); err != nil { 40 | panic(err) 41 | } 42 | } 43 | 44 | cs := &Clientset{tracker: o} 45 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} 46 | cs.AddReactor("*", "*", testing.ObjectReaction(o)) 47 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { 48 | gvr := action.GetResource() 49 | ns := action.GetNamespace() 50 | watch, err := o.Watch(gvr, ns) 51 | if err != nil { 52 | return false, nil, err 53 | } 54 | return true, watch, nil 55 | }) 56 | 57 | return cs 58 | } 59 | 60 | // Clientset implements clientset.Interface. Meant to be embedded into a 61 | // struct to get a default implementation. This makes faking out just the method 62 | // you want to test easier. 63 | type Clientset struct { 64 | testing.Fake 65 | discovery *fakediscovery.FakeDiscovery 66 | tracker testing.ObjectTracker 67 | } 68 | 69 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 70 | return c.discovery 71 | } 72 | 73 | func (c *Clientset) Tracker() testing.ObjectTracker { 74 | return c.tracker 75 | } 76 | 77 | var _ clientset.Interface = &Clientset{} 78 | 79 | // KubeflowV1beta1 retrieves the KubeflowV1beta1Client 80 | func (c *Clientset) KubeflowV1beta1() kubeflowv1beta1.KubeflowV1beta1Interface { 81 | return &fakekubeflowv1beta1.FakeKubeflowV1beta1{Fake: &c.Fake} 82 | } 83 | 84 | // KubeflowV1 retrieves the KubeflowV1Client 85 | func (c *Clientset) KubeflowV1() kubeflowv1.KubeflowV1Interface { 86 | return &fakekubeflowv1.FakeKubeflowV1{Fake: &c.Fake} 87 | } 88 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | // This package has the automatically generated fake clientset. 18 | package fake 19 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/fake/register.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package fake 18 | 19 | import ( 20 | kubeflowv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 21 | kubeflowv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 22 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | runtime "k8s.io/apimachinery/pkg/runtime" 24 | schema "k8s.io/apimachinery/pkg/runtime/schema" 25 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 26 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 27 | ) 28 | 29 | var scheme = runtime.NewScheme() 30 | var codecs = serializer.NewCodecFactory(scheme) 31 | var parameterCodec = runtime.NewParameterCodec(scheme) 32 | var localSchemeBuilder = runtime.SchemeBuilder{ 33 | kubeflowv1beta1.AddToScheme, 34 | kubeflowv1.AddToScheme, 35 | } 36 | 37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 38 | // of clientsets, like in: 39 | // 40 | // import ( 41 | // "k8s.io/client-go/kubernetes" 42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 44 | // ) 45 | // 46 | // kclientset, _ := kubernetes.NewForConfig(c) 47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 48 | // 49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 50 | // correctly. 51 | var AddToScheme = localSchemeBuilder.AddToScheme 52 | 53 | func init() { 54 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) 55 | utilruntime.Must(AddToScheme(scheme)) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | // This package contains the scheme of the automatically generated clientset. 18 | package scheme 19 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/scheme/register.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package scheme 18 | 19 | import ( 20 | kubeflowv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 21 | kubeflowv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 22 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | runtime "k8s.io/apimachinery/pkg/runtime" 24 | schema "k8s.io/apimachinery/pkg/runtime/schema" 25 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 26 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 27 | ) 28 | 29 | var Scheme = runtime.NewScheme() 30 | var Codecs = serializer.NewCodecFactory(Scheme) 31 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 32 | var localSchemeBuilder = runtime.SchemeBuilder{ 33 | kubeflowv1beta1.AddToScheme, 34 | kubeflowv1.AddToScheme, 35 | } 36 | 37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 38 | // of clientsets, like in: 39 | // 40 | // import ( 41 | // "k8s.io/client-go/kubernetes" 42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 44 | // ) 45 | // 46 | // kclientset, _ := kubernetes.NewForConfig(c) 47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 48 | // 49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 50 | // correctly. 51 | var AddToScheme = localSchemeBuilder.AddToScheme 52 | 53 | func init() { 54 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 55 | utilruntime.Must(AddToScheme(Scheme)) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | // This package has the automatically generated typed clients. 18 | package v1 19 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1/fake/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | // Package fake has the automatically generated clients. 18 | package fake 19 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1/fake/fake_mxnet_client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package fake 18 | 19 | import ( 20 | v1 "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/typed/mxnet/v1" 21 | rest "k8s.io/client-go/rest" 22 | testing "k8s.io/client-go/testing" 23 | ) 24 | 25 | type FakeKubeflowV1 struct { 26 | *testing.Fake 27 | } 28 | 29 | func (c *FakeKubeflowV1) MXJobs(namespace string) v1.MXJobInterface { 30 | return &FakeMXJobs{c, namespace} 31 | } 32 | 33 | // RESTClient returns a RESTClient that is used to communicate 34 | // with API server by this client implementation. 35 | func (c *FakeKubeflowV1) RESTClient() rest.Interface { 36 | var ret *rest.RESTClient 37 | return ret 38 | } 39 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package v1 18 | 19 | type MXJobExpansion interface{} 20 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1/mxnet_client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package v1 18 | 19 | import ( 20 | v1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 21 | "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/scheme" 22 | rest "k8s.io/client-go/rest" 23 | ) 24 | 25 | type KubeflowV1Interface interface { 26 | RESTClient() rest.Interface 27 | MXJobsGetter 28 | } 29 | 30 | // KubeflowV1Client is used to interact with features provided by the kubeflow.org group. 31 | type KubeflowV1Client struct { 32 | restClient rest.Interface 33 | } 34 | 35 | func (c *KubeflowV1Client) MXJobs(namespace string) MXJobInterface { 36 | return newMXJobs(c, namespace) 37 | } 38 | 39 | // NewForConfig creates a new KubeflowV1Client for the given config. 40 | func NewForConfig(c *rest.Config) (*KubeflowV1Client, error) { 41 | config := *c 42 | if err := setConfigDefaults(&config); err != nil { 43 | return nil, err 44 | } 45 | client, err := rest.RESTClientFor(&config) 46 | if err != nil { 47 | return nil, err 48 | } 49 | return &KubeflowV1Client{client}, nil 50 | } 51 | 52 | // NewForConfigOrDie creates a new KubeflowV1Client for the given config and 53 | // panics if there is an error in the config. 54 | func NewForConfigOrDie(c *rest.Config) *KubeflowV1Client { 55 | client, err := NewForConfig(c) 56 | if err != nil { 57 | panic(err) 58 | } 59 | return client 60 | } 61 | 62 | // New creates a new KubeflowV1Client for the given RESTClient. 63 | func New(c rest.Interface) *KubeflowV1Client { 64 | return &KubeflowV1Client{c} 65 | } 66 | 67 | func setConfigDefaults(config *rest.Config) error { 68 | gv := v1.SchemeGroupVersion 69 | config.GroupVersion = &gv 70 | config.APIPath = "/apis" 71 | config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 72 | 73 | if config.UserAgent == "" { 74 | config.UserAgent = rest.DefaultKubernetesUserAgent() 75 | } 76 | 77 | return nil 78 | } 79 | 80 | // RESTClient returns a RESTClient that is used to communicate 81 | // with API server by this client implementation. 82 | func (c *KubeflowV1Client) RESTClient() rest.Interface { 83 | if c == nil { 84 | return nil 85 | } 86 | return c.restClient 87 | } 88 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1beta1/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | // This package has the automatically generated typed clients. 18 | package v1beta1 19 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1beta1/fake/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | // Package fake has the automatically generated clients. 18 | package fake 19 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1beta1/fake/fake_mxnet_client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package fake 18 | 19 | import ( 20 | v1beta1 "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/typed/mxnet/v1beta1" 21 | rest "k8s.io/client-go/rest" 22 | testing "k8s.io/client-go/testing" 23 | ) 24 | 25 | type FakeKubeflowV1beta1 struct { 26 | *testing.Fake 27 | } 28 | 29 | func (c *FakeKubeflowV1beta1) MXJobs(namespace string) v1beta1.MXJobInterface { 30 | return &FakeMXJobs{c, namespace} 31 | } 32 | 33 | // RESTClient returns a RESTClient that is used to communicate 34 | // with API server by this client implementation. 35 | func (c *FakeKubeflowV1beta1) RESTClient() rest.Interface { 36 | var ret *rest.RESTClient 37 | return ret 38 | } 39 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1beta1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package v1beta1 18 | 19 | type MXJobExpansion interface{} 20 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/mxnet/v1beta1/mxnet_client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by client-gen. DO NOT EDIT. 16 | 17 | package v1beta1 18 | 19 | import ( 20 | v1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 21 | "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned/scheme" 22 | rest "k8s.io/client-go/rest" 23 | ) 24 | 25 | type KubeflowV1beta1Interface interface { 26 | RESTClient() rest.Interface 27 | MXJobsGetter 28 | } 29 | 30 | // KubeflowV1beta1Client is used to interact with features provided by the kubeflow.org group. 31 | type KubeflowV1beta1Client struct { 32 | restClient rest.Interface 33 | } 34 | 35 | func (c *KubeflowV1beta1Client) MXJobs(namespace string) MXJobInterface { 36 | return newMXJobs(c, namespace) 37 | } 38 | 39 | // NewForConfig creates a new KubeflowV1beta1Client for the given config. 40 | func NewForConfig(c *rest.Config) (*KubeflowV1beta1Client, error) { 41 | config := *c 42 | if err := setConfigDefaults(&config); err != nil { 43 | return nil, err 44 | } 45 | client, err := rest.RESTClientFor(&config) 46 | if err != nil { 47 | return nil, err 48 | } 49 | return &KubeflowV1beta1Client{client}, nil 50 | } 51 | 52 | // NewForConfigOrDie creates a new KubeflowV1beta1Client for the given config and 53 | // panics if there is an error in the config. 54 | func NewForConfigOrDie(c *rest.Config) *KubeflowV1beta1Client { 55 | client, err := NewForConfig(c) 56 | if err != nil { 57 | panic(err) 58 | } 59 | return client 60 | } 61 | 62 | // New creates a new KubeflowV1beta1Client for the given RESTClient. 63 | func New(c rest.Interface) *KubeflowV1beta1Client { 64 | return &KubeflowV1beta1Client{c} 65 | } 66 | 67 | func setConfigDefaults(config *rest.Config) error { 68 | gv := v1beta1.SchemeGroupVersion 69 | config.GroupVersion = &gv 70 | config.APIPath = "/apis" 71 | config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 72 | 73 | if config.UserAgent == "" { 74 | config.UserAgent = rest.DefaultKubernetesUserAgent() 75 | } 76 | 77 | return nil 78 | } 79 | 80 | // RESTClient returns a RESTClient that is used to communicate 81 | // with API server by this client implementation. 82 | func (c *KubeflowV1beta1Client) RESTClient() rest.Interface { 83 | if c == nil { 84 | return nil 85 | } 86 | return c.restClient 87 | } 88 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/generic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by informer-gen. DO NOT EDIT. 16 | 17 | package externalversions 18 | 19 | import ( 20 | "fmt" 21 | 22 | v1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 23 | v1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 24 | schema "k8s.io/apimachinery/pkg/runtime/schema" 25 | cache "k8s.io/client-go/tools/cache" 26 | ) 27 | 28 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other 29 | // sharedInformers based on type 30 | type GenericInformer interface { 31 | Informer() cache.SharedIndexInformer 32 | Lister() cache.GenericLister 33 | } 34 | 35 | type genericInformer struct { 36 | informer cache.SharedIndexInformer 37 | resource schema.GroupResource 38 | } 39 | 40 | // Informer returns the SharedIndexInformer. 41 | func (f *genericInformer) Informer() cache.SharedIndexInformer { 42 | return f.informer 43 | } 44 | 45 | // Lister returns the GenericLister. 46 | func (f *genericInformer) Lister() cache.GenericLister { 47 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) 48 | } 49 | 50 | // ForResource gives generic access to a shared informer of the matching type 51 | // TODO extend this to unknown resources with a client pool 52 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { 53 | switch resource { 54 | // Group=kubeflow.org, Version=v1 55 | case v1.SchemeGroupVersion.WithResource("mxjobs"): 56 | return &genericInformer{resource: resource.GroupResource(), informer: f.Kubeflow().V1().MXJobs().Informer()}, nil 57 | 58 | // Group=kubeflow.org, Version=v1beta1 59 | case v1beta1.SchemeGroupVersion.WithResource("mxjobs"): 60 | return &genericInformer{resource: resource.GroupResource(), informer: f.Kubeflow().V1beta1().MXJobs().Informer()}, nil 61 | 62 | } 63 | 64 | return nil, fmt.Errorf("no informer found for %v", resource) 65 | } 66 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by informer-gen. DO NOT EDIT. 16 | 17 | package internalinterfaces 18 | 19 | import ( 20 | time "time" 21 | 22 | versioned "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | cache "k8s.io/client-go/tools/cache" 26 | ) 27 | 28 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. 29 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer 30 | 31 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle 32 | type SharedInformerFactory interface { 33 | Start(stopCh <-chan struct{}) 34 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer 35 | } 36 | 37 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions. 38 | type TweakListOptionsFunc func(*v1.ListOptions) 39 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/mxnet/interface.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by informer-gen. DO NOT EDIT. 16 | 17 | package mxnet 18 | 19 | import ( 20 | internalinterfaces "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/internalinterfaces" 21 | v1 "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/mxnet/v1" 22 | v1beta1 "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/mxnet/v1beta1" 23 | ) 24 | 25 | // Interface provides access to each of this group's versions. 26 | type Interface interface { 27 | // V1beta1 provides access to shared informers for resources in V1beta1. 28 | V1beta1() v1beta1.Interface 29 | // V1 provides access to shared informers for resources in V1. 30 | V1() v1.Interface 31 | } 32 | 33 | type group struct { 34 | factory internalinterfaces.SharedInformerFactory 35 | namespace string 36 | tweakListOptions internalinterfaces.TweakListOptionsFunc 37 | } 38 | 39 | // New returns a new Interface. 40 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 41 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 42 | } 43 | 44 | // V1beta1 returns a new v1beta1.Interface. 45 | func (g *group) V1beta1() v1beta1.Interface { 46 | return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) 47 | } 48 | 49 | // V1 returns a new v1.Interface. 50 | func (g *group) V1() v1.Interface { 51 | return v1.New(g.factory, g.namespace, g.tweakListOptions) 52 | } 53 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/mxnet/v1/interface.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by informer-gen. DO NOT EDIT. 16 | 17 | package v1 18 | 19 | import ( 20 | internalinterfaces "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/internalinterfaces" 21 | ) 22 | 23 | // Interface provides access to all the informers in this group version. 24 | type Interface interface { 25 | // MXJobs returns a MXJobInformer. 26 | MXJobs() MXJobInformer 27 | } 28 | 29 | type version struct { 30 | factory internalinterfaces.SharedInformerFactory 31 | namespace string 32 | tweakListOptions internalinterfaces.TweakListOptionsFunc 33 | } 34 | 35 | // New returns a new Interface. 36 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 37 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 38 | } 39 | 40 | // MXJobs returns a MXJobInformer. 41 | func (v *version) MXJobs() MXJobInformer { 42 | return &mXJobInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 43 | } 44 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/mxnet/v1/mxjob.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by informer-gen. DO NOT EDIT. 16 | 17 | package v1 18 | 19 | import ( 20 | time "time" 21 | 22 | mxnetv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 23 | versioned "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned" 24 | internalinterfaces "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/internalinterfaces" 25 | v1 "github.com/kubeflow/mxnet-operator/pkg/client/listers/mxnet/v1" 26 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 | runtime "k8s.io/apimachinery/pkg/runtime" 28 | watch "k8s.io/apimachinery/pkg/watch" 29 | cache "k8s.io/client-go/tools/cache" 30 | ) 31 | 32 | // MXJobInformer provides access to a shared informer and lister for 33 | // MXJobs. 34 | type MXJobInformer interface { 35 | Informer() cache.SharedIndexInformer 36 | Lister() v1.MXJobLister 37 | } 38 | 39 | type mXJobInformer struct { 40 | factory internalinterfaces.SharedInformerFactory 41 | tweakListOptions internalinterfaces.TweakListOptionsFunc 42 | namespace string 43 | } 44 | 45 | // NewMXJobInformer constructs a new informer for MXJob type. 46 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 47 | // one. This reduces memory footprint and number of connections to the server. 48 | func NewMXJobInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 49 | return NewFilteredMXJobInformer(client, namespace, resyncPeriod, indexers, nil) 50 | } 51 | 52 | // NewFilteredMXJobInformer constructs a new informer for MXJob type. 53 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 54 | // one. This reduces memory footprint and number of connections to the server. 55 | func NewFilteredMXJobInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { 56 | return cache.NewSharedIndexInformer( 57 | &cache.ListWatch{ 58 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 59 | if tweakListOptions != nil { 60 | tweakListOptions(&options) 61 | } 62 | return client.KubeflowV1().MXJobs(namespace).List(options) 63 | }, 64 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 65 | if tweakListOptions != nil { 66 | tweakListOptions(&options) 67 | } 68 | return client.KubeflowV1().MXJobs(namespace).Watch(options) 69 | }, 70 | }, 71 | &mxnetv1.MXJob{}, 72 | resyncPeriod, 73 | indexers, 74 | ) 75 | } 76 | 77 | func (f *mXJobInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 78 | return NewFilteredMXJobInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) 79 | } 80 | 81 | func (f *mXJobInformer) Informer() cache.SharedIndexInformer { 82 | return f.factory.InformerFor(&mxnetv1.MXJob{}, f.defaultInformer) 83 | } 84 | 85 | func (f *mXJobInformer) Lister() v1.MXJobLister { 86 | return v1.NewMXJobLister(f.Informer().GetIndexer()) 87 | } 88 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/mxnet/v1beta1/interface.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by informer-gen. DO NOT EDIT. 16 | 17 | package v1beta1 18 | 19 | import ( 20 | internalinterfaces "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/internalinterfaces" 21 | ) 22 | 23 | // Interface provides access to all the informers in this group version. 24 | type Interface interface { 25 | // MXJobs returns a MXJobInformer. 26 | MXJobs() MXJobInformer 27 | } 28 | 29 | type version struct { 30 | factory internalinterfaces.SharedInformerFactory 31 | namespace string 32 | tweakListOptions internalinterfaces.TweakListOptionsFunc 33 | } 34 | 35 | // New returns a new Interface. 36 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 37 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 38 | } 39 | 40 | // MXJobs returns a MXJobInformer. 41 | func (v *version) MXJobs() MXJobInformer { 42 | return &mXJobInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 43 | } 44 | -------------------------------------------------------------------------------- /pkg/client/informers/externalversions/mxnet/v1beta1/mxjob.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by informer-gen. DO NOT EDIT. 16 | 17 | package v1beta1 18 | 19 | import ( 20 | time "time" 21 | 22 | mxnetv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 23 | versioned "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned" 24 | internalinterfaces "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/internalinterfaces" 25 | v1beta1 "github.com/kubeflow/mxnet-operator/pkg/client/listers/mxnet/v1beta1" 26 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 | runtime "k8s.io/apimachinery/pkg/runtime" 28 | watch "k8s.io/apimachinery/pkg/watch" 29 | cache "k8s.io/client-go/tools/cache" 30 | ) 31 | 32 | // MXJobInformer provides access to a shared informer and lister for 33 | // MXJobs. 34 | type MXJobInformer interface { 35 | Informer() cache.SharedIndexInformer 36 | Lister() v1beta1.MXJobLister 37 | } 38 | 39 | type mXJobInformer struct { 40 | factory internalinterfaces.SharedInformerFactory 41 | tweakListOptions internalinterfaces.TweakListOptionsFunc 42 | namespace string 43 | } 44 | 45 | // NewMXJobInformer constructs a new informer for MXJob type. 46 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 47 | // one. This reduces memory footprint and number of connections to the server. 48 | func NewMXJobInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 49 | return NewFilteredMXJobInformer(client, namespace, resyncPeriod, indexers, nil) 50 | } 51 | 52 | // NewFilteredMXJobInformer constructs a new informer for MXJob type. 53 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 54 | // one. This reduces memory footprint and number of connections to the server. 55 | func NewFilteredMXJobInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { 56 | return cache.NewSharedIndexInformer( 57 | &cache.ListWatch{ 58 | ListFunc: func(options v1.ListOptions) (runtime.Object, error) { 59 | if tweakListOptions != nil { 60 | tweakListOptions(&options) 61 | } 62 | return client.KubeflowV1beta1().MXJobs(namespace).List(options) 63 | }, 64 | WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { 65 | if tweakListOptions != nil { 66 | tweakListOptions(&options) 67 | } 68 | return client.KubeflowV1beta1().MXJobs(namespace).Watch(options) 69 | }, 70 | }, 71 | &mxnetv1beta1.MXJob{}, 72 | resyncPeriod, 73 | indexers, 74 | ) 75 | } 76 | 77 | func (f *mXJobInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 78 | return NewFilteredMXJobInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) 79 | } 80 | 81 | func (f *mXJobInformer) Informer() cache.SharedIndexInformer { 82 | return f.factory.InformerFor(&mxnetv1beta1.MXJob{}, f.defaultInformer) 83 | } 84 | 85 | func (f *mXJobInformer) Lister() v1beta1.MXJobLister { 86 | return v1beta1.NewMXJobLister(f.Informer().GetIndexer()) 87 | } 88 | -------------------------------------------------------------------------------- /pkg/client/listers/mxnet/v1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by lister-gen. DO NOT EDIT. 16 | 17 | package v1 18 | 19 | // MXJobListerExpansion allows custom methods to be added to 20 | // MXJobLister. 21 | type MXJobListerExpansion interface{} 22 | 23 | // MXJobNamespaceListerExpansion allows custom methods to be added to 24 | // MXJobNamespaceLister. 25 | type MXJobNamespaceListerExpansion interface{} 26 | -------------------------------------------------------------------------------- /pkg/client/listers/mxnet/v1/mxjob.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by lister-gen. DO NOT EDIT. 16 | 17 | package v1 18 | 19 | import ( 20 | v1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 21 | "k8s.io/apimachinery/pkg/api/errors" 22 | "k8s.io/apimachinery/pkg/labels" 23 | "k8s.io/client-go/tools/cache" 24 | ) 25 | 26 | // MXJobLister helps list MXJobs. 27 | type MXJobLister interface { 28 | // List lists all MXJobs in the indexer. 29 | List(selector labels.Selector) (ret []*v1.MXJob, err error) 30 | // MXJobs returns an object that can list and get MXJobs. 31 | MXJobs(namespace string) MXJobNamespaceLister 32 | MXJobListerExpansion 33 | } 34 | 35 | // mXJobLister implements the MXJobLister interface. 36 | type mXJobLister struct { 37 | indexer cache.Indexer 38 | } 39 | 40 | // NewMXJobLister returns a new MXJobLister. 41 | func NewMXJobLister(indexer cache.Indexer) MXJobLister { 42 | return &mXJobLister{indexer: indexer} 43 | } 44 | 45 | // List lists all MXJobs in the indexer. 46 | func (s *mXJobLister) List(selector labels.Selector) (ret []*v1.MXJob, err error) { 47 | err = cache.ListAll(s.indexer, selector, func(m interface{}) { 48 | ret = append(ret, m.(*v1.MXJob)) 49 | }) 50 | return ret, err 51 | } 52 | 53 | // MXJobs returns an object that can list and get MXJobs. 54 | func (s *mXJobLister) MXJobs(namespace string) MXJobNamespaceLister { 55 | return mXJobNamespaceLister{indexer: s.indexer, namespace: namespace} 56 | } 57 | 58 | // MXJobNamespaceLister helps list and get MXJobs. 59 | type MXJobNamespaceLister interface { 60 | // List lists all MXJobs in the indexer for a given namespace. 61 | List(selector labels.Selector) (ret []*v1.MXJob, err error) 62 | // Get retrieves the MXJob from the indexer for a given namespace and name. 63 | Get(name string) (*v1.MXJob, error) 64 | MXJobNamespaceListerExpansion 65 | } 66 | 67 | // mXJobNamespaceLister implements the MXJobNamespaceLister 68 | // interface. 69 | type mXJobNamespaceLister struct { 70 | indexer cache.Indexer 71 | namespace string 72 | } 73 | 74 | // List lists all MXJobs in the indexer for a given namespace. 75 | func (s mXJobNamespaceLister) List(selector labels.Selector) (ret []*v1.MXJob, err error) { 76 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { 77 | ret = append(ret, m.(*v1.MXJob)) 78 | }) 79 | return ret, err 80 | } 81 | 82 | // Get retrieves the MXJob from the indexer for a given namespace and name. 83 | func (s mXJobNamespaceLister) Get(name string) (*v1.MXJob, error) { 84 | obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) 85 | if err != nil { 86 | return nil, err 87 | } 88 | if !exists { 89 | return nil, errors.NewNotFound(v1.Resource("mxjob"), name) 90 | } 91 | return obj.(*v1.MXJob), nil 92 | } 93 | -------------------------------------------------------------------------------- /pkg/client/listers/mxnet/v1beta1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by lister-gen. DO NOT EDIT. 16 | 17 | package v1beta1 18 | 19 | // MXJobListerExpansion allows custom methods to be added to 20 | // MXJobLister. 21 | type MXJobListerExpansion interface{} 22 | 23 | // MXJobNamespaceListerExpansion allows custom methods to be added to 24 | // MXJobNamespaceLister. 25 | type MXJobNamespaceListerExpansion interface{} 26 | -------------------------------------------------------------------------------- /pkg/client/listers/mxnet/v1beta1/mxjob.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by lister-gen. DO NOT EDIT. 16 | 17 | package v1beta1 18 | 19 | import ( 20 | v1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 21 | "k8s.io/apimachinery/pkg/api/errors" 22 | "k8s.io/apimachinery/pkg/labels" 23 | "k8s.io/client-go/tools/cache" 24 | ) 25 | 26 | // MXJobLister helps list MXJobs. 27 | type MXJobLister interface { 28 | // List lists all MXJobs in the indexer. 29 | List(selector labels.Selector) (ret []*v1beta1.MXJob, err error) 30 | // MXJobs returns an object that can list and get MXJobs. 31 | MXJobs(namespace string) MXJobNamespaceLister 32 | MXJobListerExpansion 33 | } 34 | 35 | // mXJobLister implements the MXJobLister interface. 36 | type mXJobLister struct { 37 | indexer cache.Indexer 38 | } 39 | 40 | // NewMXJobLister returns a new MXJobLister. 41 | func NewMXJobLister(indexer cache.Indexer) MXJobLister { 42 | return &mXJobLister{indexer: indexer} 43 | } 44 | 45 | // List lists all MXJobs in the indexer. 46 | func (s *mXJobLister) List(selector labels.Selector) (ret []*v1beta1.MXJob, err error) { 47 | err = cache.ListAll(s.indexer, selector, func(m interface{}) { 48 | ret = append(ret, m.(*v1beta1.MXJob)) 49 | }) 50 | return ret, err 51 | } 52 | 53 | // MXJobs returns an object that can list and get MXJobs. 54 | func (s *mXJobLister) MXJobs(namespace string) MXJobNamespaceLister { 55 | return mXJobNamespaceLister{indexer: s.indexer, namespace: namespace} 56 | } 57 | 58 | // MXJobNamespaceLister helps list and get MXJobs. 59 | type MXJobNamespaceLister interface { 60 | // List lists all MXJobs in the indexer for a given namespace. 61 | List(selector labels.Selector) (ret []*v1beta1.MXJob, err error) 62 | // Get retrieves the MXJob from the indexer for a given namespace and name. 63 | Get(name string) (*v1beta1.MXJob, error) 64 | MXJobNamespaceListerExpansion 65 | } 66 | 67 | // mXJobNamespaceLister implements the MXJobNamespaceLister 68 | // interface. 69 | type mXJobNamespaceLister struct { 70 | indexer cache.Indexer 71 | namespace string 72 | } 73 | 74 | // List lists all MXJobs in the indexer for a given namespace. 75 | func (s mXJobNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.MXJob, err error) { 76 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { 77 | ret = append(ret, m.(*v1beta1.MXJob)) 78 | }) 79 | return ret, err 80 | } 81 | 82 | // Get retrieves the MXJob from the indexer for a given namespace and name. 83 | func (s mXJobNamespaceLister) Get(name string) (*v1beta1.MXJob, error) { 84 | obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) 85 | if err != nil { 86 | return nil, err 87 | } 88 | if !exists { 89 | return nil, errors.NewNotFound(v1beta1.Resource("mxjob"), name) 90 | } 91 | return obj.(*v1beta1.MXJob), nil 92 | } 93 | -------------------------------------------------------------------------------- /pkg/common/util/v1/testutil/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "time" 19 | ) 20 | 21 | const ( 22 | TestImageName = "mxjob/mxnet-operator:v1" 23 | TestMXJobName = "test-mxjob" 24 | 25 | LabelScheduler = "scheduler" 26 | LabelWorker = "worker" 27 | LabelServer = "server" 28 | 29 | SleepInterval = 500 * time.Millisecond 30 | ThreadCount = 1 31 | ) 32 | 33 | var ( 34 | AlwaysReady = func() bool { return true } 35 | ) 36 | -------------------------------------------------------------------------------- /pkg/common/util/v1/testutil/pod.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "fmt" 19 | "testing" 20 | 21 | "k8s.io/api/core/v1" 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | "k8s.io/client-go/tools/cache" 24 | 25 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 26 | ) 27 | 28 | const ( 29 | // labels for pods and servers. 30 | mxReplicaTypeLabel = "mxnet-replica-type" 31 | mxReplicaIndexLabel = "mxnet-replica-index" 32 | ) 33 | 34 | var ( 35 | controllerKind = mxv1.SchemeGroupVersionKind 36 | ) 37 | 38 | func NewBasePod(name string, mxJob *mxv1.MXJob, t *testing.T) *v1.Pod { 39 | return &v1.Pod{ 40 | ObjectMeta: metav1.ObjectMeta{ 41 | Name: name, 42 | Labels: GenLabels(mxJob.Name), 43 | Namespace: mxJob.Namespace, 44 | OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(mxJob, controllerKind)}, 45 | }, 46 | } 47 | } 48 | 49 | func NewPod(mxJob *mxv1.MXJob, typ string, index int, t *testing.T) *v1.Pod { 50 | pod := NewBasePod(fmt.Sprintf("%s-%d", typ, index), mxJob, t) 51 | pod.Labels[mxReplicaTypeLabel] = typ 52 | pod.Labels[mxReplicaIndexLabel] = fmt.Sprintf("%d", index) 53 | return pod 54 | } 55 | 56 | // create count pods with the given phase for the given mxJob 57 | func NewPodList(count int32, status v1.PodPhase, mxJob *mxv1.MXJob, typ string, start int32, t *testing.T) []*v1.Pod { 58 | pods := []*v1.Pod{} 59 | for i := int32(0); i < count; i++ { 60 | newPod := NewPod(mxJob, typ, int(start+i), t) 61 | newPod.Status = v1.PodStatus{Phase: status} 62 | pods = append(pods, newPod) 63 | } 64 | return pods 65 | } 66 | 67 | func SetPodsStatuses(podIndexer cache.Indexer, mxJob *mxv1.MXJob, typ string, pendingPods, activePods, succeededPods, failedPods int32, restartCounts []int32, t *testing.T) { 68 | var index int32 69 | for _, pod := range NewPodList(pendingPods, v1.PodPending, mxJob, typ, index, t) { 70 | if err := podIndexer.Add(pod); err != nil { 71 | t.Errorf("%s: unexpected error when adding pod %v", mxJob.Name, err) 72 | } 73 | } 74 | index += pendingPods 75 | for i, pod := range NewPodList(activePods, v1.PodRunning, mxJob, typ, index, t) { 76 | if restartCounts != nil { 77 | pod.Status.ContainerStatuses = []v1.ContainerStatus{{RestartCount: restartCounts[i]}} 78 | } 79 | if err := podIndexer.Add(pod); err != nil { 80 | t.Errorf("%s: unexpected error when adding pod %v", mxJob.Name, err) 81 | } 82 | } 83 | index += activePods 84 | for _, pod := range NewPodList(succeededPods, v1.PodSucceeded, mxJob, typ, index, t) { 85 | if err := podIndexer.Add(pod); err != nil { 86 | t.Errorf("%s: unexpected error when adding pod %v", mxJob.Name, err) 87 | } 88 | } 89 | index += succeededPods 90 | for _, pod := range NewPodList(failedPods, v1.PodFailed, mxJob, typ, index, t) { 91 | if err := podIndexer.Add(pod); err != nil { 92 | t.Errorf("%s: unexpected error when adding pod %v", mxJob.Name, err) 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /pkg/common/util/v1/testutil/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "fmt" 19 | "testing" 20 | 21 | "k8s.io/api/core/v1" 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | "k8s.io/client-go/tools/cache" 24 | 25 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 26 | ) 27 | 28 | func NewBaseService(name string, mxJob *mxv1.MXJob, t *testing.T) *v1.Service { 29 | return &v1.Service{ 30 | ObjectMeta: metav1.ObjectMeta{ 31 | Name: name, 32 | Labels: GenLabels(mxJob.Name), 33 | Namespace: mxJob.Namespace, 34 | OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(mxJob, controllerKind)}, 35 | }, 36 | } 37 | } 38 | 39 | func NewService(mxJob *mxv1.MXJob, typ string, index int, t *testing.T) *v1.Service { 40 | service := NewBaseService(fmt.Sprintf("%s-%d", typ, index), mxJob, t) 41 | service.Labels[mxReplicaTypeLabel] = typ 42 | service.Labels[mxReplicaIndexLabel] = fmt.Sprintf("%d", index) 43 | return service 44 | } 45 | 46 | // NewServiceList creates count pods with the given phase for the given mxJob 47 | func NewServiceList(count int32, mxJob *mxv1.MXJob, typ string, t *testing.T) []*v1.Service { 48 | services := []*v1.Service{} 49 | for i := int32(0); i < count; i++ { 50 | newService := NewService(mxJob, typ, int(i), t) 51 | services = append(services, newService) 52 | } 53 | return services 54 | } 55 | 56 | func SetServices(serviceIndexer cache.Indexer, mxJob *mxv1.MXJob, typ string, activeWorkerServices int32, t *testing.T) { 57 | for _, service := range NewServiceList(activeWorkerServices, mxJob, typ, t) { 58 | if err := serviceIndexer.Add(service); err != nil { 59 | t.Errorf("unexpected error when adding service %v", err) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /pkg/common/util/v1/testutil/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "encoding/json" 19 | commonv1 "github.com/kubeflow/common/pkg/apis/common/v1" 20 | "strings" 21 | "testing" 22 | 23 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 24 | "k8s.io/api/core/v1" 25 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 27 | "k8s.io/client-go/tools/cache" 28 | ) 29 | 30 | const ( 31 | LabelGroupName = "group-name" 32 | LabelMXJobName = "mxnet-job-name" 33 | ) 34 | 35 | var ( 36 | // KeyFunc is the short name to DeletionHandlingMetaNamespaceKeyFunc. 37 | // IndexerInformer uses a delta queue, therefore for deletes we have to use this 38 | // key function but it should be just fine for non delete events. 39 | KeyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc 40 | GroupName = mxv1.GroupName 41 | ) 42 | 43 | func GenLabels(jobName string) map[string]string { 44 | return map[string]string{ 45 | LabelGroupName: GroupName, 46 | LabelMXJobName: strings.Replace(jobName, "/", "-", -1), 47 | } 48 | } 49 | 50 | func GenOwnerReference(mxjob *mxv1.MXJob) *metav1.OwnerReference { 51 | boolPtr := func(b bool) *bool { return &b } 52 | controllerRef := &metav1.OwnerReference{ 53 | APIVersion: mxv1.SchemeGroupVersion.String(), 54 | Kind: mxv1.Kind, 55 | Name: mxjob.Name, 56 | UID: mxjob.UID, 57 | BlockOwnerDeletion: boolPtr(true), 58 | Controller: boolPtr(true), 59 | } 60 | 61 | return controllerRef 62 | } 63 | 64 | // ConvertMXJobToUnstructured uses JSON to convert MXJob to Unstructured. 65 | func ConvertMXJobToUnstructured(mxJob *mxv1.MXJob) (*unstructured.Unstructured, error) { 66 | var unstructured unstructured.Unstructured 67 | b, err := json.Marshal(mxJob) 68 | if err != nil { 69 | return nil, err 70 | } 71 | 72 | if err := json.Unmarshal(b, &unstructured); err != nil { 73 | return nil, err 74 | } 75 | return &unstructured, nil 76 | } 77 | 78 | func GetKey(mxJob *mxv1.MXJob, t *testing.T) string { 79 | key, err := KeyFunc(mxJob) 80 | if err != nil { 81 | t.Errorf("Unexpected error getting key for job %v: %v", mxJob.Name, err) 82 | return "" 83 | } 84 | return key 85 | } 86 | 87 | func CheckCondition(mxJob *mxv1.MXJob, condition commonv1.JobConditionType, reason string) bool { 88 | for _, v := range mxJob.Status.Conditions { 89 | if v.Type == condition && v.Status == v1.ConditionTrue && v.Reason == reason { 90 | return true 91 | } 92 | } 93 | return false 94 | } 95 | -------------------------------------------------------------------------------- /pkg/common/util/v1/unstructured/informer.go: -------------------------------------------------------------------------------- 1 | // Package unstructured is the package for unstructured informer, 2 | // which is from https://github.com/argoproj/argo/blob/master/util/unstructured/unstructured.go 3 | package unstructured 4 | 5 | import ( 6 | "time" 7 | 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 10 | "k8s.io/apimachinery/pkg/runtime" 11 | "k8s.io/apimachinery/pkg/runtime/schema" 12 | "k8s.io/apimachinery/pkg/watch" 13 | "k8s.io/client-go/dynamic" 14 | "k8s.io/client-go/tools/cache" 15 | 16 | informer "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/mxnet/v1" 17 | lister "github.com/kubeflow/mxnet-operator/pkg/client/listers/mxnet/v1" 18 | ) 19 | 20 | type UnstructuredInformer struct { 21 | informer cache.SharedIndexInformer 22 | } 23 | 24 | func NewMXJobInformer(resource schema.GroupVersionResource, client dynamic.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) informer.MXJobInformer { 25 | return &UnstructuredInformer{ 26 | informer: newUnstructuredInformer(resource, client, namespace, resyncPeriod, indexers), 27 | } 28 | } 29 | 30 | func (f *UnstructuredInformer) Informer() cache.SharedIndexInformer { 31 | return f.informer 32 | } 33 | 34 | func (f *UnstructuredInformer) Lister() lister.MXJobLister { 35 | return lister.NewMXJobLister(f.Informer().GetIndexer()) 36 | } 37 | 38 | // newUnstructuredInformer constructs a new informer for Unstructured type. 39 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 40 | // one. This reduces memory footprint and number of connections to the server. 41 | func newUnstructuredInformer(resource schema.GroupVersionResource, client dynamic.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 42 | return newFilteredUnstructuredInformer(resource, client, namespace, resyncPeriod, indexers) 43 | } 44 | 45 | // newFilteredUnstructuredInformer constructs a new informer for Unstructured type. 46 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 47 | // one. This reduces memory footprint and number of connections to the server. 48 | func newFilteredUnstructuredInformer(resource schema.GroupVersionResource, client dynamic.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 49 | return cache.NewSharedIndexInformer( 50 | &cache.ListWatch{ 51 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 52 | return client.Resource(resource).Namespace(namespace).List(options) 53 | }, 54 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 55 | return client.Resource(resource).Namespace(namespace).Watch(options) 56 | }, 57 | }, 58 | &unstructured.Unstructured{}, 59 | resyncPeriod, 60 | indexers, 61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/common/util/v1beta1/testutil/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "time" 19 | ) 20 | 21 | const ( 22 | TestImageName = "mxjob/mxnet-operator:v1beta1" 23 | TestMXJobName = "test-mxjob" 24 | 25 | LabelScheduler = "scheduler" 26 | LabelWorker = "worker" 27 | LabelServer = "server" 28 | 29 | SleepInterval = 500 * time.Millisecond 30 | ThreadCount = 1 31 | ) 32 | 33 | var ( 34 | AlwaysReady = func() bool { return true } 35 | ) 36 | -------------------------------------------------------------------------------- /pkg/common/util/v1beta1/testutil/mxjob.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "time" 19 | 20 | v1 "k8s.io/api/core/v1" 21 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 | 23 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 24 | ) 25 | 26 | func NewMXJobWithCleanPolicy(scheduler, worker, server int, policy mxv1beta1.CleanPodPolicy) *mxv1beta1.MXJob { 27 | 28 | var mxJob *mxv1beta1.MXJob 29 | 30 | if scheduler > 0 { 31 | mxJob = NewMXJobWithScheduler(worker, server) 32 | } else { 33 | mxJob = NewMXJob(worker, server) 34 | } 35 | 36 | mxJob.Spec.CleanPodPolicy = &policy 37 | return mxJob 38 | } 39 | 40 | func NewMXJobWithCleanupJobDelay(scheduler, worker, server int, ttl *int32) *mxv1beta1.MXJob { 41 | 42 | var mxJob *mxv1beta1.MXJob 43 | 44 | if scheduler > 0 { 45 | mxJob = NewMXJobWithScheduler(worker, server) 46 | } else { 47 | mxJob = NewMXJob(worker, server) 48 | } 49 | 50 | mxJob.Spec.TTLSecondsAfterFinished = ttl 51 | policy := mxv1beta1.CleanPodPolicyNone 52 | mxJob.Spec.CleanPodPolicy = &policy 53 | return mxJob 54 | } 55 | 56 | func NewMXJobWithSuccessPolicy(scheduler, worker, server int, policy mxv1beta1.SuccessPolicy) *mxv1beta1.MXJob { 57 | 58 | var mxJob *mxv1beta1.MXJob 59 | 60 | if scheduler > 0 { 61 | mxJob = NewMXJobWithScheduler(worker, server) 62 | } else { 63 | mxJob = NewMXJob(worker, server) 64 | } 65 | 66 | mxJob.Spec.SuccessPolicy = &policy 67 | return mxJob 68 | } 69 | 70 | func NewMXJobWithScheduler(worker, server int) *mxv1beta1.MXJob { 71 | mxJob := NewMXJob(worker, server) 72 | mxJob.Spec.MXReplicaSpecs[mxv1beta1.MXReplicaTypeScheduler] = &mxv1beta1.MXReplicaSpec{ 73 | Template: NewMXReplicaSpecTemplate(), 74 | } 75 | return mxJob 76 | } 77 | 78 | func NewMXJob(worker, server int) *mxv1beta1.MXJob { 79 | mxJob := &mxv1beta1.MXJob{ 80 | TypeMeta: metav1.TypeMeta{ 81 | Kind: mxv1beta1.Kind, 82 | }, 83 | ObjectMeta: metav1.ObjectMeta{ 84 | Name: TestMXJobName, 85 | Namespace: metav1.NamespaceDefault, 86 | }, 87 | Spec: mxv1beta1.MXJobSpec{ 88 | MXReplicaSpecs: make(map[mxv1beta1.MXReplicaType]*mxv1beta1.MXReplicaSpec), 89 | }, 90 | } 91 | 92 | if worker > 0 { 93 | worker := int32(worker) 94 | workerReplicaSpec := &mxv1beta1.MXReplicaSpec{ 95 | Replicas: &worker, 96 | Template: NewMXReplicaSpecTemplate(), 97 | } 98 | mxJob.Spec.MXReplicaSpecs[mxv1beta1.MXReplicaTypeWorker] = workerReplicaSpec 99 | } 100 | 101 | if server > 0 { 102 | server := int32(server) 103 | serverReplicaSpec := &mxv1beta1.MXReplicaSpec{ 104 | Replicas: &server, 105 | Template: NewMXReplicaSpecTemplate(), 106 | } 107 | mxJob.Spec.MXReplicaSpecs[mxv1beta1.MXReplicaTypeServer] = serverReplicaSpec 108 | } 109 | return mxJob 110 | } 111 | 112 | func NewMXReplicaSpecTemplate() v1.PodTemplateSpec { 113 | return v1.PodTemplateSpec{ 114 | Spec: v1.PodSpec{ 115 | Containers: []v1.Container{ 116 | { 117 | Name: mxv1beta1.DefaultContainerName, 118 | Image: TestImageName, 119 | Args: []string{"Fake", "Fake"}, 120 | Ports: []v1.ContainerPort{ 121 | { 122 | Name: mxv1beta1.DefaultPortName, 123 | ContainerPort: mxv1beta1.DefaultPort, 124 | }, 125 | }, 126 | }, 127 | }, 128 | }, 129 | } 130 | } 131 | 132 | func SetMXJobCompletionTime(mxJob *mxv1beta1.MXJob) { 133 | now := metav1.Time{Time: time.Now()} 134 | mxJob.Status.CompletionTime = &now 135 | } 136 | -------------------------------------------------------------------------------- /pkg/common/util/v1beta1/testutil/pod.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "fmt" 19 | "testing" 20 | 21 | "k8s.io/api/core/v1" 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | "k8s.io/client-go/tools/cache" 24 | 25 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 26 | ) 27 | 28 | const ( 29 | // labels for pods and servers. 30 | mxReplicaTypeLabel = "mxnet-replica-type" 31 | mxReplicaIndexLabel = "mxnet-replica-index" 32 | ) 33 | 34 | var ( 35 | controllerKind = mxv1beta1.SchemeGroupVersionKind 36 | ) 37 | 38 | func NewBasePod(name string, mxJob *mxv1beta1.MXJob, t *testing.T) *v1.Pod { 39 | return &v1.Pod{ 40 | ObjectMeta: metav1.ObjectMeta{ 41 | Name: name, 42 | Labels: GenLabels(mxJob.Name), 43 | Namespace: mxJob.Namespace, 44 | OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(mxJob, controllerKind)}, 45 | }, 46 | } 47 | } 48 | 49 | func NewPod(mxJob *mxv1beta1.MXJob, typ string, index int, t *testing.T) *v1.Pod { 50 | pod := NewBasePod(fmt.Sprintf("%s-%d", typ, index), mxJob, t) 51 | pod.Labels[mxReplicaTypeLabel] = typ 52 | pod.Labels[mxReplicaIndexLabel] = fmt.Sprintf("%d", index) 53 | return pod 54 | } 55 | 56 | // create count pods with the given phase for the given mxJob 57 | func NewPodList(count int32, status v1.PodPhase, mxJob *mxv1beta1.MXJob, typ string, start int32, t *testing.T) []*v1.Pod { 58 | pods := []*v1.Pod{} 59 | for i := int32(0); i < count; i++ { 60 | newPod := NewPod(mxJob, typ, int(start+i), t) 61 | newPod.Status = v1.PodStatus{Phase: status} 62 | pods = append(pods, newPod) 63 | } 64 | return pods 65 | } 66 | 67 | func SetPodsStatuses(podIndexer cache.Indexer, mxJob *mxv1beta1.MXJob, typ string, pendingPods, activePods, succeededPods, failedPods int32, t *testing.T) { 68 | var index int32 69 | for _, pod := range NewPodList(pendingPods, v1.PodPending, mxJob, typ, index, t) { 70 | if err := podIndexer.Add(pod); err != nil { 71 | t.Errorf("%s: unexpected error when adding pod %v", mxJob.Name, err) 72 | } 73 | } 74 | index += pendingPods 75 | for _, pod := range NewPodList(activePods, v1.PodRunning, mxJob, typ, index, t) { 76 | if err := podIndexer.Add(pod); err != nil { 77 | t.Errorf("%s: unexpected error when adding pod %v", mxJob.Name, err) 78 | } 79 | } 80 | index += activePods 81 | for _, pod := range NewPodList(succeededPods, v1.PodSucceeded, mxJob, typ, index, t) { 82 | if err := podIndexer.Add(pod); err != nil { 83 | t.Errorf("%s: unexpected error when adding pod %v", mxJob.Name, err) 84 | } 85 | } 86 | index += succeededPods 87 | for _, pod := range NewPodList(failedPods, v1.PodFailed, mxJob, typ, index, t) { 88 | if err := podIndexer.Add(pod); err != nil { 89 | t.Errorf("%s: unexpected error when adding pod %v", mxJob.Name, err) 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /pkg/common/util/v1beta1/testutil/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "fmt" 19 | "testing" 20 | 21 | "k8s.io/api/core/v1" 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | "k8s.io/client-go/tools/cache" 24 | 25 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 26 | ) 27 | 28 | func NewBaseService(name string, mxJob *mxv1beta1.MXJob, t *testing.T) *v1.Service { 29 | return &v1.Service{ 30 | ObjectMeta: metav1.ObjectMeta{ 31 | Name: name, 32 | Labels: GenLabels(mxJob.Name), 33 | Namespace: mxJob.Namespace, 34 | OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(mxJob, controllerKind)}, 35 | }, 36 | } 37 | } 38 | 39 | func NewService(mxJob *mxv1beta1.MXJob, typ string, index int, t *testing.T) *v1.Service { 40 | service := NewBaseService(fmt.Sprintf("%s-%d", typ, index), mxJob, t) 41 | service.Labels[mxReplicaTypeLabel] = typ 42 | service.Labels[mxReplicaIndexLabel] = fmt.Sprintf("%d", index) 43 | return service 44 | } 45 | 46 | // NewServiceList creates count pods with the given phase for the given mxJob 47 | func NewServiceList(count int32, mxJob *mxv1beta1.MXJob, typ string, t *testing.T) []*v1.Service { 48 | services := []*v1.Service{} 49 | for i := int32(0); i < count; i++ { 50 | newService := NewService(mxJob, typ, int(i), t) 51 | services = append(services, newService) 52 | } 53 | return services 54 | } 55 | 56 | func SetServices(serviceIndexer cache.Indexer, mxJob *mxv1beta1.MXJob, typ string, activeWorkerServices int32, t *testing.T) { 57 | for _, service := range NewServiceList(activeWorkerServices, mxJob, typ, t) { 58 | if err := serviceIndexer.Add(service); err != nil { 59 | t.Errorf("unexpected error when adding service %v", err) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /pkg/common/util/v1beta1/testutil/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "encoding/json" 19 | "strings" 20 | "testing" 21 | 22 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 23 | "k8s.io/api/core/v1" 24 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 26 | "k8s.io/client-go/tools/cache" 27 | ) 28 | 29 | const ( 30 | LabelGroupName = "group_name" 31 | LabelMXJobName = "mxnet_job_name" 32 | ) 33 | 34 | var ( 35 | // KeyFunc is the short name to DeletionHandlingMetaNamespaceKeyFunc. 36 | // IndexerInformer uses a delta queue, therefore for deletes we have to use this 37 | // key function but it should be just fine for non delete events. 38 | KeyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc 39 | GroupName = mxv1beta1.GroupName 40 | ) 41 | 42 | func GenLabels(jobName string) map[string]string { 43 | return map[string]string{ 44 | LabelGroupName: GroupName, 45 | LabelMXJobName: strings.Replace(jobName, "/", "-", -1), 46 | } 47 | } 48 | 49 | func GenOwnerReference(mxjob *mxv1beta1.MXJob) *metav1.OwnerReference { 50 | boolPtr := func(b bool) *bool { return &b } 51 | controllerRef := &metav1.OwnerReference{ 52 | APIVersion: mxv1beta1.SchemeGroupVersion.String(), 53 | Kind: mxv1beta1.Kind, 54 | Name: mxjob.Name, 55 | UID: mxjob.UID, 56 | BlockOwnerDeletion: boolPtr(true), 57 | Controller: boolPtr(true), 58 | } 59 | 60 | return controllerRef 61 | } 62 | 63 | // ConvertMXJobToUnstructured uses JSON to convert MXJob to Unstructured. 64 | func ConvertMXJobToUnstructured(mxJob *mxv1beta1.MXJob) (*unstructured.Unstructured, error) { 65 | var unstructured unstructured.Unstructured 66 | b, err := json.Marshal(mxJob) 67 | if err != nil { 68 | return nil, err 69 | } 70 | 71 | if err := json.Unmarshal(b, &unstructured); err != nil { 72 | return nil, err 73 | } 74 | return &unstructured, nil 75 | } 76 | 77 | func GetKey(mxJob *mxv1beta1.MXJob, t *testing.T) string { 78 | key, err := KeyFunc(mxJob) 79 | if err != nil { 80 | t.Errorf("Unexpected error getting key for job %v: %v", mxJob.Name, err) 81 | return "" 82 | } 83 | return key 84 | } 85 | 86 | func CheckCondition(mxJob *mxv1beta1.MXJob, condition mxv1beta1.MXJobConditionType, reason string) bool { 87 | for _, v := range mxJob.Status.Conditions { 88 | if v.Type == condition && v.Status == v1.ConditionTrue && v.Reason == reason { 89 | return true 90 | } 91 | } 92 | return false 93 | } 94 | -------------------------------------------------------------------------------- /pkg/common/util/v1beta1/unstructured/informer.go: -------------------------------------------------------------------------------- 1 | // Package unstructured is the package for unstructured informer, 2 | // which is from https://github.com/argoproj/argo/blob/master/util/unstructured/unstructured.go 3 | package unstructured 4 | 5 | import ( 6 | "time" 7 | 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 10 | "k8s.io/apimachinery/pkg/runtime" 11 | "k8s.io/apimachinery/pkg/runtime/schema" 12 | "k8s.io/apimachinery/pkg/watch" 13 | "k8s.io/client-go/dynamic" 14 | "k8s.io/client-go/tools/cache" 15 | 16 | informer "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/mxnet/v1beta1" 17 | lister "github.com/kubeflow/mxnet-operator/pkg/client/listers/mxnet/v1beta1" 18 | ) 19 | 20 | type UnstructuredInformer struct { 21 | informer cache.SharedIndexInformer 22 | } 23 | 24 | func NewMXJobInformer(resource schema.GroupVersionResource, client dynamic.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) informer.MXJobInformer { 25 | return &UnstructuredInformer{ 26 | informer: newUnstructuredInformer(resource, client, namespace, resyncPeriod, indexers), 27 | } 28 | } 29 | 30 | func (f *UnstructuredInformer) Informer() cache.SharedIndexInformer { 31 | return f.informer 32 | } 33 | 34 | func (f *UnstructuredInformer) Lister() lister.MXJobLister { 35 | return lister.NewMXJobLister(f.Informer().GetIndexer()) 36 | } 37 | 38 | // newUnstructuredInformer constructs a new informer for Unstructured type. 39 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 40 | // one. This reduces memory footprint and number of connections to the server. 41 | func newUnstructuredInformer(resource schema.GroupVersionResource, client dynamic.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 42 | return newFilteredUnstructuredInformer(resource, client, namespace, resyncPeriod, indexers) 43 | } 44 | 45 | // newFilteredUnstructuredInformer constructs a new informer for Unstructured type. 46 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 47 | // one. This reduces memory footprint and number of connections to the server. 48 | func newFilteredUnstructuredInformer(resource schema.GroupVersionResource, client dynamic.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 49 | return cache.NewSharedIndexInformer( 50 | &cache.ListWatch{ 51 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 52 | return client.Resource(resource).List(options) 53 | }, 54 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 55 | return client.Resource(resource).Watch(options) 56 | }, 57 | }, 58 | &unstructured.Unstructured{}, 59 | resyncPeriod, 60 | indexers, 61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/controller.v1/mxnet/controller_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package controller provides a Kubernetes controller for a MXJob resource. 16 | package mxnet 17 | 18 | import ( 19 | "testing" 20 | "time" 21 | 22 | "github.com/kubeflow/common/pkg/controller.v1/control" 23 | batchv1beta1 "volcano.sh/volcano/pkg/apis/scheduling/v1beta1" 24 | volcanoclient "volcano.sh/volcano/pkg/client/clientset/versioned" 25 | 26 | v1 "k8s.io/api/core/v1" 27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 | kubeinformers "k8s.io/client-go/informers" 29 | kubeclientset "k8s.io/client-go/kubernetes" 30 | "k8s.io/client-go/rest" 31 | "k8s.io/kubernetes/pkg/controller" 32 | 33 | "github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1/app/options" 34 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 35 | mxjobclientset "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned" 36 | mxjobinformers "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions" 37 | "github.com/kubeflow/mxnet-operator/pkg/common/util/v1/testutil" 38 | ) 39 | 40 | func newMXController( 41 | config *rest.Config, 42 | kubeClientSet kubeclientset.Interface, 43 | mxJobClientSet mxjobclientset.Interface, 44 | volcanoClientSet volcanoclient.Interface, 45 | resyncPeriod controller.ResyncPeriodFunc, 46 | option options.ServerOption, 47 | ) ( 48 | *MXController, 49 | kubeinformers.SharedInformerFactory, mxjobinformers.SharedInformerFactory, 50 | ) { 51 | kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClientSet, resyncPeriod()) 52 | mxJobInformerFactory := mxjobinformers.NewSharedInformerFactory(mxJobClientSet, resyncPeriod()) 53 | 54 | mxJobInformer := NewUnstructuredMXJobInformer(config, metav1.NamespaceAll) 55 | 56 | ctr := NewMXController(mxJobInformer, kubeClientSet, mxJobClientSet, volcanoClientSet, kubeInformerFactory, mxJobInformerFactory, option) 57 | ctr.PodControl = &control.FakePodControl{} 58 | ctr.ServiceControl = &control.FakeServiceControl{} 59 | return ctr, kubeInformerFactory, mxJobInformerFactory 60 | } 61 | 62 | func TestRun(t *testing.T) { 63 | // Prepare the clientset and controller for the test. 64 | kubeClientSet := kubeclientset.NewForConfigOrDie(&rest.Config{ 65 | Host: "", 66 | ContentConfig: rest.ContentConfig{ 67 | GroupVersion: &v1.SchemeGroupVersion, 68 | }, 69 | }, 70 | ) 71 | // Prepare the volcano clientset and controller for the test. 72 | volcanoClientSet := volcanoclient.NewForConfigOrDie(&rest.Config{ 73 | Host: "", 74 | ContentConfig: rest.ContentConfig{ 75 | GroupVersion: &batchv1beta1.SchemeGroupVersion, 76 | }, 77 | }, 78 | ) 79 | config := &rest.Config{ 80 | Host: "", 81 | ContentConfig: rest.ContentConfig{ 82 | GroupVersion: &mxv1.SchemeGroupVersion, 83 | }, 84 | } 85 | mxJobClientSet := mxjobclientset.NewForConfigOrDie(config) 86 | ctr, _, _ := newMXController(config, kubeClientSet, mxJobClientSet, volcanoClientSet, controller.NoResyncPeriodFunc, options.ServerOption{}) 87 | ctr.mxJobInformerSynced = testutil.AlwaysReady 88 | ctr.PodInformerSynced = testutil.AlwaysReady 89 | ctr.ServiceInformerSynced = testutil.AlwaysReady 90 | 91 | stopCh := make(chan struct{}) 92 | go func() { 93 | // It is a hack to let the controller stop to run without errors. 94 | // We can not just send a struct to stopCh because there are multiple 95 | // receivers in controller.Run. 96 | time.Sleep(testutil.SleepInterval) 97 | stopCh <- struct{}{} 98 | }() 99 | err := ctr.Run(testutil.ThreadCount, stopCh) 100 | if err != nil { 101 | t.Errorf("Failed to run: %v", err) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /pkg/controller.v1/mxnet/informer.go: -------------------------------------------------------------------------------- 1 | package mxnet 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | log "github.com/sirupsen/logrus" 8 | metav1unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 9 | "k8s.io/apimachinery/pkg/runtime" 10 | "k8s.io/apimachinery/pkg/runtime/schema" 11 | "k8s.io/client-go/dynamic" 12 | restclientset "k8s.io/client-go/rest" 13 | "k8s.io/client-go/tools/cache" 14 | 15 | mxlogger "github.com/kubeflow/common/pkg/util" 16 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 17 | "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/validation" 18 | mxjobinformers "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions" 19 | mxjobinformersv1 "github.com/kubeflow/mxnet-operator/pkg/client/informers/externalversions/mxnet/v1" 20 | "github.com/kubeflow/mxnet-operator/pkg/common/util/v1/unstructured" 21 | ) 22 | 23 | const ( 24 | resyncPeriod = 30 * time.Second 25 | failedMarshalMsg = "Failed to marshal the object to MXJob: %v" 26 | ) 27 | 28 | var ( 29 | errGetFromKey = fmt.Errorf("failed to get MXJob from key") 30 | errNotExists = fmt.Errorf("the object is not found") 31 | errFailedMarshal = fmt.Errorf("failed to marshal the object to MXJob") 32 | errWrongJobMode = fmt.Errorf("failed to inspect jobMode, maybe mxReplicaSpecs has a member which is not belong to this jobMode or misses one") 33 | ) 34 | 35 | func NewUnstructuredMXJobInformer(restConfig *restclientset.Config, namespace string) mxjobinformersv1.MXJobInformer { 36 | dclient, err := dynamic.NewForConfig(restConfig) 37 | if err != nil { 38 | panic(err) 39 | } 40 | resource := schema.GroupVersionResource{ 41 | Group: mxv1.GroupName, 42 | Version: mxv1.GroupVersion, 43 | Resource: mxv1.Plural, 44 | } 45 | informer := unstructured.NewMXJobInformer( 46 | resource, 47 | dclient, 48 | namespace, 49 | resyncPeriod, 50 | cache.Indexers{}, 51 | ) 52 | return informer 53 | } 54 | 55 | // NewMXJobInformer returns MXJobInformer from the given factory. 56 | func (tc *MXController) NewMXJobInformer(mxJobInformerFactory mxjobinformers.SharedInformerFactory) mxjobinformersv1.MXJobInformer { 57 | return mxJobInformerFactory.Kubeflow().V1().MXJobs() 58 | } 59 | 60 | func (tc *MXController) getMXJobFromName(namespace, name string) (*mxv1.MXJob, error) { 61 | key := fmt.Sprintf("%s/%s", namespace, name) 62 | return tc.getMXJobFromKey(key) 63 | } 64 | 65 | func (tc *MXController) getMXJobFromKey(key string) (*mxv1.MXJob, error) { 66 | // Check if the key exists. 67 | obj, exists, err := tc.mxJobInformer.GetIndexer().GetByKey(key) 68 | logger := mxlogger.LoggerForKey(key) 69 | if err != nil { 70 | logger.Errorf("Failed to get MXJob '%s' from informer index: %+v", key, err) 71 | return nil, errGetFromKey 72 | } 73 | if !exists { 74 | // This happens after a mxjob was deleted, but the work queue still had an entry for it. 75 | return nil, errNotExists 76 | } 77 | 78 | mxjob, err := mxJobFromUnstructured(obj) 79 | if err != nil { 80 | return nil, err 81 | } 82 | return mxjob, nil 83 | } 84 | 85 | func mxJobFromUnstructured(obj interface{}) (*mxv1.MXJob, error) { 86 | // Check if the spec is valid. 87 | un, ok := obj.(*metav1unstructured.Unstructured) 88 | if !ok { 89 | log.Errorf("The object in index is not an unstructured; %+v", obj) 90 | return nil, errGetFromKey 91 | } 92 | var mxjob mxv1.MXJob 93 | err := runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &mxjob) 94 | logger := mxlogger.LoggerForUnstructured(un, mxv1.Kind) 95 | if err != nil { 96 | logger.Errorf(failedMarshalMsg, err) 97 | return nil, errFailedMarshal 98 | } 99 | // This is a simple validation for MXJob to close 100 | // TODO(gaocegege): Add more validation here. 101 | err = validation.ValidateV1MXJobSpec(&mxjob.Spec) 102 | if err != nil { 103 | logger.Errorf(failedMarshalMsg, err) 104 | return nil, errFailedMarshal 105 | } 106 | return &mxjob, nil 107 | } 108 | 109 | func unstructuredFromMXJob(obj interface{}, mxJob *mxv1.MXJob) error { 110 | un, ok := obj.(*metav1unstructured.Unstructured) 111 | logger := mxlogger.LoggerForJob(mxJob) 112 | if !ok { 113 | logger.Warn("The object in index isn't type Unstructured") 114 | return errGetFromKey 115 | } 116 | 117 | var err error 118 | un.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(mxJob) 119 | if err != nil { 120 | logger.Error("The MXJob convert failed") 121 | return err 122 | } 123 | return nil 124 | 125 | } 126 | -------------------------------------------------------------------------------- /pkg/controller.v1/mxnet/job_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package mxnet 16 | 17 | import ( 18 | "context" 19 | "testing" 20 | 21 | batchv1beta1 "volcano.sh/volcano/pkg/apis/scheduling/v1beta1" 22 | volcanoclient "volcano.sh/volcano/pkg/client/clientset/versioned" 23 | 24 | v1 "k8s.io/api/core/v1" 25 | kubeclientset "k8s.io/client-go/kubernetes" 26 | "k8s.io/client-go/rest" 27 | "k8s.io/kubernetes/pkg/controller" 28 | 29 | "github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1/app/options" 30 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 31 | mxjobclientset "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned" 32 | "github.com/kubeflow/mxnet-operator/pkg/common/util/v1/testutil" 33 | ) 34 | 35 | func TestAddMXJob(t *testing.T) { 36 | // Prepare the clientset and controller for the test. 37 | kubeClientSet := kubeclientset.NewForConfigOrDie(&rest.Config{ 38 | Host: "", 39 | ContentConfig: rest.ContentConfig{ 40 | GroupVersion: &v1.SchemeGroupVersion, 41 | }, 42 | }, 43 | ) 44 | // Prepare the volcano clientset and controller for the test. 45 | volcanoClientSet := volcanoclient.NewForConfigOrDie(&rest.Config{ 46 | Host: "", 47 | ContentConfig: rest.ContentConfig{ 48 | GroupVersion: &batchv1beta1.SchemeGroupVersion, 49 | }, 50 | }, 51 | ) 52 | config := &rest.Config{ 53 | Host: "", 54 | ContentConfig: rest.ContentConfig{ 55 | GroupVersion: &mxv1.SchemeGroupVersion, 56 | }, 57 | } 58 | mxJobClientSet := mxjobclientset.NewForConfigOrDie(config) 59 | ctr, _, _ := newMXController(config, kubeClientSet, mxJobClientSet, volcanoClientSet, controller.NoResyncPeriodFunc, options.ServerOption{}) 60 | ctr.mxJobInformerSynced = testutil.AlwaysReady 61 | ctr.PodInformerSynced = testutil.AlwaysReady 62 | ctr.ServiceInformerSynced = testutil.AlwaysReady 63 | mxJobIndexer := ctr.mxJobInformer.GetIndexer() 64 | 65 | stopCh := make(chan struct{}) 66 | run := func(ctx context.Context) { 67 | if err := ctr.Run(testutil.ThreadCount, stopCh); err != nil { 68 | t.Errorf("Failed to run MXNet Controller!") 69 | } 70 | } 71 | ctx, cancel := context.WithCancel(context.Background()) 72 | go run(ctx) 73 | 74 | var key string 75 | syncChan := make(chan string) 76 | ctr.syncHandler = func(mxJobKey string) (bool, error) { 77 | key = mxJobKey 78 | <-syncChan 79 | return true, nil 80 | } 81 | ctr.updateStatusHandler = func(mxjob *mxv1.MXJob) error { 82 | return nil 83 | } 84 | ctr.deleteMXJobHandler = func(mxjob *mxv1.MXJob) error { 85 | return nil 86 | } 87 | 88 | mxJob := testutil.NewMXJob(1, 0) 89 | unstructured, err := testutil.ConvertMXJobToUnstructured(mxJob) 90 | if err != nil { 91 | t.Errorf("Failed to convert the MXJob to Unstructured: %v", err) 92 | } 93 | if err := mxJobIndexer.Add(unstructured); err != nil { 94 | t.Errorf("Failed to add mxjob to mxJobIndexer: %v", err) 95 | } 96 | ctr.addMXJob(unstructured) 97 | 98 | syncChan <- "sync" 99 | if key != testutil.GetKey(mxJob, t) { 100 | t.Errorf("Failed to enqueue the MXJob %s: expected %s, got %s", mxJob.Name, testutil.GetKey(mxJob, t), key) 101 | } 102 | cancel() 103 | } 104 | -------------------------------------------------------------------------------- /pkg/controller.v1/mxnet/mxnet.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package controller provides a Kubernetes controller for a MXJob resource. 16 | package mxnet 17 | 18 | import ( 19 | "fmt" 20 | "strconv" 21 | "strings" 22 | 23 | "github.com/kubeflow/common/pkg/controller.v1/common" 24 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 25 | ) 26 | 27 | const ( 28 | // Label is used as tunerServerKey, it's designed for tvm auto-tuning. 29 | mxJobTunerServerKey = "tuner-server-key" 30 | ) 31 | 32 | // MXConfig is a struct representing the distributed Mxnet config. 33 | // This struct is turned into an environment variable MX_CONFIG 34 | // which is used by Mxnet processes to configure themselves. 35 | type MXConfig struct { 36 | // Cluster represents a Mxnet ClusterSpec. 37 | Cluster ClusterSpec `json:"cluster"` 38 | // Labels include all label of task. 39 | Labels LabelsSpec `json:"labels"` 40 | // Task include information of current node. 41 | Task TaskSpec `json:"task"` 42 | } 43 | 44 | // ClusterSpec represents a cluster Mxnet specification. 45 | type ClusterSpec map[string][]UrlPort 46 | 47 | type UrlPort struct { 48 | Url string `json:"url"` 49 | Port int `json:"port"` 50 | } 51 | 52 | // LabelsSpec represents a label specification. 53 | type LabelsSpec map[string]string 54 | 55 | // TaskSpec is the specification for a task (server or worker ...) of the MXJob. 56 | type TaskSpec struct { 57 | Type string `json:"type"` 58 | Index int `json:"index"` 59 | } 60 | 61 | func genMXConfig(mxjob *mxv1.MXJob, rtype, index string) (MXConfig, error) { 62 | // Configure the MXCONFIG environment variable. 63 | i, err := strconv.ParseInt(index, 0, 32) 64 | if err != nil { 65 | return MXConfig{}, err 66 | } 67 | 68 | cluster, err := genClusterSpec(mxjob) 69 | if err != nil { 70 | return MXConfig{}, err 71 | } 72 | 73 | labels, err := genLabelsSpec(mxjob) 74 | if err != nil { 75 | return MXConfig{}, err 76 | } 77 | 78 | mxConfig := MXConfig{ 79 | Cluster: cluster, 80 | Labels: labels, 81 | Task: TaskSpec{ 82 | Type: rtype, 83 | Index: int(i), 84 | }, 85 | } 86 | 87 | return mxConfig, nil 88 | } 89 | 90 | // genClusterSpec will generate ClusterSpec. 91 | func genClusterSpec(mxjob *mxv1.MXJob) (ClusterSpec, error) { 92 | clusterSpec := make(ClusterSpec) 93 | 94 | for rtype, spec := range mxjob.Spec.MXReplicaSpecs { 95 | rt := strings.ToLower(string(rtype)) 96 | replicaNames := make([]UrlPort, 0, *spec.Replicas) 97 | 98 | port, err := GetPortFromMXJob(mxjob, rtype) 99 | if err != nil { 100 | return nil, err 101 | } 102 | for i := int32(0); i < *spec.Replicas; i++ { 103 | host := UrlPort{ 104 | Url: common.GenGeneralName(mxjob.Name, rt, fmt.Sprintf("%d", i)), 105 | Port: int(port), 106 | } 107 | replicaNames = append(replicaNames, host) 108 | } 109 | 110 | clusterSpec[rt] = replicaNames 111 | } 112 | 113 | return clusterSpec, nil 114 | } 115 | 116 | // genLabelsSpec will generate LabelsSpec. 117 | func genLabelsSpec(mxjob *mxv1.MXJob) (LabelsSpec, error) { 118 | labelsSpec := make(LabelsSpec) 119 | 120 | for rtype, spec := range mxjob.Spec.MXReplicaSpecs { 121 | rt := strings.ToLower(string(rtype)) 122 | 123 | labelsSpec[rt] = spec.Template.Annotations[mxJobTunerServerKey] 124 | } 125 | 126 | return labelsSpec, nil 127 | } 128 | -------------------------------------------------------------------------------- /pkg/controller.v1/mxnet/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package controller provides a Kubernetes controller for a MXJob resource. 16 | package mxnet 17 | 18 | import ( 19 | "fmt" 20 | 21 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 22 | corev1 "k8s.io/api/core/v1" 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "k8s.io/apimachinery/pkg/labels" 25 | ) 26 | 27 | func (tc *MXController) GetServicesForJob(job interface{}) ([]*corev1.Service, error) { 28 | mxJob, ok := job.(*mxv1.MXJob) 29 | if !ok { 30 | return nil, fmt.Errorf("%v is not a type of MXJob", mxJob) 31 | } 32 | 33 | //log := mxlogger.LoggerForJob(mxJob) 34 | // List all services to include those that don't match the selector anymore 35 | // but have a ControllerRef pointing to this controller. 36 | 37 | labelSelector := metav1.LabelSelector{MatchLabels: tc.JobController.GenLabels(mxJob.Name)} 38 | opts := metav1.ListOptions{ 39 | LabelSelector: labels.Set(labelSelector.MatchLabels).String(), 40 | } 41 | svclist, err := tc.KubeClientSet.CoreV1().Services(mxJob.Namespace).List(opts) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return convertServiceList(svclist.Items), nil 46 | } 47 | 48 | // convertServiceList convert service list to service point list 49 | func convertServiceList(list []corev1.Service) []*corev1.Service { 50 | if list == nil { 51 | return nil 52 | } 53 | ret := make([]*corev1.Service, 0, len(list)) 54 | for i := range list { 55 | ret = append(ret, &list[i]) 56 | } 57 | return ret 58 | } 59 | -------------------------------------------------------------------------------- /pkg/controller.v1/mxnet/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package mxnet 16 | 17 | import ( 18 | "fmt" 19 | 20 | commonv1 "github.com/kubeflow/common/pkg/apis/common/v1" 21 | 22 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 23 | ) 24 | 25 | var ( 26 | errPortNotFound = fmt.Errorf("failed to found the port") 27 | ) 28 | 29 | // GetPortFromMXJob gets the port of mxnet container. 30 | func GetPortFromMXJob(mxJob *mxv1.MXJob, rtype commonv1.ReplicaType) (int32, error) { 31 | containers := mxJob.Spec.MXReplicaSpecs[rtype].Template.Spec.Containers 32 | for _, container := range containers { 33 | if container.Name == mxv1.DefaultContainerName { 34 | ports := container.Ports 35 | for _, port := range ports { 36 | if port.Name == mxv1.DefaultPortName { 37 | return port.ContainerPort, nil 38 | } 39 | } 40 | } 41 | } 42 | return -1, errPortNotFound 43 | } 44 | 45 | func ContainSchedulerSpec(mxJob *mxv1.MXJob) bool { 46 | if _, ok := mxJob.Spec.MXReplicaSpecs[mxv1.MXReplicaTypeScheduler]; ok { 47 | return true 48 | } 49 | return false 50 | } 51 | -------------------------------------------------------------------------------- /pkg/controller.v1/mxnet/util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package mxnet 16 | 17 | import ( 18 | "testing" 19 | 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/types" 22 | 23 | mxv1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1" 24 | "github.com/kubeflow/mxnet-operator/pkg/common/util/v1/testutil" 25 | ) 26 | 27 | func TestGenOwnerReference(t *testing.T) { 28 | testName := "test-mxjob" 29 | testUID := types.UID("test-UID") 30 | mxJob := &mxv1.MXJob{ 31 | ObjectMeta: metav1.ObjectMeta{ 32 | Name: testName, 33 | UID: testUID, 34 | }, 35 | } 36 | 37 | ref := testutil.GenOwnerReference(mxJob) 38 | if ref.UID != testUID { 39 | t.Errorf("Expected UID %s, got %s", testUID, ref.UID) 40 | } 41 | if ref.Name != testName { 42 | t.Errorf("Expected Name %s, got %s", testName, ref.Name) 43 | } 44 | if ref.APIVersion != mxv1.SchemeGroupVersion.String() { 45 | t.Errorf("Expected APIVersion %s, got %s", mxv1.SchemeGroupVersion.String(), ref.APIVersion) 46 | } 47 | } 48 | 49 | func TestGenLabels(t *testing.T) { 50 | testKey := "test/key" 51 | expctedKey := "test-key" 52 | 53 | labels := testutil.GenLabels(testKey) 54 | 55 | if labels[labelMXJobName] != expctedKey { 56 | t.Errorf("Expected %s %s, got %s", labelMXJobName, expctedKey, labels[labelMXJobName]) 57 | } 58 | if labels[labelGroupName] != mxv1.GroupName { 59 | t.Errorf("Expected %s %s, got %s", labelGroupName, mxv1.GroupName, labels[labelGroupName]) 60 | } 61 | } 62 | 63 | func TestConvertMXJobToUnstructured(t *testing.T) { 64 | testName := "test-mxjob" 65 | testUID := types.UID("test-UID") 66 | mxJob := &mxv1.MXJob{ 67 | TypeMeta: metav1.TypeMeta{ 68 | Kind: mxv1.Kind, 69 | }, 70 | ObjectMeta: metav1.ObjectMeta{ 71 | Name: testName, 72 | UID: testUID, 73 | }, 74 | } 75 | 76 | _, err := testutil.ConvertMXJobToUnstructured(mxJob) 77 | if err != nil { 78 | t.Errorf("Expected error to be nil while got %v", err) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /pkg/controller.v1beta1/mxnet/mxnet.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package controller provides a Kubernetes controller for a MXJob resource. 16 | package mxnet 17 | 18 | import ( 19 | "fmt" 20 | "strconv" 21 | "strings" 22 | 23 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 24 | "github.com/kubeflow/tf-operator/pkg/common/jobcontroller" 25 | ) 26 | 27 | // MXConfig is a struct representing the distributed Mxnet config. 28 | // This struct is turned into an environment variable MX_CONFIG 29 | // which is used by Mxnet processes to configure themselves. 30 | type MXConfig struct { 31 | // Cluster represents a Mxnet ClusterSpec. 32 | Cluster ClusterSpec `json:"cluster"` 33 | // Labels include all label of task. 34 | Labels LabelsSpec `json:"labels"` 35 | // Task include information of current node. 36 | Task TaskSpec `json:"task"` 37 | } 38 | 39 | // ClusterSpec represents a cluster Mxnet specification. 40 | type ClusterSpec map[string][]Url_Port 41 | 42 | type Url_Port struct { 43 | Url string `json:"url"` 44 | Port int `json:"port"` 45 | } 46 | 47 | // LabelsSpec represents a label specification. 48 | type LabelsSpec map[string]string 49 | 50 | // TaskSpec is the specification for a task (server or worker ...) of the MXJob. 51 | type TaskSpec struct { 52 | Type string `json:"type"` 53 | Index int `json:"index"` 54 | } 55 | 56 | func genMXConfig(mxjob *mxv1beta1.MXJob, rtype, index string) (MXConfig, error) { 57 | // Configure the MXCONFIG environment variable. 58 | i, err := strconv.ParseInt(index, 0, 32) 59 | if err != nil { 60 | return MXConfig{}, err 61 | } 62 | 63 | cluster, err := genClusterSpec(mxjob) 64 | if err != nil { 65 | return MXConfig{}, err 66 | } 67 | 68 | labels, err := genLabelsSpec(mxjob) 69 | if err != nil { 70 | return MXConfig{}, err 71 | } 72 | 73 | mxConfig := MXConfig{ 74 | Cluster: cluster, 75 | Labels: labels, 76 | Task: TaskSpec{ 77 | Type: rtype, 78 | Index: int(i), 79 | }, 80 | } 81 | 82 | return mxConfig, nil 83 | } 84 | 85 | // genClusterSpec will generate ClusterSpec. 86 | func genClusterSpec(mxjob *mxv1beta1.MXJob) (ClusterSpec, error) { 87 | clusterSpec := make(ClusterSpec) 88 | 89 | for rtype, spec := range mxjob.Spec.MXReplicaSpecs { 90 | rt := strings.ToLower(string(rtype)) 91 | replicaNames := make([]Url_Port, 0, *spec.Replicas) 92 | 93 | port, err := GetPortFromMXJob(mxjob, rtype) 94 | if err != nil { 95 | return nil, err 96 | } 97 | for i := int32(0); i < *spec.Replicas; i++ { 98 | host := Url_Port{ 99 | Url: jobcontroller.GenGeneralName(mxjob.Name, rt, fmt.Sprintf("%d", i)), 100 | Port: int(port), 101 | } 102 | replicaNames = append(replicaNames, host) 103 | } 104 | 105 | clusterSpec[rt] = replicaNames 106 | } 107 | 108 | return clusterSpec, nil 109 | } 110 | 111 | // genLabelsSpec will generate LabelsSpec. 112 | func genLabelsSpec(mxjob *mxv1beta1.MXJob) (LabelsSpec, error) { 113 | labelsSpec := make(LabelsSpec) 114 | 115 | for rtype, spec := range mxjob.Spec.MXReplicaSpecs { 116 | rt := strings.ToLower(string(rtype)) 117 | 118 | labelsSpec[rt] = spec.Label 119 | } 120 | 121 | return labelsSpec, nil 122 | } 123 | -------------------------------------------------------------------------------- /pkg/controller.v1beta1/mxnet/service_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package controller provides a Kubernetes controller for a MXJob resource. 16 | package mxnet 17 | 18 | import ( 19 | "context" 20 | "testing" 21 | 22 | "k8s.io/api/core/v1" 23 | kubeclientset "k8s.io/client-go/kubernetes" 24 | "k8s.io/client-go/rest" 25 | "k8s.io/kubernetes/pkg/controller" 26 | 27 | "github.com/kubeflow/mxnet-operator/cmd/mxnet-operator.v1beta1/app/options" 28 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 29 | mxjobclientset "github.com/kubeflow/mxnet-operator/pkg/client/clientset/versioned" 30 | "github.com/kubeflow/mxnet-operator/pkg/common/util/v1beta1/testutil" 31 | batchv1alpha1 "github.com/kubernetes-sigs/kube-batch/pkg/apis/scheduling/v1alpha1" 32 | kubebatchclient "github.com/kubernetes-sigs/kube-batch/pkg/client/clientset/versioned" 33 | ) 34 | 35 | func TestAddService(t *testing.T) { 36 | // Prepare the clientset and controller for the test. 37 | kubeClientSet := kubeclientset.NewForConfigOrDie(&rest.Config{ 38 | Host: "", 39 | ContentConfig: rest.ContentConfig{ 40 | GroupVersion: &v1.SchemeGroupVersion, 41 | }, 42 | }, 43 | ) 44 | // Prepare the kube-batch clientset and controller for the test. 45 | kubeBatchClientSet := kubebatchclient.NewForConfigOrDie(&rest.Config{ 46 | Host: "", 47 | ContentConfig: rest.ContentConfig{ 48 | GroupVersion: &batchv1alpha1.SchemeGroupVersion, 49 | }, 50 | }, 51 | ) 52 | config := &rest.Config{ 53 | Host: "", 54 | ContentConfig: rest.ContentConfig{ 55 | GroupVersion: &mxv1beta1.SchemeGroupVersion, 56 | }, 57 | } 58 | mxJobClientSet := mxjobclientset.NewForConfigOrDie(config) 59 | ctr, _, _ := newMXController(config, kubeClientSet, mxJobClientSet, kubeBatchClientSet, controller.NoResyncPeriodFunc, options.ServerOption{}) 60 | ctr.mxJobInformerSynced = testutil.AlwaysReady 61 | ctr.PodInformerSynced = testutil.AlwaysReady 62 | ctr.ServiceInformerSynced = testutil.AlwaysReady 63 | mxJobIndexer := ctr.mxJobInformer.GetIndexer() 64 | 65 | stopCh := make(chan struct{}) 66 | run := func(ctx context.Context) { 67 | if err := ctr.Run(testutil.ThreadCount, stopCh); err != nil { 68 | t.Errorf("Failed to run MXNet Controller!") 69 | } 70 | } 71 | ctx, cancel := context.WithCancel(context.Background()) 72 | go run(ctx) 73 | var key string 74 | syncChan := make(chan string) 75 | ctr.syncHandler = func(mxJobKey string) (bool, error) { 76 | key = mxJobKey 77 | <-syncChan 78 | return true, nil 79 | } 80 | 81 | mxJob := testutil.NewMXJob(1, 0) 82 | unstructured, err := testutil.ConvertMXJobToUnstructured(mxJob) 83 | if err != nil { 84 | t.Errorf("Failed to convert the MXJob to Unstructured: %v", err) 85 | } 86 | 87 | if err := mxJobIndexer.Add(unstructured); err != nil { 88 | t.Errorf("Failed to add mxjob to mxJobIndexer: %v", err) 89 | } 90 | service := testutil.NewService(mxJob, testutil.LabelWorker, 0, t) 91 | ctr.AddService(service) 92 | 93 | syncChan <- "sync" 94 | if key != testutil.GetKey(mxJob, t) { 95 | t.Errorf("Failed to enqueue the MXJob %s: expected %s, got %s", mxJob.Name, testutil.GetKey(mxJob, t), key) 96 | } 97 | cancel() 98 | } 99 | -------------------------------------------------------------------------------- /pkg/controller.v1beta1/mxnet/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package mxnet 16 | 17 | import ( 18 | "fmt" 19 | 20 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 21 | ) 22 | 23 | var ( 24 | errPortNotFound = fmt.Errorf("failed to found the port") 25 | ) 26 | 27 | // GetPortFromMXJob gets the port of mxnet container. 28 | func GetPortFromMXJob(mxJob *mxv1beta1.MXJob, rtype mxv1beta1.MXReplicaType) (int32, error) { 29 | containers := mxJob.Spec.MXReplicaSpecs[rtype].Template.Spec.Containers 30 | for _, container := range containers { 31 | if container.Name == mxv1beta1.DefaultContainerName { 32 | ports := container.Ports 33 | for _, port := range ports { 34 | if port.Name == mxv1beta1.DefaultPortName { 35 | return port.ContainerPort, nil 36 | } 37 | } 38 | } 39 | } 40 | return -1, errPortNotFound 41 | } 42 | 43 | func ContainSchedulerSpec(mxJob *mxv1beta1.MXJob) bool { 44 | if _, ok := mxJob.Spec.MXReplicaSpecs[mxv1beta1.MXReplicaTypeScheduler]; ok { 45 | return true 46 | } 47 | return false 48 | } 49 | -------------------------------------------------------------------------------- /pkg/controller.v1beta1/mxnet/util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package mxnet 16 | 17 | import ( 18 | "testing" 19 | 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/types" 22 | 23 | mxv1beta1 "github.com/kubeflow/mxnet-operator/pkg/apis/mxnet/v1beta1" 24 | "github.com/kubeflow/mxnet-operator/pkg/common/util/v1beta1/testutil" 25 | ) 26 | 27 | func TestGenOwnerReference(t *testing.T) { 28 | testName := "test-mxjob" 29 | testUID := types.UID("test-UID") 30 | mxJob := &mxv1beta1.MXJob{ 31 | ObjectMeta: metav1.ObjectMeta{ 32 | Name: testName, 33 | UID: testUID, 34 | }, 35 | } 36 | 37 | ref := testutil.GenOwnerReference(mxJob) 38 | if ref.UID != testUID { 39 | t.Errorf("Expected UID %s, got %s", testUID, ref.UID) 40 | } 41 | if ref.Name != testName { 42 | t.Errorf("Expected Name %s, got %s", testName, ref.Name) 43 | } 44 | if ref.APIVersion != mxv1beta1.SchemeGroupVersion.String() { 45 | t.Errorf("Expected APIVersion %s, got %s", mxv1beta1.SchemeGroupVersion.String(), ref.APIVersion) 46 | } 47 | } 48 | 49 | func TestGenLabels(t *testing.T) { 50 | testKey := "test/key" 51 | expctedKey := "test-key" 52 | 53 | labels := testutil.GenLabels(testKey) 54 | 55 | if labels[labelMXJobName] != expctedKey { 56 | t.Errorf("Expected %s %s, got %s", labelMXJobName, expctedKey, labels[labelMXJobName]) 57 | } 58 | if labels[labelGroupName] != mxv1beta1.GroupName { 59 | t.Errorf("Expected %s %s, got %s", labelGroupName, mxv1beta1.GroupName, labels[labelGroupName]) 60 | } 61 | } 62 | 63 | func TestConvertMXJobToUnstructured(t *testing.T) { 64 | testName := "test-mxjob" 65 | testUID := types.UID("test-UID") 66 | mxJob := &mxv1beta1.MXJob{ 67 | TypeMeta: metav1.TypeMeta{ 68 | Kind: mxv1beta1.Kind, 69 | }, 70 | ObjectMeta: metav1.ObjectMeta{ 71 | Name: testName, 72 | UID: testUID, 73 | }, 74 | } 75 | 76 | _, err := testutil.ConvertMXJobToUnstructured(mxJob) 77 | if err != nil { 78 | t.Errorf("Expected error to be nil while got %v", err) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /pkg/util/k8sutil/client.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package k8sutil 14 | 15 | import ( 16 | "fmt" 17 | "net/http" 18 | 19 | mxlogger "github.com/kubeflow/common/pkg/util" 20 | metav1unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | "k8s.io/apimachinery/pkg/runtime/schema" 23 | "k8s.io/apimachinery/pkg/runtime/serializer" 24 | "k8s.io/client-go/kubernetes/scheme" 25 | "k8s.io/client-go/rest" 26 | ) 27 | 28 | // CRDRestClient defines an interface for working with CRDs using the REST client. 29 | // In most cases we want to use the auto-generated clientset for specific CRDs. 30 | // The only exception is when the CRD spec is invalid and we can't parse the type into the corresponding 31 | // go struct. 32 | type CRDClient interface { 33 | // Update a MXJob. 34 | Update(obj *metav1unstructured.Unstructured) error 35 | } 36 | 37 | // CRDRestClient uses the Kubernetes rest interface to talk to the CRD. 38 | type CRDRestClient struct { 39 | restcli *rest.RESTClient 40 | } 41 | 42 | func NewCRDRestClient(version *schema.GroupVersion) (*CRDRestClient, error) { 43 | config, err := GetClusterConfig() 44 | if err != nil { 45 | return nil, err 46 | } 47 | config.GroupVersion = version 48 | config.APIPath = "/apis" 49 | config.ContentType = runtime.ContentTypeJSON 50 | config.NegotiatedSerializer = serializer.WithoutConversionCodecFactory{CodecFactory: scheme.Codecs} 51 | 52 | restcli, err := rest.RESTClientFor(config) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | cli := &CRDRestClient{ 58 | restcli: restcli, 59 | } 60 | return cli, nil 61 | } 62 | 63 | // HttpClient returns the http client used. 64 | func (c *CRDRestClient) Client() *http.Client { 65 | return c.restcli.Client 66 | } 67 | 68 | func (c *CRDRestClient) Update(obj *metav1unstructured.Unstructured, plural string) error { 69 | logger := mxlogger.LoggerForUnstructured(obj, obj.GetKind()) 70 | // TODO(jlewi): Can we just call obj.GetKind() to get the kind? I think that will return the singular 71 | // not plural will that work? 72 | if plural == "" { 73 | logger.Errorf("Could not issue update because plural not set.") 74 | return fmt.Errorf("plural must be set") 75 | } 76 | r := c.restcli.Put().Resource(plural).Namespace(obj.GetNamespace()).Name(obj.GetName()).Body(obj) 77 | _, err := r.DoRaw() 78 | if err != nil { 79 | logger.Errorf("Could not issue update using URL: %v; error; %v", r.URL().String(), err) 80 | } 81 | return err 82 | } 83 | 84 | func (c *CRDRestClient) UpdateStatus(obj *metav1unstructured.Unstructured, plural string) error { 85 | logger := mxlogger.LoggerForUnstructured(obj, obj.GetKind()) 86 | if plural == "" { 87 | logger.Errorf("Could not issue update because plural not set.") 88 | return fmt.Errorf("plural must be set") 89 | } 90 | r := c.restcli.Put().Resource(plural).Namespace(obj.GetNamespace()).Name(obj.GetName()).SubResource("status").Body(obj) 91 | _, err := r.DoRaw() 92 | if err != nil { 93 | logger.Errorf("Could not issue update using URL: %v; error; %v", r.URL().String(), err) 94 | } 95 | return err 96 | } 97 | -------------------------------------------------------------------------------- /pkg/util/k8sutil/k8sutil.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package k8sutil 16 | 17 | import ( 18 | "net" 19 | "os" 20 | 21 | log "github.com/sirupsen/logrus" 22 | 23 | "k8s.io/api/core/v1" 24 | apierrors "k8s.io/apimachinery/pkg/api/errors" 25 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | "k8s.io/client-go/kubernetes" 27 | _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // for gcp auth 28 | "k8s.io/client-go/rest" 29 | "k8s.io/client-go/tools/clientcmd" 30 | ) 31 | 32 | // RecommendedConfigPathEnvVar is a environment variable for path configuration 33 | const RecommendedConfigPathEnvVar = "KUBECONFIG" 34 | 35 | // MustNewKubeClient returns new kubernetes client for cluster configuration 36 | func MustNewKubeClient() kubernetes.Interface { 37 | cfg, err := GetClusterConfig() 38 | if err != nil { 39 | log.Fatal(err) 40 | } 41 | return kubernetes.NewForConfigOrDie(cfg) 42 | } 43 | 44 | // GetClusterConfig obtain the config from the Kube configuration used by kubeconfig, or from k8s cluster. 45 | func GetClusterConfig() (*rest.Config, error) { 46 | if len(os.Getenv(RecommendedConfigPathEnvVar)) > 0 { 47 | // use the current context in kubeconfig 48 | // This is very useful for running locally. 49 | return clientcmd.BuildConfigFromFlags("", os.Getenv(RecommendedConfigPathEnvVar)) 50 | } 51 | 52 | // Work around https://github.com/kubernetes/kubernetes/issues/40973 53 | // See https://github.com/coreos/etcd-operator/issues/731#issuecomment-283804819 54 | if len(os.Getenv("KUBERNETES_SERVICE_HOST")) == 0 { 55 | addrs, err := net.LookupHost("kubernetes.default.svc") 56 | if err != nil { 57 | panic(err) 58 | } 59 | if err := os.Setenv("KUBERNETES_SERVICE_HOST", addrs[0]); err != nil { 60 | return nil, err 61 | } 62 | } 63 | if len(os.Getenv("KUBERNETES_SERVICE_PORT")) == 0 { 64 | if err := os.Setenv("KUBERNETES_SERVICE_PORT", "443"); err != nil { 65 | panic(err) 66 | } 67 | } 68 | return rest.InClusterConfig() 69 | } 70 | 71 | // IsKubernetesResourceAlreadyExistError throws error when kubernetes resources already exist. 72 | func IsKubernetesResourceAlreadyExistError(err error) bool { 73 | return apierrors.IsAlreadyExists(err) 74 | } 75 | 76 | // IsKubernetesResourceNotFoundError throws error when there is no kubernetes resource found. 77 | func IsKubernetesResourceNotFoundError(err error) bool { 78 | return apierrors.IsNotFound(err) 79 | } 80 | 81 | // CascadeDeletOptions are part of garbage collection policy. 82 | // CascadeDeleteOptions deletes the workload after the grace period 83 | func CascadeDeleteOptions(gracePeriodSeconds int64) *metav1.DeleteOptions { 84 | return &metav1.DeleteOptions{ 85 | GracePeriodSeconds: func(t int64) *int64 { return &t }(gracePeriodSeconds), 86 | PropagationPolicy: func() *metav1.DeletionPropagation { 87 | foreground := metav1.DeletePropagationForeground 88 | return &foreground 89 | }(), 90 | } 91 | } 92 | 93 | // FilterActivePods returns pods that have not terminated. 94 | func FilterActivePods(pods []*v1.Pod) []*v1.Pod { 95 | var result []*v1.Pod 96 | for _, p := range pods { 97 | if IsPodActive(p) { 98 | result = append(result, p) 99 | } else { 100 | log.Infof("Ignoring inactive pod %v/%v in state %v, deletion time %v", 101 | p.Namespace, p.Name, p.Status.Phase, p.DeletionTimestamp) 102 | } 103 | } 104 | return result 105 | } 106 | 107 | func IsPodActive(p *v1.Pod) bool { 108 | return v1.PodSucceeded != p.Status.Phase && 109 | v1.PodFailed != p.Status.Phase && 110 | p.DeletionTimestamp == nil 111 | } 112 | 113 | // filterPodCount returns pods based on their phase. 114 | func FilterPodCount(pods []*v1.Pod, phase v1.PodPhase) int32 { 115 | var result int32 116 | for i := range pods { 117 | if phase == pods[i].Status.Phase { 118 | result++ 119 | } 120 | } 121 | return result 122 | } 123 | -------------------------------------------------------------------------------- /pkg/util/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Kubeflow Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package util provides various helper routines. 16 | package util 17 | 18 | import ( 19 | "encoding/json" 20 | "fmt" 21 | "math/rand" 22 | "time" 23 | 24 | log "github.com/sirupsen/logrus" 25 | ) 26 | 27 | const ( 28 | // EnvKubeflowNamespace is a environment variable for namespace when deployed on kubernetes 29 | EnvKubeflowNamespace = "KUBEFLOW_NAMESPACE" 30 | ) 31 | 32 | // Pformat returns a pretty format output of any value that can be marshaled to JSON. 33 | func Pformat(value interface{}) string { 34 | if s, ok := value.(string); ok { 35 | return s 36 | } 37 | valueJSON, err := json.MarshalIndent(value, "", " ") 38 | if err != nil { 39 | log.Warningf("Couldn't pretty format %v, error: %v", value, err) 40 | return fmt.Sprintf("%v", value) 41 | } 42 | return string(valueJSON) 43 | } 44 | 45 | // src is variable initialized with random value. 46 | var src = rand.NewSource(time.Now().UnixNano()) 47 | 48 | const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyz" 49 | const ( 50 | letterIdxBits = 6 // 6 bits to represent a letter index 51 | letterIdxMask = 1<= 0; { 63 | if remain == 0 { 64 | cache, remain = src.Int63(), letterIdxMax 65 | } 66 | if idx := int(cache & letterIdxMask); idx < len(letterBytes) { 67 | b[i] = letterBytes[idx] 68 | i-- 69 | } 70 | cache >>= letterIdxBits 71 | remain-- 72 | } 73 | 74 | return string(b) 75 | } 76 | -------------------------------------------------------------------------------- /pkg/version/version.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package version 14 | 15 | import ( 16 | "fmt" 17 | "os" 18 | "runtime" 19 | ) 20 | 21 | var ( 22 | Version = "v0.1.0-alpha" 23 | GitSHA = "Not provided." 24 | ) 25 | 26 | // PrintVersionAndExit prints versions from the array returned by Info() and exit 27 | func PrintVersionAndExit(apiVersion string) { 28 | for _, i := range Info(apiVersion) { 29 | fmt.Printf("%v\n", i) 30 | } 31 | os.Exit(0) 32 | } 33 | 34 | // Info returns an array of various service versions 35 | func Info(apiVersion string) []string { 36 | return []string{ 37 | fmt.Sprintf("API Version: %s", apiVersion), 38 | fmt.Sprintf("Version: %s", Version), 39 | fmt.Sprintf("Git SHA: %s", GitSHA), 40 | fmt.Sprintf("Go Version: %s", runtime.Version()), 41 | fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH), 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /prow_config.yaml: -------------------------------------------------------------------------------- 1 | workflows: [] 2 | --------------------------------------------------------------------------------