├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build ├── build.sh └── dockerfile │ ├── Dockerfile.edge-controller │ ├── Dockerfile.ote-cc │ ├── Dockerfile.ote-cm │ └── Dockerfile.ote-shim ├── cmd ├── clustercontroller │ ├── app │ │ └── app.go │ └── clustercontroller.go ├── edgecontroller │ ├── app │ │ └── app.go │ └── edgecontroller.go ├── edgehub │ ├── app │ │ └── app.go │ └── edgehub.go ├── k3s_cluster_shim │ ├── app │ │ └── app.go │ └── k3s_cluster_shim.go ├── k8s_cluster_shim │ ├── app │ │ └── app.go │ └── k8s_cluster_shim.go └── ote_controller_manager │ ├── app │ └── app.go │ └── ote_controller_manager.go ├── deployments ├── alertmanager │ └── alertmanager.yml.tpl ├── apply_yml.sh ├── create_yml.sh ├── data-query-server │ └── data-query-server.yml.tpl ├── edge-controller │ └── edge-controller.yml.tpl ├── elasticsearch │ ├── elasticsearch.yml.tpl │ └── elasticsearch.yml.tpl.aarch64 ├── etcd │ ├── etcd.yml.tpl │ └── etcd.yml.tpl.aarch64 ├── fluent-bit │ └── fluent-bit.yml.tpl ├── gpu-metrics-exporter │ └── gpu-metrics-exporter.yml.tpl ├── interface_conf ├── k3s │ ├── config.toml.tmpl │ └── gpu_device_plugin.yml ├── kube-apiserver │ ├── cc-crd.yml.tpl │ ├── edgenode-crd.yml.tpl │ ├── kube-apiserver.yml.tpl │ └── ns.yml.tpl ├── mysql │ ├── mysql.yml.tpl │ └── mysql.yml.tpl.aarch64 ├── node-agent │ └── node-agent.yml.tpl ├── node-exporter │ └── node-exporter.yml.tpl ├── nodes-server │ └── nodes-server.yml.tpl ├── open-api │ └── open-api.yml.tpl ├── ote-cc │ └── ote-cc.yml.tpl ├── ote-cm │ └── ote-cm.yml.tpl ├── ote-k8s-shim │ └── ote-k8s-shim.yml.tpl ├── otectl ├── prometheus │ ├── alerting-rules.yml.tpl │ ├── prometheus.yml.tpl │ └── recording-rules.yml.tpl ├── tiller-proxy │ └── tiller-proxy.yml.tpl ├── tiller │ └── tiller.yml.tpl └── web-frontend-nginx │ └── web-frontend-nginx.yml.tpl ├── docs ├── clustercontroller-dev.md ├── clustershim.md ├── design.md ├── edge-autonomy.md ├── gpu-for-k3s.md ├── images │ ├── architecture.png │ ├── cluster-controller-design.png │ ├── cluster-shim.png │ ├── clustercontroller-dev.png │ ├── edge-autonomy.png │ ├── edgecontroller.png │ ├── edgehub.png │ ├── general-design.png │ ├── multi-level-edge.png │ ├── multi-runtime.png │ ├── multiple-clusters-architecture.png │ ├── multiple-clusters-nodes-info1.png │ ├── multiple-clusters-nodes-info2.png │ ├── multiple-clusters-nodes-info3.png │ ├── nginx-test.png │ ├── ote-stack.png │ ├── ote-web2.0.png │ ├── quickstart-log.png │ ├── quickstart-multi-cluster.png │ └── single-cluster-architecture.png ├── install-scripts.md └── quickstart.md ├── go.mod ├── go.sum ├── hack ├── boilerplate.go.txt ├── custom-boilerplate.go.txt ├── tools.go ├── update-codegen.sh └── verify-codegen.sh └── pkg ├── apis └── ote │ ├── register.go │ └── v1 │ ├── doc.go │ ├── register.go │ ├── types.go │ └── zz_generated.deepcopy.go ├── clusterhandler ├── clusterhandler.go └── clusterhandler_test.go ├── clustermessage ├── clustermessage.pb.go ├── clustermessage.proto ├── util.go └── util_test.go ├── clusterrouter ├── router.go └── router_test.go ├── clusterselector ├── selector.go └── selector_test.go ├── clustershim ├── apis │ └── v1 │ │ ├── cluster.pb.go │ │ └── cluster.proto ├── handler │ ├── handler.go │ ├── handler_test.go │ ├── httpproxyhandler.go │ ├── httpproxyhandler_test.go │ ├── k8shandler.go │ └── k8shandler_test.go ├── shimclient.go ├── shimclient_test.go ├── shimserver.go └── shimserver_test.go ├── config ├── config.go └── config_test.go ├── controller ├── clustercrd │ ├── clustercrd_controller.go │ └── clustercrd_controller_test.go ├── edgenode │ ├── edgenode_controller.go │ └── edgenode_controller_test.go ├── namespace │ ├── namespace_controller.go │ └── namespace_controller_test.go ├── util.go └── util_test.go ├── controllermanager ├── cluster_status_processor.go ├── cluster_status_processor_test.go ├── controllermanager.go ├── daemonset_processor.go ├── daemonset_processor_test.go ├── deployment_processor.go ├── deployment_processor_test.go ├── event_processor.go ├── event_processor_test.go ├── node_processor.go ├── node_processor_test.go ├── pod_processor.go ├── pod_processor_test.go ├── service_processor.go ├── service_processor_test.go ├── upstream_processor.go └── upstream_processor_test.go ├── edgehandler ├── edgehandler.go ├── edgehandler_test.go └── func.go ├── eventrecorder └── local_eventrecorder.go ├── generated ├── clientset │ └── versioned │ │ ├── clientset.go │ │ ├── doc.go │ │ ├── fake │ │ ├── clientset_generated.go │ │ ├── doc.go │ │ └── register.go │ │ ├── scheme │ │ ├── doc.go │ │ └── register.go │ │ └── typed │ │ └── ote │ │ └── v1 │ │ ├── cluster.go │ │ ├── clustercontroller.go │ │ ├── doc.go │ │ ├── edgenode.go │ │ ├── fake │ │ ├── doc.go │ │ ├── fake_cluster.go │ │ ├── fake_clustercontroller.go │ │ ├── fake_edgenode.go │ │ └── fake_ote_client.go │ │ ├── generated_expansion.go │ │ └── ote_client.go ├── informers │ └── externalversions │ │ ├── factory.go │ │ ├── generic.go │ │ ├── internalinterfaces │ │ └── factory_interfaces.go │ │ └── ote │ │ ├── interface.go │ │ └── v1 │ │ ├── cluster.go │ │ ├── clustercontroller.go │ │ ├── edgenode.go │ │ └── interface.go └── listers │ └── ote │ └── v1 │ ├── cluster.go │ ├── clustercontroller.go │ ├── edgenode.go │ └── expansion_generated.go ├── k8sclient ├── cluster.go ├── clustercontroller.go ├── fake │ └── fake.go ├── k8s_client.go └── k8s_client_test.go ├── loadbalancer ├── loadbalancer.go ├── loadbalancer_test.go ├── util.go └── util_test.go ├── reporter ├── cluster_status_report.go ├── cluster_status_reporter_test.go ├── daemonset_reporter.go ├── daemonset_reporter_test.go ├── deployment_reporter.go ├── deployment_reporter_test.go ├── event_reporter.go ├── event_reporter_test.go ├── node_reporter.go ├── node_reporter_test.go ├── pod_reporter.go ├── pod_reporter_test.go ├── reporter.go ├── reporter_test.go ├── service_reporter.go └── service_reporter_test.go ├── server ├── apisauthentication │ ├── register.go │ └── resource │ │ └── tokenreview.go ├── apisauthorization │ ├── register.go │ └── resource │ │ └── subjectaccessreview.go ├── apiscertificates │ ├── register.go │ └── resource │ │ └── certificatesigningrequest.go ├── apiscoordination │ ├── register.go │ └── resource │ │ └── lease.go ├── apisnetworking │ ├── register.go │ └── resource │ │ └── networkpolicy.go ├── apisnode │ ├── register.go │ └── resource │ │ └── runtimeclass.go ├── apisstorage │ ├── register.go │ └── resource │ │ ├── csidriver.go │ │ └── csinode.go ├── apiv1 │ ├── register.go │ └── resource │ │ ├── configmap.go │ │ ├── endpoint.go │ │ ├── event.go │ │ ├── namespace.go │ │ ├── node.go │ │ ├── pod.go │ │ ├── secret.go │ │ └── service.go ├── certificate │ ├── certificate.go │ └── register.go ├── handler │ ├── creator.go │ ├── deleter.go │ ├── handler.go │ ├── lister.go │ ├── updater.go │ └── watcher.go ├── k3s_server.go ├── k3s_server_test.go ├── k8s_server.go ├── k8s_server_test.go └── server.go ├── storage ├── persistent_storage.go ├── persistent_storage_test.go ├── storage.go └── storage_test.go ├── syncer ├── configmap_syncer.go ├── configmap_syncer_test.go ├── csidriver_syncer.go ├── csidriver_syncer_test.go ├── csinode_syncer.go ├── csinode_syncer_test.go ├── csr_syncer.go ├── csr_syncer_test.go ├── endpoint_syncer.go ├── endpoint_syncer_test.go ├── event_syncer.go ├── event_syncer_test.go ├── lease_syncer.go ├── lease_syncer_test.go ├── namespace_syncer.go ├── namespace_syncer_test.go ├── networkpolicy_syncer.go ├── networkpolicy_syncer_test.go ├── node_syncer.go ├── node_syncer_test.go ├── pod_syncer.go ├── pod_syncer_test.go ├── runtimeclass_syncer.go ├── runtimeclass_syncer_test.go ├── secret_syncer.go ├── secret_syncer_test.go ├── service_syncer.go ├── service_syncer_test.go ├── syncer.go └── syncer_test.go ├── tunnel ├── cloudtunnel.go ├── cloudtunnel_test.go ├── controller_tunnel.go ├── controller_tunnel_test.go ├── edgetunnel.go ├── edgetunnel_test.go ├── wsclient.go └── wsclient_test.go └── util ├── util.go └── util_test.go /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.12" 5 | 6 | install: true 7 | 8 | script: bash build/build.sh build && bash build/build.sh test 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | OTE Stack is Apache 2.0 licensed and welcome to contribute code through github. When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. 3 | 4 | 5 | ## Getting started 6 | * Fork the repository on GitHub 7 | * Read the [README.md](./README.md) for build instructions 8 | 9 | 10 | ## Contribution flow 11 | OTE-Stack use this [Git branching model](https://nvie.com/posts/a-successful-git-branching-model/). The following steps guide usual contributions. 12 | 13 | 1. Fork 14 | 15 | To make a fork, please refer to Github page and click on the ["Fork"](https://help.github.com/articles/fork-a-repo/) button. 16 | 17 | 2. Prepare for the development environment for linux 18 | 19 | ```bash 20 | go get github.com/baidu/ote-stack # get OTE Stack official repository 21 | cd $GOPATH/src/github.com/baidu/ote-stack # step into OTE Stack 22 | git checkout master # verify master branch 23 | git remote add fork https://github.com//ote-stack # specify remote repository 24 | ``` 25 | 26 | 3. Push changes to your forked repository 27 | 28 | ```bash 29 | git status # view current code change status 30 | git add . # add all local changes 31 | git commit -m "modify description" # commit changes with comment 32 | git push fork # push code changes to remote repository which specifies your forked repository 33 | ``` 34 | 35 | 4. Create pull request 36 | 37 | To create a pull request, please follow [these steps](https://help.github.com/articles/creating-a-pull-request/). Once the OTE-Stack repository reviewer approves and merges your pull request, you will see the code contributed by you in the ote-stack official repository. 38 | 39 | ## CodeStyle 40 | The coding style suggested by the Golang community is used in OTE-Stack. See the [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) for details. 41 | Please follow this style to make OTE-Stack easy to review, maintain and develop. 42 | 43 | ## Merge Rule 44 | * Please run command `govendor fmt +local` before push changes, more details refer to [govendor](https://github.com/kardianos/govendor) 45 | * Must run command `make test` before push changes(unit test should be contained), and make sure all unit test and data race test passed 46 | * Only the passed(unit test and data race test) code can be allowed to submit to OTE-Stack official repository 47 | * At least one reviewer approved code can be merged into OTE-Stack official repository 48 | 49 | -------------------------------------------------------------------------------- /build/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export LANG="en_US.UTF-8" 4 | WORKROOT="$(cd $(dirname "$0") && cd ../ && pwd || false)" 5 | export GO111MODULE=on 6 | export GOPROXY=https://goproxy.io 7 | export CGO_ENABLED=0 8 | cd $WORKROOT 9 | 10 | function build() { 11 | OUTPUT=$WORKROOT/output 12 | rm -rf $OUTPUT && mkdir $OUTPUT 13 | 14 | OUTPUT_BIN=$OUTPUT/bin 15 | mkdir -p $OUTPUT_BIN 16 | 17 | # add otectl to output directory 18 | cp $WORKROOT/deployments/otectl $OUTPUT_BIN 19 | if [ $? -ne 0 ]; then 20 | exit 1 21 | fi 22 | 23 | # build clustercontroller and cluster shim 24 | go build -o $OUTPUT_BIN/clustercontroller ./cmd/clustercontroller && \ 25 | go build -o $OUTPUT_BIN/k8s_cluster_shim ./cmd/k8s_cluster_shim && \ 26 | go build -o $OUTPUT_BIN/k3s_cluster_shim ./cmd/k3s_cluster_shim && \ 27 | go build -o $OUTPUT_BIN/ote_controller_manager ./cmd/ote_controller_manager && \ 28 | go build -o $OUTPUT_BIN/ote_edgehub ./cmd/edgehub && \ 29 | go build -o $OUTPUT_BIN/ote_edgecontroller ./cmd/edgecontroller && \ 30 | echo "build done" 31 | } 32 | 33 | function build_image() { 34 | arch=$(uname -m) 35 | if [[ $arch == "x86_64" ]];then 36 | arch="amd64" 37 | elif [[ $arch == "aarch64" ]];then 38 | arch="arm64" 39 | else 40 | arch="386" 41 | fi 42 | 43 | export GOOS=linux 44 | export GOARCH=$arch 45 | build 46 | 47 | cd $OUTPUT_BIN/ 48 | docker build -f $WORKROOT/build/dockerfile/Dockerfile.ote-cc -t ote-cc:latest . 49 | docker build -f $WORKROOT/build/dockerfile/Dockerfile.ote-cm -t ote-cm:latest . 50 | docker build -f $WORKROOT/build/dockerfile/Dockerfile.ote-shim -t ote-shim:latest . 51 | docker build -f $WORKROOT/build/dockerfile/Dockerfile.edge-controller -t edge-controller:latest . 52 | echo "build image done" 53 | } 54 | 55 | function test() { 56 | #go list ./pkg/... | grep -v "pkg/generated" | grep -v "pkg/apis" | xargs -n1 go test -cover 57 | go test ./pkg/... -coverprofile cover.out 58 | totalcover=`go tool cover -func cover.out | grep total | awk '{print $3}'` 59 | rm cover.out 60 | echo "total coverage: $totalcover" 61 | } 62 | 63 | function usage() { 64 | echo >&2 "Usage:" 65 | echo >&2 " $0 build" 66 | echo >&2 " $0 test" 67 | exit 1 68 | } 69 | 70 | cmd="${1:-}" 71 | if [[ ! $cmd ]]; then 72 | usage 73 | fi 74 | shift 75 | 76 | case "${cmd}" in 77 | build) 78 | build 79 | ;; 80 | build-image) 81 | build_image 82 | ;; 83 | test) 84 | test 85 | ;; 86 | *) 87 | usage 88 | ;; 89 | esac 90 | -------------------------------------------------------------------------------- /build/dockerfile/Dockerfile.edge-controller: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | COPY ote_edgecontroller /usr/local/bin/ 4 | 5 | WORKDIR /usr/local/bin/ 6 | ENTRYPOINT ["./ote_edgecontroller"] 7 | -------------------------------------------------------------------------------- /build/dockerfile/Dockerfile.ote-cc: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | COPY clustercontroller /usr/local/bin/ 4 | 5 | WORKDIR /usr/local/bin/ 6 | 7 | ENTRYPOINT ["./clustercontroller"] 8 | -------------------------------------------------------------------------------- /build/dockerfile/Dockerfile.ote-cm: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | COPY ote_controller_manager /usr/local/bin/ 4 | 5 | WORKDIR /usr/local/bin/ 6 | ENTRYPOINT ["./ote_controller_manager"] 7 | -------------------------------------------------------------------------------- /build/dockerfile/Dockerfile.ote-shim: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | COPY k8s_cluster_shim /usr/local/bin/ 4 | 5 | WORKDIR /usr/local/bin/ 6 | ENTRYPOINT ["./k8s_cluster_shim"] 7 | -------------------------------------------------------------------------------- /cmd/clustercontroller/clustercontroller.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Binary clustercontroller 19 | 20 | For more details to run clustercontroller, run: 21 | ./clustercontroller help 22 | */ 23 | package main 24 | 25 | import ( 26 | "fmt" 27 | "math/rand" 28 | "os" 29 | "time" 30 | 31 | "k8s.io/component-base/logs" 32 | 33 | "github.com/baidu/ote-stack/cmd/clustercontroller/app" 34 | ) 35 | 36 | func main() { 37 | rand.Seed(time.Now().UnixNano()) 38 | 39 | command := app.NewClusterControllerCommand() 40 | 41 | logs.InitLogs() 42 | defer logs.FlushLogs() 43 | 44 | if err := command.Execute(); err != nil { 45 | fmt.Fprintf(os.Stderr, "%v\n", err) 46 | os.Exit(1) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /cmd/edgecontroller/app/app.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | "os/signal" 8 | "sync" 9 | "syscall" 10 | 11 | "github.com/spf13/cobra" 12 | "k8s.io/klog" 13 | 14 | "github.com/baidu/ote-stack/pkg/controller/edgenode" 15 | "github.com/baidu/ote-stack/pkg/k8sclient" 16 | ) 17 | 18 | var ( 19 | kubeConfig string 20 | ) 21 | 22 | func NewEdgeControllerCommand() *cobra.Command { 23 | cmd := &cobra.Command{ 24 | Use: "edgecontroller", 25 | Short: "edgecontroller is a component using for indicating node status in cloud", 26 | Long: "edgecontroller is a component using for indicating node status in cloud", 27 | Run: func(cmd *cobra.Command, args []string) { 28 | if err := Run(); err != nil { 29 | panic(err) 30 | } 31 | }, 32 | } 33 | 34 | versionCmd := &cobra.Command{ 35 | Use: "version", 36 | Short: "Show version", 37 | Long: "", 38 | Run: func(cmd *cobra.Command, args []string) { 39 | klog.Info("OTE edgecontroller 1.0") 40 | }, 41 | } 42 | 43 | cmd.AddCommand(versionCmd) 44 | cmd.PersistentFlags().StringVarP(&kubeConfig, "kube-config", "k", "/root/.kube/config", "KubeConfig file path") 45 | 46 | fs := cmd.Flags() 47 | fs.AddGoFlagSet(flag.CommandLine) 48 | 49 | return cmd 50 | } 51 | 52 | func Run() error { 53 | signals := make(chan os.Signal, 0) 54 | signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) 55 | 56 | k8sClient, err := k8sclient.NewK8sClient(k8sclient.K8sOption{KubeConfig: kubeConfig}) 57 | if err != nil { 58 | return fmt.Errorf("get k8s client failed: %v", err) 59 | } 60 | 61 | oteClient, err := k8sclient.NewClient(kubeConfig) 62 | if err != nil { 63 | return fmt.Errorf("get ote client failed: %v", err) 64 | } 65 | 66 | ctx := &edgenode.ControllerContext{ 67 | OteClient: oteClient, 68 | KubeClient: k8sClient, 69 | StopChan: make(chan struct{}), 70 | } 71 | 72 | edgeNodeController := edgenode.NewEdgeNodeController(ctx) 73 | edgeNodeController.Start() 74 | 75 | go func() { 76 | <-signals 77 | klog.Infof("edgecontroller exit") 78 | os.Exit(0) 79 | }() 80 | 81 | // hang. 82 | wait := sync.WaitGroup{} 83 | wait.Add(1) 84 | wait.Wait() 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /cmd/edgecontroller/edgecontroller.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "k8s.io/component-base/logs" 8 | 9 | "github.com/baidu/ote-stack/cmd/edgecontroller/app" 10 | ) 11 | 12 | func main() { 13 | command := app.NewEdgeControllerCommand() 14 | 15 | logs.InitLogs() 16 | defer logs.FlushLogs() 17 | 18 | if err := command.Execute(); err != nil { 19 | fmt.Fprintf(os.Stderr, "%v\n", err) 20 | os.Exit(1) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cmd/edgehub/edgehub.go: -------------------------------------------------------------------------------- 1 | // Binary ote_edgehub is a proxy handling all the request from node to k8s master. 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "os" 7 | 8 | "k8s.io/component-base/logs" 9 | 10 | "github.com/baidu/ote-stack/cmd/edgehub/app" 11 | ) 12 | 13 | func main() { 14 | command := app.NewEdgehubCommand() 15 | 16 | logs.InitLogs() 17 | defer logs.FlushLogs() 18 | 19 | if err := command.Execute(); err != nil { 20 | fmt.Fprintf(os.Stderr, "%v\n", err) 21 | os.Exit(1) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cmd/k3s_cluster_shim/k3s_cluster_shim.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Binary k3s_cluster_shim is an adapter handling message from clustercontroller for k3s cluster. 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "math/rand" 23 | "os" 24 | "time" 25 | 26 | "k8s.io/component-base/logs" 27 | 28 | "github.com/baidu/ote-stack/cmd/k3s_cluster_shim/app" 29 | ) 30 | 31 | func main() { 32 | rand.Seed(time.Now().UnixNano()) 33 | 34 | command := app.NewK3sClusterShimCommand() 35 | 36 | logs.InitLogs() 37 | defer logs.FlushLogs() 38 | 39 | if err := command.Execute(); err != nil { 40 | fmt.Fprintf(os.Stderr, "%v\n", err) 41 | os.Exit(1) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cmd/k8s_cluster_shim/k8s_cluster_shim.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Binary k8s_cluster_shim is an adapter handling message from clustercontroller for k8s cluster. 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "math/rand" 23 | "os" 24 | "time" 25 | 26 | "github.com/baidu/ote-stack/cmd/k8s_cluster_shim/app" 27 | "k8s.io/component-base/logs" 28 | ) 29 | 30 | func main() { 31 | rand.Seed(time.Now().UnixNano()) 32 | 33 | command := app.NewK8sClusterShimCommand() 34 | 35 | logs.InitLogs() 36 | defer logs.FlushLogs() 37 | 38 | if err := command.Execute(); err != nil { 39 | fmt.Fprintf(os.Stderr, "%v\n", err) 40 | os.Exit(1) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cmd/ote_controller_manager/ote_controller_manager.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Binary ote_controller_manager 19 | 20 | For more details to run ote_controller_manager, run: 21 | ./ote_controller_manager help 22 | */ 23 | package main 24 | 25 | import ( 26 | "fmt" 27 | "math/rand" 28 | "os" 29 | "time" 30 | 31 | "k8s.io/component-base/logs" 32 | 33 | "github.com/baidu/ote-stack/cmd/ote_controller_manager/app" 34 | ) 35 | 36 | func main() { 37 | rand.Seed(time.Now().UnixNano()) 38 | 39 | command := app.NewOTEControllerManagerCommand() 40 | 41 | logs.InitLogs() 42 | defer logs.FlushLogs() 43 | 44 | if err := command.Execute(); err != nil { 45 | fmt.Fprintf(os.Stderr, "%v\n", err) 46 | os.Exit(1) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /deployments/alertmanager/alertmanager.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: alertmanager-config 5 | namespace: monitor 6 | data: 7 | alertmanager.yml: | 8 | global: 9 | resolve_timeout: 5m 10 | smtp_smarthost: 127.0.0.1:25 # 邮箱smtp服务器代理 11 | smtp_from: v2x@ote #邮件接收人员 12 | smtp_require_tls: false 13 | 14 | route: 15 | receiver: 'default_receiver' # 配置默认路由策略 16 | group_wait: 30s # 最初告警通知等待时间 17 | group_by: ['alertname'] 18 | group_interval: 5m # 告警新通知等待时间 19 | repeat_interval: 1h # 重复告警等待时间 20 | 21 | receivers: 22 | - name: 'default_receiver' # 与如上的default_reveiver匹配 23 | # email_configs: # 邮件告警配置 24 | # - to: v2xalert-ote@baidu.com 25 | # headers: { Subject: "[WARN] K8S报警邮件"} 26 | webhook_configs: # web平台告警配置 27 | - url: 'http://10.240.0.10:8012/v1/alert/callback' 28 | http_config: 29 | tls_config: 30 | insecure_skip_verify: true 31 | 32 | inhibit_rules: # 告警抑制规则 33 | - source_match: 34 | severity: 'critical' 35 | target_match: 36 | severity: 'warning' 37 | equal: ['alertname', 'dev', 'instance'] 38 | --- 39 | 40 | apiVersion: apps/v1 41 | kind: Deployment 42 | metadata: 43 | name: alertmanager 44 | namespace: monitor 45 | spec: 46 | selector: 47 | matchLabels: 48 | app: alertmanager 49 | replicas: 1 50 | template: 51 | metadata: 52 | labels: 53 | app: alertmanager 54 | spec: 55 | nodeSelector: 56 | monitor: deploy 57 | imagePullSecrets: 58 | - name: _HARBOR_SECRET_NAME_ 59 | hostNetwork: true 60 | dnsPolicy: ClusterFirstWithHostNet 61 | containers: 62 | - name: alertmanager 63 | image: _HARBOR_IMAGE_ADDR_/alertmanager:v0.20.0 64 | imagePullPolicy: IfNotPresent 65 | command: ["/bin/alertmanager"] 66 | args: 67 | - "--config.file=/etc/alertmanager/config/alertmanager.yml" 68 | - "--storage.path=/alertmanager-data/" 69 | - "--data.retention=120h" 70 | - "--web.listen-address=0.0.0.0:8997" 71 | ports: 72 | - containerPort: 8997 73 | securityContext: 74 | runAsUser: 0 75 | lifecycle: 76 | postStart: 77 | exec: 78 | command: ["/bin/sh", "-c", "chmod -R 777 /alertmanager-data/"] 79 | volumeMounts: 80 | - name: alertmanager-config 81 | mountPath: /etc/alertmanager/config/ 82 | - name: alertmanager-data 83 | mountPath: /alertmanager-data/ 84 | volumes: 85 | - name: alertmanager-config 86 | configMap: 87 | name: alertmanager-config 88 | - name: alertmanager-data 89 | hostPath: 90 | path: /home/work/ote/alertmanager-data/ 91 | --- 92 | 93 | apiVersion: v1 94 | kind: Service 95 | metadata: 96 | name: alertmanager 97 | namespace: monitor 98 | spec: 99 | selector: 100 | app: alertmanager 101 | type: ClusterIP 102 | ports: 103 | - port: 8997 104 | targetPort: 8997 105 | -------------------------------------------------------------------------------- /deployments/data-query-server/data-query-server.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: data-query-server-config 5 | namespace: kube-system 6 | data: 7 | config.yml: | 8 | configs: 9 | - name: prometheusAddr 10 | value: _PROMETHEUS_ADDR_ 11 | - name: allCluster 12 | value: all|root 13 | - name: minStep 14 | value: 1m 15 | - name: disk 16 | value: /home|/tmp|/var|/home/disk.+|/ssd.+|/ 17 | --- 18 | 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: data-query-server 23 | namespace: kube-system 24 | spec: 25 | selector: 26 | matchLabels: 27 | app: data-query-server 28 | replicas: 1 29 | template: 30 | metadata: 31 | labels: 32 | app: data-query-server 33 | spec: 34 | imagePullSecrets: 35 | - name: _HARBOR_SECRET_NAME_ 36 | containers: 37 | - name: data-query-server 38 | image: _HARBOR_IMAGE_ADDR_/data-query-server:multi-cluster-2020.01.20.16.03.22 39 | imagePullPolicy: IfNotPresent 40 | volumeMounts: 41 | - name: data-query-server-config 42 | mountPath: /home/config 43 | ports: 44 | - containerPort: 8994 45 | volumes: 46 | - name: data-query-server-config 47 | configMap: 48 | name: data-query-server-config 49 | --- 50 | 51 | apiVersion: v1 52 | kind: Service 53 | metadata: 54 | name: data-query-server 55 | namespace: kube-system 56 | spec: 57 | selector: 58 | app: data-query-server 59 | type: ClusterIP 60 | ports: 61 | - port: 8994 62 | targetPort: 8994 63 | -------------------------------------------------------------------------------- /deployments/edge-controller/edge-controller.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: edge-controller 5 | namespace: kube-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: edge-controller 10 | release: edge-controller 11 | replicas: 1 12 | template: 13 | metadata: 14 | labels: 15 | app: edge-controller 16 | release: edge-controller 17 | spec: 18 | imagePullSecrets: 19 | - name: _HARBOR_SECRET_NAME_ 20 | containers: 21 | - name: edge-controller 22 | image: _HARBOR_IMAGE_ADDR_/edge-controller:1.0 23 | imagePullPolicy: IfNotPresent 24 | args: 25 | - "--kube-config=/kube/kubeconfig" 26 | - "--logtostderr=true" 27 | - "--v=2" 28 | volumeMounts: 29 | - name: kube-config 30 | mountPath: /kube 31 | readOnly: true 32 | volumes: 33 | - name: kube-config 34 | secret: 35 | secretName: kubeconfig 36 | -------------------------------------------------------------------------------- /deployments/etcd/etcd.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: etcd 5 | namespace: kube-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: etcd 10 | replicas: 1 11 | template: 12 | metadata: 13 | labels: 14 | app: etcd 15 | spec: 16 | nodeSelector: 17 | cc: deploy 18 | imagePullSecrets: 19 | - name: _HARBOR_SECRET_NAME_ 20 | hostNetwork: true 21 | containers: 22 | - name: etcd 23 | image: _HARBOR_IMAGE_ADDR_/etcd:v3.3.18 24 | imagePullPolicy: IfNotPresent 25 | command: ["/usr/local/bin/etcd"] 26 | args: 27 | - "--name=etcd" 28 | - "--data-dir=/etcd-data/" 29 | - "--listen-peer-urls=http://0.0.0.0:9380" 30 | - "--initial-advertise-peer-urls=http://_ETCD_HOST_IP_:9380" 31 | - "--listen-client-urls=http://0.0.0.0:9379" 32 | - "--advertise-client-urls=http://_ETCD_HOST_IP_:9379" 33 | - "--initial-cluster-token=etcd-cluster-token" 34 | - "--initial-cluster-state=new" 35 | - "--log-output=stdout" 36 | volumeMounts: 37 | - name: etcd-data 38 | mountPath: /etcd-data/ 39 | ports: 40 | - containerPort: 9379 41 | volumes: 42 | - name: etcd-data 43 | hostPath: 44 | path: /home/work/ote/etcd-data/ 45 | --- 46 | 47 | apiVersion: v1 48 | kind: Service 49 | metadata: 50 | name: etcd 51 | namespace: kube-system 52 | spec: 53 | selector: 54 | app: etcd 55 | type: ClusterIP 56 | ports: 57 | - port: 9379 58 | targetPort: 9379 59 | -------------------------------------------------------------------------------- /deployments/etcd/etcd.yml.tpl.aarch64: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: etcd 5 | namespace: kube-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: etcd 10 | replicas: 1 11 | template: 12 | metadata: 13 | labels: 14 | app: etcd 15 | spec: 16 | nodeSelector: 17 | cc: deploy 18 | imagePullSecrets: 19 | - name: _HARBOR_SECRET_NAME_ 20 | hostNetwork: true 21 | containers: 22 | - name: etcd 23 | image: _HARBOR_IMAGE_ADDR_/etcd:v3.3.18 24 | imagePullPolicy: IfNotPresent 25 | command: ["/usr/local/bin/etcd"] 26 | args: 27 | - "--name=etcd" 28 | - "--data-dir=/etcd-data/" 29 | - "--listen-peer-urls=http://0.0.0.0:9380" 30 | - "--initial-advertise-peer-urls=http://_ETCD_HOST_IP_:9380" 31 | - "--listen-client-urls=http://0.0.0.0:9379" 32 | - "--advertise-client-urls=http://_ETCD_HOST_IP_:9379" 33 | - "--initial-cluster-token=etcd-cluster-token" 34 | - "--initial-cluster-state=new" 35 | - "--log-output=stdout" 36 | volumeMounts: 37 | - name: etcd-data 38 | mountPath: /etcd-data/ 39 | ports: 40 | - containerPort: 9379 41 | env: 42 | # set ETCD_UNSUPPORTED_ARCH=arm64 to support architecture arm64 43 | - name: ETCD_UNSUPPORTED_ARCH 44 | value: arm64 45 | volumes: 46 | - name: etcd-data 47 | hostPath: 48 | path: /home/work/ote/etcd-data/ 49 | --- 50 | 51 | apiVersion: v1 52 | kind: Service 53 | metadata: 54 | name: etcd 55 | namespace: kube-system 56 | spec: 57 | selector: 58 | app: etcd 59 | type: ClusterIP 60 | ports: 61 | - port: 9379 62 | targetPort: 9379 63 | -------------------------------------------------------------------------------- /deployments/gpu-metrics-exporter/gpu-metrics-exporter.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: DaemonSet 3 | metadata: 4 | name: gpu-metrics-exporter 5 | namespace: monitor 6 | spec: 7 | template: 8 | metadata: 9 | labels: 10 | app: gpu-metrics-exporter 11 | name: gpu-metrics-exporter 12 | spec: 13 | hostNetwork: true 14 | nodeSelector: 15 | gpu: deploy 16 | imagePullSecrets: 17 | - name: _HARBOR_SECRET_NAME_ 18 | containers: 19 | - image: _HARBOR_IMAGE_ADDR_/pod-gpu-metrics-exporter:v1.0.0-alpha 20 | name: pod-nvidia-gpu-metrics-exporter 21 | ports: 22 | - name: gpu-metrics 23 | containerPort: 9400 24 | securityContext: 25 | runAsNonRoot: false 26 | runAsUser: 0 27 | volumeMounts: 28 | - name: pod-gpu-resources 29 | readOnly: true 30 | mountPath: /var/lib/kubelet/pod-resources 31 | - name: device-metrics 32 | readOnly: true 33 | mountPath: /run/prometheus 34 | - image: _HARBOR_IMAGE_ADDR_/dcgm-exporter:1.4.6 35 | name: nvidia-dcgm-exporter 36 | securityContext: 37 | runAsNonRoot: false 38 | runAsUser: 0 39 | volumeMounts: 40 | - name: device-metrics 41 | mountPath: /run/prometheus 42 | volumes: 43 | - name: pod-gpu-resources 44 | hostPath: 45 | path: /var/lib/kubelet/pod-resources 46 | - name: device-metrics 47 | emptyDir: 48 | medium: Memory 49 | --- 50 | 51 | apiVersion: extensions/v1beta1 52 | kind: DaemonSet 53 | metadata: 54 | name: nvidia-device-plugin 55 | namespace: monitor 56 | spec: 57 | template: 58 | metadata: 59 | annotations: 60 | scheduler.alpha.kubernetes.io/critical-pod: "" 61 | labels: 62 | app: nvidia-device-plugin 63 | spec: 64 | nodeSelector: 65 | gpu: deploy 66 | imagePullSecrets: 67 | - name: _HARBOR_SECRET_NAME_ 68 | tolerations: 69 | # Allow this pod to be rescheduled while the node is in "critical add-ons only" mode. 70 | # This, along with the annotation above marks this pod as a critical add-on. 71 | - key: CriticalAddonsOnly 72 | operator: Exists 73 | - key: nvidia.com/gpu 74 | operator: Exists 75 | effect: NoSchedule 76 | containers: 77 | - image: _HARBOR_IMAGE_ADDR_/k8s-device-plugin:1.11 78 | name: nvidia-device-plugin-ctr 79 | securityContext: 80 | allowPrivilegeEscalation: false 81 | capabilities: 82 | drop: ["ALL"] 83 | volumeMounts: 84 | - name: device-plugin 85 | mountPath: /var/lib/kubelet/device-plugins 86 | volumes: 87 | - name: device-plugin 88 | hostPath: 89 | path: /var/lib/kubelet/device-plugins 90 | -------------------------------------------------------------------------------- /deployments/interface_conf: -------------------------------------------------------------------------------- 1 | # interface_conf is the config file for create_yml.sh to use. 2 | # please refer to docs/install-scripts.md about how to install ote-stack. 3 | 4 | 5 | # Fill in the node name in k8s cluster. 6 | # If it is a k8s cluster with only one node, all node_name should be the same. 7 | node1_name=k8s-node1 8 | node2_name=k8s-node2 9 | 10 | # Fill in the docker image address of all modules. 11 | # It can be a public harbor repository or a private harbor repository. 12 | harbor_image_addr=otestack 13 | # Fill in the imagePullSecrets for k8s if necessary. 14 | # If docker image is public, we don't care about this value. 15 | harbor_secret_name=harbor_secret 16 | 17 | # ote-web needs to manage the harbor and stores helm charts in the harbor 18 | # Fill in the variables related to harbor 19 | harbor_api_addr=http://1.2.3.4:8702 20 | harbor_admin_user=admin 21 | harbor_admin_passwd=123456 22 | repository_domain=ote-harbor.baidu.com 23 | 24 | # docker root dir 25 | docker_root_dir=/var/lib/docker 26 | 27 | # edge autonomy enable 28 | EDGE_AUTONOMY_ENABLE=false -------------------------------------------------------------------------------- /deployments/k3s/gpu_device_plugin.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: nvidia-device-plugin 5 | namespace: kube-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: nvidia-device-plugin 10 | template: 11 | metadata: 12 | annotations: 13 | scheduler.alpha.kubernetes.io/critical-pod: "" 14 | labels: 15 | app: nvidia-device-plugin 16 | spec: 17 | nodeSelector: 18 | gpu: deploy 19 | imagePullSecrets: 20 | - name: default-token-6qh84 21 | tolerations: 22 | # Allow this pod to be rescheduled while the node is in "critical add-ons only" mode. 23 | # This, along with the annotation above marks this pod as a critical add-on. 24 | - key: CriticalAddonsOnly 25 | operator: Exists 26 | - key: nvidia.com/gpu 27 | operator: Exists 28 | effect: NoSchedule 29 | containers: 30 | - image: nvidia/k8s-device-plugin:1.11 31 | name: nvidia-device-plugin-ctr 32 | securityContext: 33 | allowPrivilegeEscalation: false 34 | capabilities: 35 | drop: ["ALL"] 36 | volumeMounts: 37 | - name: device-plugin 38 | mountPath: /var/lib/kubelet/device-plugins 39 | volumes: 40 | - name: device-plugin 41 | hostPath: 42 | path: /var/lib/kubelet/device-plugins 43 | -------------------------------------------------------------------------------- /deployments/kube-apiserver/cc-crd.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | name: clusters.ote.baidu.com 7 | spec: 8 | group: ote.baidu.com 9 | names: 10 | kind: Cluster 11 | plural: clusters 12 | shortNames: 13 | - cs 14 | singular: cluster 15 | scope: Namespaced 16 | additionalPrinterColumns: 17 | - name: Listen 18 | type: string 19 | JSONPath: .status.listen 20 | - name: Parent 21 | type: string 22 | JSONPath: .status.parentName 23 | - name: UserDefineName 24 | type: string 25 | JSONPath: .spec.name 26 | - name: Status 27 | type: string 28 | JSONPath: .status.status 29 | - name: Age 30 | type: date 31 | JSONPath: .metadata.creationTimestamp 32 | validation: 33 | openAPIV3Schema: 34 | properties: 35 | spec: 36 | properties: 37 | name: 38 | type: string 39 | version: v1 40 | --- 41 | apiVersion: apiextensions.k8s.io/v1beta1 42 | kind: CustomResourceDefinition 43 | metadata: 44 | creationTimestamp: null 45 | labels: 46 | name: clustercontrollers.ote.baidu.com 47 | spec: 48 | group: ote.baidu.com 49 | names: 50 | kind: ClusterController 51 | plural: clustercontrollers 52 | shortNames: 53 | - ccs 54 | singular: clustercontroller 55 | scope: Namespaced 56 | validation: 57 | openAPIV3Schema: 58 | properties: 59 | spec: 60 | properties: 61 | clusterSelector: 62 | type: string 63 | destination: 64 | type: string 65 | url: 66 | type: string 67 | body: 68 | type: string 69 | version: v1 70 | --- 71 | apiVersion: rbac.authorization.k8s.io/v1beta1 72 | kind: ClusterRole 73 | metadata: 74 | creationTimestamp: null 75 | name: ote-crd 76 | rules: 77 | - apiGroups: 78 | - ote.baidu.com 79 | resources: 80 | - customresourcedefinitions 81 | verbs: 82 | - create 83 | - apiGroups: 84 | - ote.baidu.com 85 | resources: 86 | - clusters 87 | - clustercontrollers 88 | verbs: 89 | - list 90 | - get 91 | - update 92 | - watch 93 | - create 94 | - delete 95 | -------------------------------------------------------------------------------- /deployments/kube-apiserver/edgenode-crd.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | name: edgenodes.ote.baidu.com 7 | spec: 8 | group: ote.baidu.com 9 | names: 10 | kind: EdgeNode 11 | plural: edgenodes 12 | shortNames: 13 | - en 14 | singular: edgenode 15 | scope: Namespaced 16 | additionalPrinterColumns: 17 | - name: Status 18 | type: string 19 | JSONPath: .status 20 | - name: Age 21 | type: date 22 | JSONPath: .metadata.creationTimestamp 23 | validation: 24 | openAPIV3Schema: 25 | properties: 26 | spec: 27 | properties: 28 | name: 29 | type: string 30 | version: v1 31 | --- 32 | apiVersion: rbac.authorization.k8s.io/v1beta1 33 | kind: ClusterRole 34 | metadata: 35 | creationTimestamp: null 36 | name: ote-crd 37 | rules: 38 | - apiGroups: 39 | - ote.baidu.com 40 | resources: 41 | - customresourcedefinitions 42 | verbs: 43 | - create 44 | - apiGroups: 45 | - ote.baidu.com 46 | resources: 47 | - edgenodes 48 | verbs: 49 | - list 50 | - get 51 | - update 52 | - watch 53 | - create 54 | - delete 55 | -------------------------------------------------------------------------------- /deployments/kube-apiserver/kube-apiserver.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kube-apiserver-token-config 5 | namespace: kube-system 6 | data: 7 | token.csv: | 8 | 365719038f0aafe86eb9f8bbadf48955,kubelet-bootstrap,10001 9 | --- 10 | 11 | apiVersion: apps/v1 12 | kind: Deployment 13 | metadata: 14 | name: kube-apiserver 15 | namespace: kube-system 16 | spec: 17 | selector: 18 | matchLabels: 19 | app: kube-apiserver 20 | replicas: 1 21 | template: 22 | metadata: 23 | labels: 24 | app: kube-apiserver 25 | spec: 26 | nodeSelector: 27 | cc: deploy 28 | imagePullSecrets: 29 | - name: _HARBOR_SECRET_NAME_ 30 | hostNetwork: true 31 | containers: 32 | - name: kube-apiserver 33 | image: _HARBOR_IMAGE_ADDR_/kube-apiserver:v1.12.5 34 | imagePullPolicy: IfNotPresent 35 | command: ["/usr/local/bin/kube-apiserver"] 36 | args: 37 | - "--etcd-servers=http://127.0.0.1:9379" 38 | - "--token-auth-file=/home/config/token.csv" 39 | - "--disable-admission-plugins=ServiceAccount" 40 | - "--allow-privileged=true" 41 | - "--service-cluster-ip-range=10.254.0.0/12" 42 | - "--insecure-bind-address=0.0.0.0" 43 | - "--insecure-port=9082" 44 | - "--secure-port=9083" 45 | - "--advertise-address=_KUBE_APISERVER_HOST_IP_" 46 | - "--logtostderr=true" 47 | - "--v=2" 48 | volumeMounts: 49 | - name: kube-apiserver-token-config 50 | mountPath: /home/config/ 51 | ports: 52 | - containerPort: 9082 53 | volumes: 54 | - name: kube-apiserver-token-config 55 | configMap: 56 | name: kube-apiserver-token-config 57 | --- 58 | 59 | apiVersion: v1 60 | kind: Service 61 | metadata: 62 | name: kube-apiserver 63 | namespace: kube-system 64 | spec: 65 | selector: 66 | app: kube-apiserver 67 | type: ClusterIP 68 | ports: 69 | - port: 9082 70 | targetPort: 9082 71 | -------------------------------------------------------------------------------- /deployments/kube-apiserver/ns.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: monitor 5 | --- 6 | 7 | apiVersion: v1 8 | kind: Namespace 9 | metadata: 10 | name: kube-system 11 | -------------------------------------------------------------------------------- /deployments/node-agent/node-agent.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: node-agent-config 5 | namespace: monitor 6 | data: 7 | node-agent-config.yaml: | 8 | jobs: 9 | - name: cadvisor 10 | localAddr: http://127.0.0.1:6028/metrics/cadvisor 11 | remoteAddr: _NODES_SERVER_ADDR_/post_data 12 | scrapeInterval: 30 13 | filter: 14 | - container_cpu_usage_seconds_total 15 | - container_memory_usage_bytes 16 | - container_network_transmit_bytes_total 17 | - container_network_receive_bytes_total 18 | - container_fs_usage_bytes 19 | - machine_cpu_cores 20 | - machine_memory_bytes 21 | - name: node_exporter 22 | localAddr: http://127.0.0.1:9100/metrics 23 | remoteAddr: _NODES_SERVER_ADDR_/post_data 24 | scrapeInterval: 30 25 | filter: 26 | - node_cpu_seconds_total 27 | - node_filesystem_size_bytes 28 | - node_filesystem_free_bytes 29 | - node_memory_MemTotal_bytes 30 | - node_memory_MemFree_bytes 31 | - node_memory_Cached_bytes 32 | - node_memory_Buffers_bytes 33 | - node_network_transmit_bytes_total 34 | - node_network_receive_bytes_total 35 | - node_load5 36 | - name: gpu 37 | localAddr: http://127.0.0.1:9400/gpu/metrics 38 | remoteAddr: _NODES_SERVER_ADDR_/post_data 39 | scrapeInterval: 30 40 | filter: 41 | - dcgm_fb_free 42 | - dcgm_fb_used 43 | - dcgm_gpu_utilization 44 | --- 45 | 46 | apiVersion: extensions/v1beta1 47 | kind: DaemonSet 48 | metadata: 49 | name: node-agent 50 | namespace: monitor 51 | labels: 52 | app: node-agent 53 | spec: 54 | template: 55 | metadata: 56 | name: node-agent 57 | labels: 58 | app: node-agent 59 | spec: 60 | hostNetwork: true 61 | # dnsPolicy: ClusterFirstWithHostNet 62 | imagePullSecrets: 63 | - name: _HARBOR_SECRET_NAME_ 64 | containers: 65 | - name: node-agent 66 | image: _HARBOR_IMAGE_ADDR_/node-agent:online0.1 67 | imagePullPolicy: IfNotPresent 68 | command: ["/home/node-agent"] 69 | args: 70 | - "--config=/home/config/node-agent-config.yaml" 71 | - "--logtostderr=true" 72 | - "--queue_size=100" 73 | - "--retry_num=3" 74 | - "--retry_interval=1" 75 | volumeMounts: 76 | - name: node-agent-config 77 | mountPath: /home/config 78 | volumes: 79 | - name: node-agent-config 80 | configMap: 81 | name: node-agent-config -------------------------------------------------------------------------------- /deployments/nodes-server/nodes-server.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: nodes-server-config 5 | namespace: monitor 6 | data: 7 | nodes-server-config.yaml: | 8 | configs: 9 | - name: cadvisor 10 | value: 30 11 | - name: node_exporter 12 | value: 30 13 | - name: gpu 14 | value: 30 15 | - name: network_monitor 16 | value: 30 17 | - name: test 18 | value: 30 19 | --- 20 | 21 | apiVersion: apps/v1beta1 22 | kind: Deployment 23 | metadata: 24 | name: nodes-server 25 | namespace: monitor 26 | spec: 27 | selector: 28 | matchLabels: 29 | app: nodes-server 30 | replicas: 1 31 | template: 32 | metadata: 33 | labels: 34 | app: nodes-server 35 | spec: 36 | nodeSelector: 37 | monitor: deploy 38 | imagePullSecrets: 39 | - name: _HARBOR_SECRET_NAME_ 40 | hostNetwork: true 41 | containers: 42 | - name: nodes-server 43 | image: _HARBOR_IMAGE_ADDR_/nodes-server:online0.3 44 | imagePullPolicy: IfNotPresent 45 | command: ["/home/nodes-server"] 46 | args: 47 | - "--config=/home/config/nodes-server-config.yaml" 48 | - "--logtostderr=true" 49 | - "--port=8999" 50 | volumeMounts: 51 | - name: nodes-server-config 52 | mountPath: /home/config 53 | ports: 54 | - containerPort: 8999 55 | volumes: 56 | - name: nodes-server-config 57 | configMap: 58 | name: nodes-server-config 59 | --- 60 | 61 | apiVersion: v1 62 | kind: Service 63 | metadata: 64 | name: nodes-server 65 | namespace: monitor 66 | spec: 67 | selector: 68 | app: nodes-server 69 | type: ClusterIP 70 | ports: 71 | - port: 8999 72 | targetPort: 8999 73 | -------------------------------------------------------------------------------- /deployments/ote-cc/ote-cc.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: ote-cc 5 | namespace: kube-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: ote-cc 10 | release: ote-cc 11 | replicas: 1 12 | template: 13 | metadata: 14 | labels: 15 | app: ote-cc 16 | release: ote-cc 17 | spec: 18 | imagePullSecrets: 19 | - name: _HARBOR_SECRET_NAME_ 20 | containers: 21 | - name: ote-cc 22 | image: _HARBOR_IMAGE_ADDR_/ote-cc:3.0 23 | imagePullPolicy: IfNotPresent 24 | args: 25 | - "--kube-config=/kube/config" 26 | - "--remote-shim-endpoint=ote-k8s-shim:8262" 27 | - "--tunnel-listen=0.0.0.0:8287" 28 | - "--logtostderr=true" 29 | - "--v=2" 30 | volumeMounts: 31 | - name: root-kube-config 32 | mountPath: /kube/config 33 | subPath: config 34 | ports: 35 | - containerPort: 8287 36 | volumes: 37 | - name: root-kube-config 38 | configMap: 39 | name: root-kube-config 40 | --- 41 | 42 | apiVersion: v1 43 | kind: Service 44 | metadata: 45 | name: ote-cc 46 | namespace: kube-system 47 | spec: 48 | selector: 49 | app: ote-cc 50 | release: ote-cc 51 | type: ClusterIP 52 | ports: 53 | - port: 8287 54 | targetPort: 8287 55 | -------------------------------------------------------------------------------- /deployments/ote-cm/ote-cm.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: root-kube-config 5 | namespace: kube-system 6 | data: 7 | config: | 8 | apiVersion: v1 9 | kind: Config 10 | preferences: {} 11 | current-context: default 12 | clusters: 13 | - name: root 14 | cluster: 15 | insecure-skip-tls-verify: true 16 | server: http://kube-apiserver:9082 17 | contexts: 18 | - name: default 19 | context: 20 | cluster: root 21 | user: cluster-admin 22 | users: 23 | - name: cluster-admin 24 | user: 25 | token: 365719038f0aafe86eb9f8bbadf48955 26 | --- 27 | 28 | apiVersion: apps/v1beta1 29 | kind: Deployment 30 | metadata: 31 | name: ote-cm 32 | namespace: kube-system 33 | spec: 34 | selector: 35 | matchLabels: 36 | app: ote-cm 37 | release: ote-cm 38 | replicas: 1 39 | template: 40 | metadata: 41 | labels: 42 | app: ote-cm 43 | release: ote-cm 44 | spec: 45 | imagePullSecrets: 46 | - name: _HARBOR_SECRET_NAME_ 47 | containers: 48 | - name: ote-cm 49 | image: _HARBOR_IMAGE_ADDR_/ote-cm:3.0 50 | imagePullPolicy: IfNotPresent 51 | args: 52 | - "--kube-config=/kube/config" 53 | - "--root-cluster-controller=ote-cc:8287" 54 | - "--logtostderr=true" 55 | - "--v=2" 56 | volumeMounts: 57 | - name: root-kube-config 58 | mountPath: /kube/config 59 | subPath: config 60 | ports: 61 | - containerPort: 8287 62 | volumes: 63 | - name: root-kube-config 64 | configMap: 65 | name: root-kube-config 66 | 67 | -------------------------------------------------------------------------------- /deployments/ote-k8s-shim/ote-k8s-shim.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: ote-k8s-shim 5 | namespace: kube-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: ote-k8s-shim 10 | release: ote-k8s-shim 11 | replicas: 1 12 | template: 13 | metadata: 14 | labels: 15 | app: ote-k8s-shim 16 | release: ote-k8s-shim 17 | spec: 18 | imagePullSecrets: 19 | - name: _HARBOR_SECRET_NAME_ 20 | containers: 21 | - name: ote-k8s-shim 22 | image: _HARBOR_IMAGE_ADDR_/ote-shim:3.0 23 | imagePullPolicy: IfNotPresent 24 | args: 25 | - "--kube-config=/kube/config" 26 | - "--helm-addr=tiller-proxy:80" 27 | - "--listen=0.0.0.0:8262" 28 | - "--logtostderr=true" 29 | - "--v=2" 30 | volumeMounts: 31 | - name: edge-kube-config 32 | mountPath: /kube/config 33 | subPath: config 34 | ports: 35 | - containerPort: 8262 36 | volumes: 37 | - name: edge-kube-config 38 | configMap: 39 | name: edge-kube-config 40 | --- 41 | 42 | apiVersion: v1 43 | kind: Service 44 | metadata: 45 | name: ote-k8s-shim 46 | namespace: kube-system 47 | spec: 48 | selector: 49 | app: ote-k8s-shim 50 | release: ote-k8s-shim 51 | type: ClusterIP 52 | ports: 53 | - port: 8262 54 | targetPort: 8262 55 | 56 | -------------------------------------------------------------------------------- /deployments/otectl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # usage: otectl cluster_name kubectl_args... 3 | 4 | # check if kubectl exists 5 | find_kubectl=$(type kubectl) 6 | if [ $? -ne 0 ];then 7 | echo "add kubectl to PATH" 8 | exit 1 9 | fi 10 | 11 | cmd="kubectl -l ote-cluster=" 12 | for arg in "$@" 13 | do 14 | cmd="${cmd}${arg} " 15 | done 16 | 17 | eval $cmd 18 | if [ $? -ne 0 ];then 19 | echo "otectl cluster_name kubectl_args..." 20 | exit 1 21 | fi 22 | -------------------------------------------------------------------------------- /deployments/prometheus/alerting-rules.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: prometheus-alerting-rules 5 | namespace: monitor 6 | data: 7 | cpu.yml: |+ 8 | groups: 9 | - name: NodeCPU 10 | rules: 11 | - alert: NodeCPUUsage 12 | expr: node:node_cpu_usage_percentage:avg_rate2m > 80 13 | for: 30s 14 | labels: 15 | user: car 16 | limit: 80% 17 | ipaddr: "{{$labels.ipaddr}}" 18 | annotations: 19 | summary: "{{$labels.instance}}: High CPU usage detected" 20 | description: "{{$labels.instance}}: CPU usage is above 80%" 21 | value: "{{$value}}" 22 | 23 | mem.yml: |+ 24 | groups: 25 | - name: NodeCPU 26 | rules: 27 | - alert: NodeCPUUsage 28 | expr: node:node_memory_usage_percentage:sum > 80 29 | for: 30s 30 | labels: 31 | user: car 32 | limit: 80% 33 | ipaddr: "{{$labels.ipaddr}}" 34 | annotations: 35 | summary: "{{$labels.instance}}: High CPU usage detected" 36 | description: "{{$labels.instance}}: CPU usage is above 80%" 37 | value: "{{$value}}" -------------------------------------------------------------------------------- /deployments/tiller-proxy/tiller-proxy.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: tiller-proxy 5 | namespace: kube-system 6 | labels: 7 | app: tiller-proxy 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: tiller-proxy 13 | template: 14 | metadata: 15 | labels: 16 | app: tiller-proxy 17 | annotations: 18 | scheduler.alpha.kubernetes.io/critical-pod: '' 19 | spec: 20 | imagePullSecrets: 21 | - name: _HARBOR_SECRET_NAME_ 22 | containers: 23 | - name: tiller-proxy 24 | image: _HARBOR_IMAGE_ADDR_/tiller-proxy:0.11.1 25 | imagePullPolicy: IfNotPresent 26 | args: 27 | - run 28 | - --v=3 29 | - --connector=direct 30 | - --tiller-insecure-skip-verify=true 31 | - --enable-analytics=true 32 | - --tiller-endpoint=tiller:44134 33 | ports: 34 | - containerPort: 9855 35 | volumeMounts: 36 | - mountPath: /tmp 37 | name: chart-volume 38 | volumes: 39 | - name: chart-volume 40 | emptyDir: {} 41 | tolerations: 42 | - key: CriticalAddonsOnly 43 | operator: Exists 44 | --- 45 | 46 | apiVersion: v1 47 | kind: Service 48 | metadata: 49 | name: tiller-proxy 50 | namespace: kube-system 51 | labels: 52 | app: tiller-proxy 53 | spec: 54 | ports: 55 | - name: http 56 | port: 80 57 | targetPort: 9855 58 | selector: 59 | app: tiller-proxy -------------------------------------------------------------------------------- /deployments/tiller/tiller.yml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: tiller 5 | namespace: kube-system 6 | --- 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRoleBinding 10 | metadata: 11 | name: tiller 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: ClusterRole 15 | name: cluster-admin 16 | subjects: 17 | - kind: ServiceAccount 18 | name: tiller 19 | namespace: kube-system 20 | --- 21 | 22 | apiVersion: extensions/v1beta1 23 | kind: Deployment 24 | metadata: 25 | labels: 26 | app: helm 27 | name: tiller 28 | name: tiller 29 | namespace: kube-system 30 | spec: 31 | replicas: 1 32 | template: 33 | metadata: 34 | labels: 35 | app: helm 36 | name: tiller 37 | spec: 38 | imagePullSecrets: 39 | - name: _HARBOR_SECRET_NAME_ 40 | automountServiceAccountToken: true 41 | containers: 42 | - env: 43 | - name: TILLER_NAMESPACE 44 | value: kube-system 45 | - name: TILLER_HISTORY_MAX 46 | value: "100" 47 | image: _HARBOR_IMAGE_ADDR_/helm.tiller:v2.13.1 48 | imagePullPolicy: IfNotPresent 49 | livenessProbe: 50 | httpGet: 51 | path: /liveness 52 | port: 44135 53 | initialDelaySeconds: 1 54 | timeoutSeconds: 1 55 | name: tiller 56 | ports: 57 | - containerPort: 44134 58 | name: tiller 59 | - containerPort: 44135 60 | name: http 61 | readinessProbe: 62 | httpGet: 63 | path: /readiness 64 | port: 44135 65 | initialDelaySeconds: 1 66 | timeoutSeconds: 1 67 | resources: {} 68 | serviceAccountName: tiller 69 | --- 70 | 71 | apiVersion: v1 72 | kind: Service 73 | metadata: 74 | labels: 75 | app: helm 76 | name: tiller 77 | name: tiller 78 | namespace: kube-system 79 | spec: 80 | selector: 81 | app: helm 82 | name: tiller 83 | type: ClusterIP 84 | ports: 85 | - name: tiller 86 | port: 44134 87 | targetPort: tiller 88 | -------------------------------------------------------------------------------- /docs/clustershim.md: -------------------------------------------------------------------------------- 1 | # cluster-shim 2 | ## Overview 3 | The cluster-shim is a grpc server that handle the cluster messages forwarded by ote cluster controller and transmit to the specific destination. The diagram below shows how cluster-shim works. 4 | ![cluster-shim](./images/cluster-shim.png) 5 | This project implements two shim for the cluster controller, which called k8s-cluster-shim and k3s-cluster-shim respectively. Both k8s-cluster-shim and k3s-cluster-shim have the same capability to interact with Kubernetes, but k8s-cluster-shim also integrates helmchart deploy capability. 6 | 7 | ## Usage 8 | Run the binary as below. 9 | ```shell 10 | # same as k3s_cluster_shim 11 | ./k8s_cluster_shim --kube-config /root/.kube/config 12 | ``` 13 | The shim will start a websocket server (default ":8262"). To change the listen address use flag `--listen`. 14 | ```shell 15 | ./k8s_cluster_shim --kube-config /root/.kube/config --listen :8262 16 | ``` 17 | If you're using helm to manage applications, then you have to install [tiller proxy server](https://appscode.com/products/swift/) since we haven't implement the direct connection with tiller server yet. Before running the k8s-cluster-shim binary, You need to specify the proxy server address. 18 | ```shell 19 | ./k8s_cluster_shim --kube-config /root/.kube/config --helm-addr 127.0.0.1:8080 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/architecture.png -------------------------------------------------------------------------------- /docs/images/cluster-controller-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/cluster-controller-design.png -------------------------------------------------------------------------------- /docs/images/cluster-shim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/cluster-shim.png -------------------------------------------------------------------------------- /docs/images/clustercontroller-dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/clustercontroller-dev.png -------------------------------------------------------------------------------- /docs/images/edge-autonomy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/edge-autonomy.png -------------------------------------------------------------------------------- /docs/images/edgecontroller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/edgecontroller.png -------------------------------------------------------------------------------- /docs/images/edgehub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/edgehub.png -------------------------------------------------------------------------------- /docs/images/general-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/general-design.png -------------------------------------------------------------------------------- /docs/images/multi-level-edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/multi-level-edge.png -------------------------------------------------------------------------------- /docs/images/multi-runtime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/multi-runtime.png -------------------------------------------------------------------------------- /docs/images/multiple-clusters-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/multiple-clusters-architecture.png -------------------------------------------------------------------------------- /docs/images/multiple-clusters-nodes-info1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/multiple-clusters-nodes-info1.png -------------------------------------------------------------------------------- /docs/images/multiple-clusters-nodes-info2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/multiple-clusters-nodes-info2.png -------------------------------------------------------------------------------- /docs/images/multiple-clusters-nodes-info3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/multiple-clusters-nodes-info3.png -------------------------------------------------------------------------------- /docs/images/nginx-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/nginx-test.png -------------------------------------------------------------------------------- /docs/images/ote-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/ote-stack.png -------------------------------------------------------------------------------- /docs/images/ote-web2.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/ote-web2.0.png -------------------------------------------------------------------------------- /docs/images/quickstart-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/quickstart-log.png -------------------------------------------------------------------------------- /docs/images/quickstart-multi-cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/quickstart-multi-cluster.png -------------------------------------------------------------------------------- /docs/images/single-cluster-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baidu/ote-stack/afc7ae1e6419f63aa229a019674232b2878c6cd2/docs/images/single-cluster-architecture.png -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/baidu/ote-stack 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/Azure/go-autorest v11.1.2+incompatible // indirect 7 | github.com/emicklei/go-restful v2.9.5+incompatible 8 | github.com/evanphx/json-patch v4.2.0+incompatible 9 | github.com/golang/protobuf v1.3.2 10 | github.com/gorilla/mux v1.7.2 11 | github.com/gorilla/websocket v1.4.0 12 | github.com/pborman/uuid v1.2.0 // indirect 13 | github.com/pkg/errors v0.9.1 14 | github.com/rancher/dynamiclistener v0.2.0 15 | github.com/segmentio/ksuid v1.0.2 16 | github.com/spf13/cobra v0.0.4 17 | github.com/stretchr/testify v1.4.0 18 | github.com/syndtr/goleveldb v1.0.0 19 | golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 20 | google.golang.org/grpc v1.21.1 21 | k8s.io/api v0.18.4 22 | k8s.io/apimachinery v0.18.4 23 | k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible 24 | k8s.io/code-generator v0.17.4 25 | k8s.io/component-base v0.0.0-20190602130718-4ec519775454 26 | k8s.io/gengo v0.0.0-20191010091904-7fa3014cb28f // indirect 27 | k8s.io/klog v1.0.0 28 | ) 29 | 30 | replace ( 31 | k8s.io/api => github.com/rancher/kubernetes/staging/src/k8s.io/api v1.17.4-k3s1 32 | k8s.io/apimachinery => github.com/rancher/kubernetes/staging/src/k8s.io/apimachinery v1.17.4-k3s1 33 | k8s.io/client-go => github.com/rancher/kubernetes/staging/src/k8s.io/client-go v1.17.4-k3s1 34 | k8s.io/component-base => github.com/rancher/kubernetes/staging/src/k8s.io/component-base v1.17.4-k3s1 35 | ) 36 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /hack/custom-boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright YEAR The Kubernetes sample-controller Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /hack/tools.go: -------------------------------------------------------------------------------- 1 | // +build tools 2 | 3 | /* 4 | Copyright 2019 The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | // This package imports things required by build scripts, to force `go mod` to see them as dependencies 20 | package tools 21 | 22 | import _ "k8s.io/code-generator" 23 | -------------------------------------------------------------------------------- /hack/update-codegen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 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 | echo "script root: $SCRIPT_ROOT" 23 | #CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} 24 | if [ -f go.mod ]; then 25 | echo "modules on" 26 | code_generator_path=`grep code-generator $SCRIPT_ROOT/go.mod|awk '{print $1"@"$2}'` 27 | CODEGEN_PKG=$GOPATH/pkg/mod/$code_generator_path 28 | echo "code gen path: $CODEGEN_PKG" 29 | chmod +x "${CODEGEN_PKG}"/generate-groups.sh 30 | chmod -R +w $CODEGEN_PKG 31 | fi 32 | 33 | # generate the code with: 34 | # --output-base because this script should also be able to run inside the vendor dir of 35 | # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir 36 | # instead of the $GOPATH directly. For normal projects this can be dropped. 37 | "${CODEGEN_PKG}"/generate-groups.sh "deepcopy,client,informer,lister" \ 38 | github.com/baidu/ote-stack/pkg/generated github.com/baidu/ote-stack/pkg/apis \ 39 | ote:v1 \ 40 | --output-base "$SCRIPT_ROOT" \ 41 | --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt 42 | 43 | # To use your own boilerplate text append: 44 | # --go-header-file "${SCRIPT_ROOT}"/hack/custom-boilerplate.go.txt 45 | 46 | # move generated code to pkg and clean the output 47 | cp -R $SCRIPT_ROOT/github.com/baidu/ote-stack/pkg/* $SCRIPT_ROOT/pkg && rm -rf $SCRIPT_ROOT/github.com 48 | -------------------------------------------------------------------------------- /hack/verify-codegen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 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 | -------------------------------------------------------------------------------- /pkg/apis/ote/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package ote defines k8s crd used by ote. 18 | package ote 19 | 20 | const ( 21 | // GroupName is spec.groupname of k8s crd, and is the suffix of crd name. 22 | GroupName = "ote.baidu.com" 23 | ) 24 | -------------------------------------------------------------------------------- /pkg/apis/ote/v1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // +k8s:deepcopy-gen=package 18 | // +groupName=ote.baidu.com 19 | 20 | // Package v1 defines version v1 k8s crd used by ote. 21 | package v1 22 | -------------------------------------------------------------------------------- /pkg/apis/ote/v1/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | "k8s.io/apimachinery/pkg/runtime/schema" 23 | 24 | ote "github.com/baidu/ote-stack/pkg/apis/ote" 25 | ) 26 | 27 | // SchemeGroupVersion is group version used to register these objects. 28 | var SchemeGroupVersion = schema.GroupVersion{Group: ote.GroupName, Version: "v1"} 29 | 30 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind. 31 | func Kind(kind string) schema.GroupKind { 32 | return SchemeGroupVersion.WithKind(kind).GroupKind() 33 | } 34 | 35 | // Resource takes an unqualified resource and returns a Group qualified GroupResource. 36 | func Resource(resource string) schema.GroupResource { 37 | return SchemeGroupVersion.WithResource(resource).GroupResource() 38 | } 39 | 40 | // SchemeBuilder and AddToScheme is needed by k8s client-go, can be used to auto-generate crd clientset, etc. 41 | var ( 42 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 43 | AddToScheme = SchemeBuilder.AddToScheme 44 | ) 45 | 46 | // addKnownTypes adds the list of known types to Scheme. 47 | func addKnownTypes(scheme *runtime.Scheme) error { 48 | scheme.AddKnownTypes(SchemeGroupVersion, 49 | &Cluster{}, 50 | &ClusterController{}, 51 | &EdgeNode{}, 52 | ) 53 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/clustermessage/clustermessage.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package clustermessage; 4 | 5 | enum CommandType { 6 | Reserved = 0; // no used 7 | ClusterRegist = 1; // when a cluster regist 8 | ClusterUnregist = 2; // when a cluster unregist 9 | NeighborRoute = 3; // parent send its neighbor route to childs 10 | SubTreeRoute = 4; // child send its subtree route to parent when reconnect 11 | DeployReq = 5; 12 | DeployResp = 6; 13 | ControlReq = 7; 14 | ControlResp = 8; 15 | EdgeReport = 9; // shim report edge status to cloud 16 | ControlMultiReq = 10; //send multiple controller requests 17 | } 18 | 19 | // ClusterMessage is the message between cluster controllers and maybe cc and cluster shim. 20 | message ClusterMessage { 21 | MessageHead Head = 1; 22 | bytes Body = 2; 23 | } 24 | 25 | message MessageHead { 26 | // MessageID is the uuid of a cluster message. 27 | // if the message comes from a crd, the messageid is the name of the crd. 28 | string MessageID = 1; 29 | CommandType Command = 2; 30 | string ClusterSelector = 3; 31 | string ClusterName = 4; 32 | string ParentClusterName = 5; 33 | } 34 | 35 | message ControllerTask { 36 | string Destination = 1; 37 | string Method = 2; 38 | string URI = 3; 39 | bytes Body = 4; 40 | } 41 | 42 | message ControllerTaskResponse { 43 | int64 Timestamp = 1; 44 | int32 StatusCode = 2; 45 | bytes Body = 3; 46 | } 47 | 48 | message DeployTask { 49 | int32 Replicas = 1; 50 | map PodParams = 2; 51 | string Status = 3; 52 | } 53 | 54 | message ControlMultiTask { 55 | string Destination = 1; 56 | string Method = 2; 57 | string URI = 3; 58 | repeated bytes Body = 4; 59 | } -------------------------------------------------------------------------------- /pkg/clustermessage/util.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package clustermessage 18 | 19 | import ( 20 | "fmt" 21 | 22 | proto "github.com/golang/protobuf/proto" 23 | ) 24 | 25 | // Serialize serializes a ClusterMessage to []byte, and return nil error if no error. 26 | func (c *ClusterMessage) Serialize() ([]byte, error) { 27 | data, err := proto.Marshal(c) 28 | if err != nil { 29 | return nil, fmt.Errorf("serialize cluster message(%v) failed: %v", c, err) 30 | } 31 | return data, nil 32 | } 33 | 34 | // Deserialize deserializes data to a ClusterMessage, and return nil if no error. 35 | func (c *ClusterMessage) Deserialize(data []byte) error { 36 | if data == nil { 37 | return fmt.Errorf("deserialize cluster message failed: data is nil") 38 | } 39 | err := proto.Unmarshal(data, c) 40 | if err != nil { 41 | return fmt.Errorf("deserialize cluster message(%s) failed: %v", string(data), err) 42 | } 43 | return nil 44 | } 45 | 46 | //ToClusterMessage makes ControllerTask to ClusterMessage. 47 | func (c *ControllerTask) ToClusterMessage(head *MessageHead) (*ClusterMessage, error) { 48 | if head.Command != CommandType_ControlReq { 49 | return nil, fmt.Errorf("make ControllerTask to ClusterMessage failed: wrong command") 50 | } 51 | 52 | data, err := proto.Marshal(c) 53 | if err != nil { 54 | return nil, fmt.Errorf("make ControllerTask to ClusterMessage failed: %v", err) 55 | } 56 | 57 | ret := &ClusterMessage{ 58 | Head: head, 59 | Body: data, 60 | } 61 | return ret, nil 62 | } 63 | 64 | //ToClusterMessage makes ControlMultiTask to ClusterMessage. 65 | func (c *ControlMultiTask) ToClusterMessage(head *MessageHead) (*ClusterMessage, error) { 66 | if head.Command != CommandType_ControlMultiReq { 67 | return nil, fmt.Errorf("make ControlMultiTask to ClusterMessage failed: wrong command") 68 | } 69 | 70 | data, err := proto.Marshal(c) 71 | if err != nil { 72 | return nil, fmt.Errorf("make ControlMultiTask to ClusterMessage failed: %v", err) 73 | } 74 | 75 | ret := &ClusterMessage{ 76 | Head: head, 77 | Body: data, 78 | } 79 | return ret, nil 80 | } 81 | -------------------------------------------------------------------------------- /pkg/clustermessage/util_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package clustermessage 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestUtil(t *testing.T) { 26 | msg := &ClusterMessage{} 27 | // serialize 28 | data, err := msg.Serialize() 29 | assert.NotNil(t, data) 30 | assert.Nil(t, err) 31 | 32 | // nil deserialize 33 | err = msg.Deserialize(nil) 34 | assert.NotNil(t, err) 35 | // not nil deserialize 36 | err = msg.Deserialize([]byte{}) 37 | assert.Nil(t, err) 38 | err = msg.Deserialize([]byte{'{'}) 39 | assert.NotNil(t, err) 40 | 41 | head1 := &MessageHead{ 42 | Command: CommandType_ControlReq, 43 | } 44 | head2 := &MessageHead{ 45 | Command: CommandType_ControlMultiReq, 46 | } 47 | controllerTask := &ControllerTask{} 48 | controlMultiTask := &ControlMultiTask{} 49 | m, err := controllerTask.ToClusterMessage(head1) 50 | assert.NotNil(t, m) 51 | assert.Nil(t, err) 52 | 53 | m, err = controllerTask.ToClusterMessage(head2) 54 | assert.Nil(t, m) 55 | assert.NotNil(t, err) 56 | 57 | m, err = controlMultiTask.ToClusterMessage(head1) 58 | assert.Nil(t, m) 59 | assert.NotNil(t, err) 60 | 61 | m, err = controlMultiTask.ToClusterMessage(head2) 62 | assert.NotNil(t, m) 63 | assert.Nil(t, err) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/clusterselector/selector.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package clusterselector implements the routing of cluster messages. 18 | package clusterselector 19 | 20 | import ( 21 | "regexp" 22 | "strings" 23 | ) 24 | 25 | const ( 26 | // SelectorPatternDelimiter defines the delimiter of routing rules. 27 | SelectorPatternDelimiter = "," 28 | ) 29 | 30 | // Selector is the interface of cluster selector. 31 | type Selector interface { 32 | // Has determines whether the name matchs the rules. 33 | Has(string) bool 34 | } 35 | 36 | type selector struct { 37 | pattern []string 38 | } 39 | 40 | // NewSelector returns a new selector object with given routing rules. 41 | func NewSelector(s string) Selector { 42 | ps := strings.Split(s, SelectorPatternDelimiter) 43 | for i := range ps { 44 | ps[i] = strings.TrimSpace(ps[i]) 45 | } 46 | return &selector{ps} 47 | } 48 | 49 | func (s *selector) Has(clusterName string) bool { 50 | for _, p := range s.pattern { 51 | if ok, _ := regexp.MatchString(p, clusterName); ok { 52 | return true 53 | } 54 | } 55 | return false 56 | } 57 | 58 | // ClustersToSelector combines given clusters to routing rule. 59 | func ClustersToSelector(clusters *[]string) string { 60 | return strings.Join(*clusters, SelectorPatternDelimiter) 61 | } 62 | -------------------------------------------------------------------------------- /pkg/clusterselector/selector_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package clusterselector 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestSelector(t *testing.T) { 26 | selector := NewSelector("c\\d+,d2") 27 | 28 | assert.True(t, selector.Has("c1")) 29 | assert.True(t, selector.Has("c123")) 30 | assert.True(t, selector.Has("d2")) 31 | assert.True(t, selector.Has("d234")) 32 | assert.False(t, selector.Has("d34")) 33 | 34 | assert.Equal(t, "c1,c2,c3", ClustersToSelector(&[]string{"c1", "c2", "c3"})) 35 | } 36 | -------------------------------------------------------------------------------- /pkg/clustershim/apis/v1/cluster.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package cluster; 4 | message MessageHead { 5 | // MessageID is the uuid of a controller crd. 6 | string MessageID = 1; 7 | string ParentClusterName = 2; 8 | } 9 | // ShimRequest is a request to transmit to target server. 10 | message ShimRequest { 11 | // ParentClusterName is the name of parent cluster. 12 | string ParentClusterName = 1; 13 | // Destination is the target server name. 14 | string Destination = 2; 15 | // Method is the method need to be performed by target server. 16 | string Method = 3; 17 | // URL is the request URL. 18 | string URL = 4; 19 | // Body is the request body. 20 | string Body = 5; 21 | MessageHead Head = 6; 22 | } 23 | 24 | // ShimResponse is a response containing result from target server. 25 | message ShimResponse { 26 | // Timestamp is the timestamp of response. 27 | int64 Timestamp = 1; 28 | // StatusCode is the status code of response. 29 | int32 StatusCode = 2; 30 | // Body is the response body. 31 | string Body = 3; 32 | MessageHead Head = 4; 33 | } 34 | -------------------------------------------------------------------------------- /pkg/clustershim/handler/handler.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package handler provides the ability to interact with k8s or third-party services. 18 | package handler 19 | 20 | import ( 21 | "sync" 22 | "time" 23 | 24 | "github.com/golang/protobuf/proto" 25 | "k8s.io/klog" 26 | 27 | "github.com/baidu/ote-stack/pkg/clustermessage" 28 | ) 29 | 30 | var ( 31 | ShimNewResponse = sync.NewCond(&sync.Mutex{}) 32 | ) 33 | 34 | // Handler is shim handler interface that contains 35 | // the methods required to interact to remote server. 36 | type Handler interface { 37 | // Do handle the request and transmit to corresponding server. 38 | Do(*clustermessage.ClusterMessage) (*clustermessage.ClusterMessage, error) 39 | } 40 | 41 | // Response packages the body message to clustermessage.ClusterMessage. 42 | func Response(body []byte, head *clustermessage.MessageHead) *clustermessage.ClusterMessage { 43 | ShimNewResponse.Broadcast() 44 | msg := &clustermessage.ClusterMessage{ 45 | Head: head, 46 | Body: body, 47 | } 48 | return msg 49 | } 50 | 51 | //ControlTaskResponse packages the body message to clustermessage.ControllerTaskResponse 52 | //and serialize it. 53 | func ControlTaskResponse(status int, body string) []byte { 54 | data := &clustermessage.ControllerTaskResponse{ 55 | Timestamp: time.Now().Unix(), 56 | StatusCode: int32(status), 57 | Body: []byte(body), 58 | } 59 | 60 | resp, err := proto.Marshal(data) 61 | if err != nil { 62 | klog.Errorf("marshal ControllerTaskResponse failed: %v", err) 63 | return nil 64 | } 65 | return resp 66 | } 67 | 68 | func GetControllerTaskFromClusterMessage( 69 | msg *clustermessage.ClusterMessage) *clustermessage.ControllerTask { 70 | if msg == nil { 71 | return nil 72 | } 73 | task := &clustermessage.ControllerTask{} 74 | err := proto.Unmarshal([]byte(msg.Body), task) 75 | if err != nil { 76 | klog.Errorf("unmarshal controller task failed: %v", err) 77 | return nil 78 | } 79 | return task 80 | } 81 | 82 | func GetControlMultiTaskFromClusterMessage( 83 | msg *clustermessage.ClusterMessage) *clustermessage.ControlMultiTask { 84 | if msg == nil { 85 | return nil 86 | } 87 | task := &clustermessage.ControlMultiTask{} 88 | err := proto.Unmarshal([]byte(msg.Body), task) 89 | if err != nil { 90 | klog.Errorf("unmarshal ControlMultiTask failed: %v", err) 91 | return nil 92 | } 93 | return task 94 | } 95 | -------------------------------------------------------------------------------- /pkg/clustershim/handler/handler_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package handler 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | 24 | "github.com/baidu/ote-stack/pkg/clustermessage" 25 | ) 26 | 27 | func TestResponse (t *testing.T) { 28 | head := &clustermessage.MessageHead{ 29 | Command: clustermessage.CommandType_ControlReq, 30 | } 31 | resp := Response(nil, head) 32 | assert.NotNil(t, resp) 33 | } 34 | 35 | func TestControlTaskResponse(t *testing.T) { 36 | resp := ControlTaskResponse(200, "") 37 | assert.NotNil(t, resp) 38 | } 39 | 40 | func TestGetControllerTask(t *testing.T) { 41 | ret := GetControllerTaskFromClusterMessage(nil) 42 | assert.Nil(t, ret) 43 | 44 | msg := &clustermessage.ClusterMessage{ 45 | Body: []byte{1}, 46 | } 47 | ret = GetControllerTaskFromClusterMessage(msg) 48 | assert.Nil(t, ret) 49 | } 50 | 51 | func TestGetControlMultiTask(t *testing.T) { 52 | ret := GetControlMultiTaskFromClusterMessage(nil) 53 | assert.Nil(t, ret) 54 | 55 | msg := &clustermessage.ClusterMessage{ 56 | Body: []byte{1}, 57 | } 58 | ret = GetControlMultiTaskFromClusterMessage(msg) 59 | assert.Nil(t, ret) 60 | } -------------------------------------------------------------------------------- /pkg/config/config_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package config 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestIsRoot(t *testing.T) { 26 | assert.True(t, IsRoot("root")) 27 | assert.False(t, IsRoot("a")) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/controller/namespace/namespace_controller.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | //Package namespace watch Namespace resource if it is created, 18 | //and send it to all clusters. 19 | package namespace 20 | 21 | import ( 22 | "fmt" 23 | "net/http" 24 | 25 | v1 "k8s.io/api/core/v1" 26 | "k8s.io/client-go/tools/cache" 27 | "k8s.io/klog" 28 | 29 | otev1 "github.com/baidu/ote-stack/pkg/apis/ote/v1" 30 | "github.com/baidu/ote-stack/pkg/clustermessage" 31 | "github.com/baidu/ote-stack/pkg/controller" 32 | "github.com/baidu/ote-stack/pkg/controllermanager" 33 | ) 34 | 35 | //NamespaceController is responsible for performing actions dependent upon a namespace phase. 36 | type NamespaceController struct { 37 | sendChan chan clustermessage.ClusterMessage 38 | } 39 | 40 | //InitNamespaceController inits namespace controller. 41 | func InitNamespaceController(ctx *controllermanager.ControllerContext) error { 42 | namespaceController := &NamespaceController{ 43 | sendChan: ctx.PublishChan, 44 | } 45 | ctx.InformerFactory.Core().V1().Namespaces().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ 46 | AddFunc: namespaceController.handleAddedEvent, 47 | }) 48 | 49 | return nil 50 | } 51 | 52 | //handleAddedEvent handles Added Event when new namespace was created, 53 | //and send the new namespace to all clusters. 54 | func (c *NamespaceController) handleAddedEvent(obj interface{}) { 55 | namespace := obj.(*v1.Namespace) 56 | klog.V(3).Infof("new namespace added: %v", namespace.ObjectMeta.Name) 57 | 58 | err := c.sendNamespaceToCluster(namespace) 59 | if err != nil { 60 | klog.Errorf("send namespace to cluster failed: %v", err) 61 | } 62 | } 63 | 64 | //sendNamespaceToCluster sends new namespace to all clusters. 65 | func (c *NamespaceController) sendNamespaceToCluster(namespace *v1.Namespace) error { 66 | name, err := controller.SerializeNamespaceObject(namespace.ObjectMeta.Name) 67 | if err != nil { 68 | return fmt.Errorf("serialize namespace object %s failed: %v", namespace.ObjectMeta.Name, err) 69 | } 70 | 71 | data := &clustermessage.ControllerTask{ 72 | Destination: otev1.ClusterControllerDestAPI, 73 | Method: http.MethodPost, 74 | URI: controller.OteNamespaceURI, 75 | Body: name, 76 | } 77 | head := &clustermessage.MessageHead{ 78 | ClusterSelector: "", 79 | Command: clustermessage.CommandType_ControlReq, 80 | } 81 | msg, err := data.ToClusterMessage(head) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | c.sendChan <- *msg 87 | return nil 88 | } 89 | -------------------------------------------------------------------------------- /pkg/controller/namespace/namespace_controller_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package namespace 18 | 19 | import ( 20 | "testing" 21 | "time" 22 | 23 | "github.com/stretchr/testify/assert" 24 | v1 "k8s.io/api/core/v1" 25 | "k8s.io/apimachinery/pkg/runtime" 26 | "k8s.io/client-go/informers" 27 | k8sfake "k8s.io/client-go/kubernetes/fake" 28 | 29 | "github.com/baidu/ote-stack/pkg/clustermessage" 30 | "github.com/baidu/ote-stack/pkg/controllermanager" 31 | ) 32 | 33 | var ( 34 | noResyncPeriodFunc = func() time.Duration { return 0 } 35 | ) 36 | 37 | type fixture struct { 38 | t *testing.T 39 | kubeClient *k8sfake.Clientset 40 | kubeObjects []runtime.Object 41 | } 42 | 43 | func newFixture(t *testing.T) *fixture { 44 | f := &fixture{} 45 | f.t = t 46 | f.kubeObjects = []runtime.Object{} 47 | return f 48 | } 49 | 50 | func newFakeNamespace(name string) *v1.Namespace { 51 | return &v1.Namespace{} 52 | } 53 | 54 | func newFakeNamespaceController() *NamespaceController { 55 | namespaceController := &NamespaceController{ 56 | sendChan: make(chan clustermessage.ClusterMessage, 1), 57 | } 58 | 59 | return namespaceController 60 | } 61 | 62 | func TestInitNamespaceController(t *testing.T) { 63 | f := newFixture(t) 64 | f.kubeClient = k8sfake.NewSimpleClientset(f.kubeObjects...) 65 | 66 | k8sInformer := informers.NewSharedInformerFactory(f.kubeClient, noResyncPeriodFunc()) 67 | 68 | ctx := &controllermanager.ControllerContext{ 69 | K8sContext: controllermanager.K8sContext{ 70 | InformerFactory: k8sInformer, 71 | }, 72 | } 73 | 74 | err := InitNamespaceController(ctx) 75 | assert.Nil(t, err) 76 | } 77 | 78 | func TestSendNamespaceToCluster(t *testing.T) { 79 | fakeController := newFakeNamespaceController() 80 | namespace := newFakeNamespace("") 81 | 82 | err := fakeController.sendNamespaceToCluster(namespace) 83 | assert.Nil(t, err) 84 | } 85 | -------------------------------------------------------------------------------- /pkg/controller/util.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | //Package controller provides some method to help controller handles event. 18 | package controller 19 | 20 | import ( 21 | "encoding/json" 22 | "fmt" 23 | ) 24 | 25 | const ( 26 | OteNamespaceKind = "Namespace" 27 | OteNamespaceURI = "/api/v1/namespaces" 28 | OteApiVersionV1 = "v1" 29 | ) 30 | 31 | //oteNamespace is responsible for constructing namespace object. 32 | type oteNamespace struct { 33 | Kind string `json:"kind"` 34 | ApiVersion string `json:"apiVersion"` 35 | MetaData map[string]string `json:"metadata"` 36 | } 37 | 38 | //SerializeNamespaceObject serializes an oteNamespace to be the body of 39 | //k8s rest request with specific name. 40 | func SerializeNamespaceObject(name string) ([]byte, error) { 41 | data := make(map[string]string) 42 | data["name"] = name 43 | msg := oteNamespace{ 44 | Kind: OteNamespaceKind, 45 | ApiVersion: OteApiVersionV1, 46 | MetaData: data, 47 | } 48 | ret, err := json.Marshal(msg) 49 | if err != nil { 50 | return nil, fmt.Errorf("marshal Namespace Object failed.") 51 | } 52 | return ret, nil 53 | } 54 | -------------------------------------------------------------------------------- /pkg/controller/util_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package controller 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestSerializeNamespaceObject(t *testing.T) { 26 | data, err := SerializeNamespaceObject("wangpan") 27 | assert.Nil(t, err) 28 | assert.NotNil(t, data) 29 | } 30 | -------------------------------------------------------------------------------- /pkg/controllermanager/cluster_status_processor.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package controllermanager 18 | 19 | import ( 20 | "fmt" 21 | 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | "k8s.io/klog" 24 | 25 | otev1 "github.com/baidu/ote-stack/pkg/apis/ote/v1" 26 | ) 27 | 28 | func (u *UpstreamProcessor) handleClusterStatusReport(clustername string, statusbody []byte) error { 29 | status, err := otev1.ClusterStatusDeserialize(statusbody) 30 | if err != nil { 31 | return fmt.Errorf("status body of cluster %s deserialize failed : %v", clustername, err) 32 | } 33 | 34 | klog.V(3).Infof("update cluster status: name=%s, status=%v", clustername, status) 35 | 36 | err = u.UpdateClusterStatus(clustername, status) 37 | if err != nil { 38 | return fmt.Errorf("update cluster % status failed : %v", clustername, err) 39 | } 40 | 41 | return nil 42 | } 43 | 44 | // UpdateClusterStatus update status of the given cluster. 45 | func (u *UpstreamProcessor) UpdateClusterStatus(clustername string, status *otev1.ClusterStatus) error { 46 | cluster := &otev1.Cluster{ 47 | ObjectMeta: metav1.ObjectMeta{ 48 | Namespace: otev1.ClusterNamespace, 49 | Name: clustername, 50 | }, 51 | Status: *status, 52 | } 53 | 54 | return u.clusterCRD.PatchStatus(cluster) 55 | } 56 | -------------------------------------------------------------------------------- /pkg/controllermanager/cluster_status_processor_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package controllermanager 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | 25 | otev1 "github.com/baidu/ote-stack/pkg/apis/ote/v1" 26 | "github.com/baidu/ote-stack/pkg/k8sclient" 27 | otefake "github.com/baidu/ote-stack/pkg/k8sclient/fake" 28 | ) 29 | 30 | func TestHandleClusterStatusReport(t *testing.T) { 31 | cluster1 := &otev1.Cluster{ 32 | ObjectMeta: metav1.ObjectMeta{ 33 | Namespace: otev1.ClusterNamespace, 34 | Name: "c1", 35 | }, 36 | Status: otev1.ClusterStatus{ 37 | Timestamp: 1571360000, 38 | }, 39 | } 40 | 41 | processor := &UpstreamProcessor{ 42 | clusterCRD: k8sclient.NewClusterCRD(otefake.NewSimpleClientset(cluster1)), 43 | } 44 | 45 | testcase := []struct { 46 | Name string 47 | ClusterName string 48 | ReportBody []byte 49 | ExpectError bool 50 | }{ 51 | { 52 | Name: "success to update cluster status", 53 | ClusterName: "c1", 54 | ReportBody: []byte(`{"timestamp":1571360001,"capacity":{"cpu":"16","memory":"12Gi"},"allocatable":{"cpu":"12","memory":"12Gi"}}`), 55 | ExpectError: false, 56 | }, 57 | { 58 | Name: "fail to update a non-existent cluster", 59 | ClusterName: "c2", 60 | ReportBody: []byte(`{"capacity":{"cpu":"16"},"allocatable":{"cpu":"12"}}`), 61 | ExpectError: true, 62 | }, 63 | { 64 | Name: "fail to update a expired cluster status", 65 | ClusterName: "c1", 66 | ReportBody: []byte(`{"timestamp":1571350000,"capacity":{"cpu":"16"},"allocatable":{"cpu":"12"}}`), 67 | ExpectError: true, 68 | }, 69 | } 70 | 71 | for _, tc := range testcase { 72 | t.Run(tc.Name, func(t *testing.T) { 73 | assert := assert.New(t) 74 | err := processor.handleClusterStatusReport(tc.ClusterName, tc.ReportBody) 75 | if tc.ExpectError { 76 | assert.Error(err) 77 | } else { 78 | assert.NoError(err) 79 | } 80 | }) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /pkg/controllermanager/controllermanager.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package controllermanager 18 | 19 | import ( 20 | "k8s.io/client-go/informers" 21 | "k8s.io/client-go/kubernetes" 22 | 23 | "github.com/baidu/ote-stack/pkg/clustermessage" 24 | oteclient "github.com/baidu/ote-stack/pkg/generated/clientset/versioned" 25 | oteinformer "github.com/baidu/ote-stack/pkg/generated/informers/externalversions" 26 | "github.com/baidu/ote-stack/pkg/tunnel" 27 | ) 28 | 29 | // ControllerContext is the context needed by all controllers. 30 | // ControllerContext woubld be a param when start a controller. 31 | type ControllerContext struct { 32 | K8sContext 33 | 34 | // a channel to publish msg to root cluster controller 35 | PublishChan chan clustermessage.ClusterMessage 36 | // a tunnel connected to root cluster controller 37 | controllerTunnel tunnel.ControllerTunnel 38 | //StopChan is the stop channel 39 | StopChan <-chan struct{} 40 | } 41 | 42 | // InitFunc is the function to start a controller within a context. 43 | type InitFunc func(ctx *ControllerContext) error 44 | 45 | // K8sContext is the context of all object related to k8s. 46 | type K8sContext struct { 47 | OteClient oteclient.Interface 48 | OteInformerFactory oteinformer.SharedInformerFactory 49 | 50 | K8sClient kubernetes.Interface 51 | InformerFactory informers.SharedInformerFactory 52 | } 53 | -------------------------------------------------------------------------------- /pkg/edgehandler/func.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package edgehandler 18 | 19 | import ( 20 | "github.com/golang/protobuf/proto" 21 | "k8s.io/klog" 22 | 23 | "github.com/baidu/ote-stack/pkg/clustermessage" 24 | pb "github.com/baidu/ote-stack/pkg/clustershim/apis/v1" 25 | ) 26 | 27 | func pb2SerializedControllerTaskResp( 28 | in *pb.ShimResponse) (*pb.MessageHead, []byte) { 29 | resp := &clustermessage.ControllerTaskResponse{ 30 | Timestamp: in.Timestamp, 31 | StatusCode: in.StatusCode, 32 | Body: []byte(in.Body), 33 | } 34 | data, err := proto.Marshal(resp) 35 | if err != nil { 36 | klog.Errorf("transfer shim resp to controller task resp failed: %v", err) 37 | return nil, nil 38 | } 39 | return in.Head, data 40 | } 41 | 42 | func controllerTask2Pb( 43 | msg *clustermessage.ClusterMessage, task *clustermessage.ControllerTask) *pb.ShimRequest { 44 | return &pb.ShimRequest{ 45 | ParentClusterName: msg.Head.ParentClusterName, 46 | Destination: task.Destination, 47 | Method: task.Method, 48 | URL: task.URI, 49 | Body: string(task.Body), 50 | Head: &pb.MessageHead{ 51 | MessageID: msg.Head.MessageID, 52 | ParentClusterName: msg.Head.ParentClusterName, 53 | }, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pkg/eventrecorder/local_eventrecorder.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package eventrecorder defines event recorder for k8s leader election. 18 | package eventrecorder 19 | 20 | import ( 21 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 | "k8s.io/apimachinery/pkg/runtime" 23 | "k8s.io/klog" 24 | ) 25 | 26 | // LocalEventRecorder is a recorder for leaderelection which print event log to local logs. 27 | // LocalEventRecorder implements recode.EventRecorder interface. 28 | // only Eventf func is needed. 29 | type LocalEventRecorder struct{} 30 | 31 | func (ler *LocalEventRecorder) Eventf(obj runtime.Object, eventType, reason, message string, args ...interface{}) { 32 | klog.Infof("local event record[%v][%s][%s][%s]%v", 33 | obj, eventType, reason, message, args) 34 | } 35 | 36 | func (ler *LocalEventRecorder) Event(object runtime.Object, eventtype, reason, message string) {} 37 | 38 | func (ler *LocalEventRecorder) PastEventf(object runtime.Object, timestamp metav1.Time, eventtype, reason, messageFmt string, args ...interface{}) { 39 | } 40 | 41 | func (ler *LocalEventRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) { 42 | } 43 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated clientset. 20 | package versioned 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/fake/clientset_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | clientset "github.com/baidu/ote-stack/pkg/generated/clientset/versioned" 23 | otev1 "github.com/baidu/ote-stack/pkg/generated/clientset/versioned/typed/ote/v1" 24 | fakeotev1 "github.com/baidu/ote-stack/pkg/generated/clientset/versioned/typed/ote/v1/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 | // OteV1 retrieves the OteV1Client 80 | func (c *Clientset) OteV1() otev1.OteV1Interface { 81 | return &fakeotev1.FakeOteV1{Fake: &c.Fake} 82 | } 83 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated fake clientset. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/fake/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | otev1 "github.com/baidu/ote-stack/pkg/apis/ote/v1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 27 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 28 | ) 29 | 30 | var scheme = runtime.NewScheme() 31 | var codecs = serializer.NewCodecFactory(scheme) 32 | var parameterCodec = runtime.NewParameterCodec(scheme) 33 | var localSchemeBuilder = runtime.SchemeBuilder{ 34 | otev1.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/generated/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package contains the scheme of the automatically generated clientset. 20 | package scheme 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/scheme/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package scheme 20 | 21 | import ( 22 | otev1 "github.com/baidu/ote-stack/pkg/apis/ote/v1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 27 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 28 | ) 29 | 30 | var Scheme = runtime.NewScheme() 31 | var Codecs = serializer.NewCodecFactory(Scheme) 32 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 33 | var localSchemeBuilder = runtime.SchemeBuilder{ 34 | otev1.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/generated/clientset/versioned/typed/ote/v1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v1 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/ote/v1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/ote/v1/fake/fake_ote_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1 "github.com/baidu/ote-stack/pkg/generated/clientset/versioned/typed/ote/v1" 23 | rest "k8s.io/client-go/rest" 24 | testing "k8s.io/client-go/testing" 25 | ) 26 | 27 | type FakeOteV1 struct { 28 | *testing.Fake 29 | } 30 | 31 | func (c *FakeOteV1) Clusters(namespace string) v1.ClusterInterface { 32 | return &FakeClusters{c, namespace} 33 | } 34 | 35 | func (c *FakeOteV1) ClusterControllers(namespace string) v1.ClusterControllerInterface { 36 | return &FakeClusterControllers{c, namespace} 37 | } 38 | 39 | func (c *FakeOteV1) EdgeNodes(namespace string) v1.EdgeNodeInterface { 40 | return &FakeEdgeNodes{c, namespace} 41 | } 42 | 43 | // RESTClient returns a RESTClient that is used to communicate 44 | // with API server by this client implementation. 45 | func (c *FakeOteV1) RESTClient() rest.Interface { 46 | var ret *rest.RESTClient 47 | return ret 48 | } 49 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/ote/v1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | type ClusterExpansion interface{} 22 | 23 | type ClusterControllerExpansion interface{} 24 | 25 | type EdgeNodeExpansion interface{} 26 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/ote/v1/ote_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | v1 "github.com/baidu/ote-stack/pkg/apis/ote/v1" 23 | "github.com/baidu/ote-stack/pkg/generated/clientset/versioned/scheme" 24 | rest "k8s.io/client-go/rest" 25 | ) 26 | 27 | type OteV1Interface interface { 28 | RESTClient() rest.Interface 29 | ClustersGetter 30 | ClusterControllersGetter 31 | EdgeNodesGetter 32 | } 33 | 34 | // OteV1Client is used to interact with features provided by the ote.baidu.com group. 35 | type OteV1Client struct { 36 | restClient rest.Interface 37 | } 38 | 39 | func (c *OteV1Client) Clusters(namespace string) ClusterInterface { 40 | return newClusters(c, namespace) 41 | } 42 | 43 | func (c *OteV1Client) ClusterControllers(namespace string) ClusterControllerInterface { 44 | return newClusterControllers(c, namespace) 45 | } 46 | 47 | func (c *OteV1Client) EdgeNodes(namespace string) EdgeNodeInterface { 48 | return newEdgeNodes(c, namespace) 49 | } 50 | 51 | // NewForConfig creates a new OteV1Client for the given config. 52 | func NewForConfig(c *rest.Config) (*OteV1Client, error) { 53 | config := *c 54 | if err := setConfigDefaults(&config); err != nil { 55 | return nil, err 56 | } 57 | client, err := rest.RESTClientFor(&config) 58 | if err != nil { 59 | return nil, err 60 | } 61 | return &OteV1Client{client}, nil 62 | } 63 | 64 | // NewForConfigOrDie creates a new OteV1Client for the given config and 65 | // panics if there is an error in the config. 66 | func NewForConfigOrDie(c *rest.Config) *OteV1Client { 67 | client, err := NewForConfig(c) 68 | if err != nil { 69 | panic(err) 70 | } 71 | return client 72 | } 73 | 74 | // New creates a new OteV1Client for the given RESTClient. 75 | func New(c rest.Interface) *OteV1Client { 76 | return &OteV1Client{c} 77 | } 78 | 79 | func setConfigDefaults(config *rest.Config) error { 80 | gv := v1.SchemeGroupVersion 81 | config.GroupVersion = &gv 82 | config.APIPath = "/apis" 83 | config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 84 | 85 | if config.UserAgent == "" { 86 | config.UserAgent = rest.DefaultKubernetesUserAgent() 87 | } 88 | 89 | return nil 90 | } 91 | 92 | // RESTClient returns a RESTClient that is used to communicate 93 | // with API server by this client implementation. 94 | func (c *OteV1Client) RESTClient() rest.Interface { 95 | if c == nil { 96 | return nil 97 | } 98 | return c.restClient 99 | } 100 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/generic.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | "fmt" 23 | 24 | v1 "github.com/baidu/ote-stack/pkg/apis/ote/v1" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | cache "k8s.io/client-go/tools/cache" 27 | ) 28 | 29 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other 30 | // sharedInformers based on type 31 | type GenericInformer interface { 32 | Informer() cache.SharedIndexInformer 33 | Lister() cache.GenericLister 34 | } 35 | 36 | type genericInformer struct { 37 | informer cache.SharedIndexInformer 38 | resource schema.GroupResource 39 | } 40 | 41 | // Informer returns the SharedIndexInformer. 42 | func (f *genericInformer) Informer() cache.SharedIndexInformer { 43 | return f.informer 44 | } 45 | 46 | // Lister returns the GenericLister. 47 | func (f *genericInformer) Lister() cache.GenericLister { 48 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) 49 | } 50 | 51 | // ForResource gives generic access to a shared informer of the matching type 52 | // TODO extend this to unknown resources with a client pool 53 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { 54 | switch resource { 55 | // Group=ote.baidu.com, Version=v1 56 | case v1.SchemeGroupVersion.WithResource("clusters"): 57 | return &genericInformer{resource: resource.GroupResource(), informer: f.Ote().V1().Clusters().Informer()}, nil 58 | case v1.SchemeGroupVersion.WithResource("clustercontrollers"): 59 | return &genericInformer{resource: resource.GroupResource(), informer: f.Ote().V1().ClusterControllers().Informer()}, nil 60 | case v1.SchemeGroupVersion.WithResource("edgenodes"): 61 | return &genericInformer{resource: resource.GroupResource(), informer: f.Ote().V1().EdgeNodes().Informer()}, nil 62 | 63 | } 64 | 65 | return nil, fmt.Errorf("no informer found for %v", resource) 66 | } 67 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package internalinterfaces 20 | 21 | import ( 22 | time "time" 23 | 24 | versioned "github.com/baidu/ote-stack/pkg/generated/clientset/versioned" 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | runtime "k8s.io/apimachinery/pkg/runtime" 27 | cache "k8s.io/client-go/tools/cache" 28 | ) 29 | 30 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. 31 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer 32 | 33 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle 34 | type SharedInformerFactory interface { 35 | Start(stopCh <-chan struct{}) 36 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer 37 | } 38 | 39 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions. 40 | type TweakListOptionsFunc func(*v1.ListOptions) 41 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/ote/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package ote 20 | 21 | import ( 22 | internalinterfaces "github.com/baidu/ote-stack/pkg/generated/informers/externalversions/internalinterfaces" 23 | v1 "github.com/baidu/ote-stack/pkg/generated/informers/externalversions/ote/v1" 24 | ) 25 | 26 | // Interface provides access to each of this group's versions. 27 | type Interface interface { 28 | // V1 provides access to shared informers for resources in V1. 29 | V1() v1.Interface 30 | } 31 | 32 | type group struct { 33 | factory internalinterfaces.SharedInformerFactory 34 | namespace string 35 | tweakListOptions internalinterfaces.TweakListOptionsFunc 36 | } 37 | 38 | // New returns a new Interface. 39 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 40 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 41 | } 42 | 43 | // V1 returns a new v1.Interface. 44 | func (g *group) V1() v1.Interface { 45 | return v1.New(g.factory, g.namespace, g.tweakListOptions) 46 | } 47 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/ote/v1/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | internalinterfaces "github.com/baidu/ote-stack/pkg/generated/informers/externalversions/internalinterfaces" 23 | ) 24 | 25 | // Interface provides access to all the informers in this group version. 26 | type Interface interface { 27 | // Clusters returns a ClusterInformer. 28 | Clusters() ClusterInformer 29 | // ClusterControllers returns a ClusterControllerInformer. 30 | ClusterControllers() ClusterControllerInformer 31 | // EdgeNodes returns a EdgeNodeInformer. 32 | EdgeNodes() EdgeNodeInformer 33 | } 34 | 35 | type version struct { 36 | factory internalinterfaces.SharedInformerFactory 37 | namespace string 38 | tweakListOptions internalinterfaces.TweakListOptionsFunc 39 | } 40 | 41 | // New returns a new Interface. 42 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 43 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 44 | } 45 | 46 | // Clusters returns a ClusterInformer. 47 | func (v *version) Clusters() ClusterInformer { 48 | return &clusterInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 49 | } 50 | 51 | // ClusterControllers returns a ClusterControllerInformer. 52 | func (v *version) ClusterControllers() ClusterControllerInformer { 53 | return &clusterControllerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 54 | } 55 | 56 | // EdgeNodes returns a EdgeNodeInformer. 57 | func (v *version) EdgeNodes() EdgeNodeInformer { 58 | return &edgeNodeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 59 | } 60 | -------------------------------------------------------------------------------- /pkg/generated/listers/ote/v1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | // ClusterListerExpansion allows custom methods to be added to 22 | // ClusterLister. 23 | type ClusterListerExpansion interface{} 24 | 25 | // ClusterNamespaceListerExpansion allows custom methods to be added to 26 | // ClusterNamespaceLister. 27 | type ClusterNamespaceListerExpansion interface{} 28 | 29 | // ClusterControllerListerExpansion allows custom methods to be added to 30 | // ClusterControllerLister. 31 | type ClusterControllerListerExpansion interface{} 32 | 33 | // ClusterControllerNamespaceListerExpansion allows custom methods to be added to 34 | // ClusterControllerNamespaceLister. 35 | type ClusterControllerNamespaceListerExpansion interface{} 36 | 37 | // EdgeNodeListerExpansion allows custom methods to be added to 38 | // EdgeNodeLister. 39 | type EdgeNodeListerExpansion interface{} 40 | 41 | // EdgeNodeNamespaceListerExpansion allows custom methods to be added to 42 | // EdgeNodeNamespaceLister. 43 | type EdgeNodeNamespaceListerExpansion interface{} 44 | -------------------------------------------------------------------------------- /pkg/k8sclient/clustercontroller.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package k8sclient 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/klog" 22 | 23 | otev1 "github.com/baidu/ote-stack/pkg/apis/ote/v1" 24 | oteclient "github.com/baidu/ote-stack/pkg/generated/clientset/versioned" 25 | ) 26 | 27 | // ClusterControllerCRD manipulates ClusterController crd. 28 | type ClusterControllerCRD struct { 29 | client oteclient.Interface 30 | } 31 | 32 | // NewClusterControllerCRD new a ClusterControllerCRD with k8s client. 33 | func NewClusterControllerCRD(client oteclient.Interface) *ClusterControllerCRD { 34 | return &ClusterControllerCRD{client} 35 | } 36 | 37 | // Get get a ClusterController by namespace and name. 38 | func (c *ClusterControllerCRD) Get(namespace, name string) *otev1.ClusterController { 39 | cc, err := c.client.OteV1().ClusterControllers(namespace).Get(name, metav1.GetOptions{}) 40 | if err != nil { 41 | klog.Errorf("get clustercontroller(%s-%s) failed: %v", namespace, name, err) 42 | return nil 43 | } 44 | return cc 45 | } 46 | 47 | // Update update a ClusterControllers. 48 | func (c *ClusterControllerCRD) Update(cc *otev1.ClusterController) { 49 | _, err := c.client.OteV1().ClusterControllers(cc.ObjectMeta.Namespace).Update(cc) 50 | if err != nil { 51 | klog.Errorf("update clustercontroller(%v) failed: %v", cc, err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /pkg/loadbalancer/util.go: -------------------------------------------------------------------------------- 1 | package loadbalancer 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "net" 7 | "reflect" 8 | "sort" 9 | "strconv" 10 | 11 | v1 "k8s.io/api/core/v1" 12 | ) 13 | 14 | // setServers set the discovery server list in load balancer. 15 | func (lb *LoadBalancer) setServers(serverAddresses []string) bool { 16 | serverAddresses, hasOriginalServer := sortServers(serverAddresses, lb.originalServerAddress) 17 | if len(serverAddresses) == 0 { 18 | return false 19 | } 20 | 21 | lb.mutex.Lock() 22 | defer lb.mutex.Unlock() 23 | 24 | if reflect.DeepEqual(serverAddresses, lb.ServerAddresses) { 25 | return false 26 | } 27 | 28 | lb.ServerAddresses = serverAddresses 29 | lb.randomServers = append([]string{}, lb.ServerAddresses...) 30 | rand.Shuffle(len(lb.randomServers), func(i, j int) { 31 | lb.randomServers[i], lb.randomServers[j] = lb.randomServers[j], lb.randomServers[i] 32 | }) 33 | if !hasOriginalServer { 34 | lb.randomServers = append(lb.randomServers, lb.originalServerAddress) 35 | } 36 | lb.currentServerAddress = lb.randomServers[0] 37 | lb.nextServerIndex = 1 38 | 39 | return true 40 | } 41 | 42 | // nextServer get the next backup server in load balancer's list. 43 | func (lb *LoadBalancer) nextServer(failedServer string) (string, error) { 44 | lb.mutex.Lock() 45 | defer lb.mutex.Unlock() 46 | 47 | if len(lb.randomServers) == 0 { 48 | return "", fmt.Errorf("No servers in load balancer proxy list") 49 | } 50 | if len(lb.randomServers) == 1 { 51 | return lb.currentServerAddress, nil 52 | } 53 | if failedServer != lb.currentServerAddress { 54 | return lb.currentServerAddress, nil 55 | } 56 | if lb.nextServerIndex >= len(lb.randomServers) { 57 | lb.nextServerIndex = 0 58 | } 59 | 60 | lb.currentServerAddress = lb.randomServers[lb.nextServerIndex] 61 | lb.nextServerIndex++ 62 | 63 | return lb.currentServerAddress, nil 64 | } 65 | 66 | // sortServers check if the searched address in input list, and return 67 | // the sorted list server address. 68 | func sortServers(input []string, search string) ([]string, bool) { 69 | result := []string{} 70 | found := false 71 | skip := map[string]bool{"": true} 72 | 73 | for _, entry := range input { 74 | if skip[entry] { 75 | continue 76 | } 77 | if search == entry { 78 | found = true 79 | } 80 | skip[entry] = true 81 | result = append(result, entry) 82 | } 83 | 84 | sort.Strings(result) 85 | return result, found 86 | } 87 | 88 | // getAddresses return address list from endpoint resource. 89 | func getAddresses(endpoint *v1.Endpoints) []string { 90 | serverAddresses := []string{} 91 | if endpoint == nil { 92 | return serverAddresses 93 | } 94 | for _, subset := range endpoint.Subsets { 95 | var port string 96 | if len(subset.Ports) > 0 { 97 | port = strconv.Itoa(int(subset.Ports[0].Port)) 98 | } 99 | if port == "" { 100 | port = "443" 101 | } 102 | for _, address := range subset.Addresses { 103 | serverAddresses = append(serverAddresses, net.JoinHostPort(address.IP, port)) 104 | } 105 | } 106 | return serverAddresses 107 | } 108 | -------------------------------------------------------------------------------- /pkg/loadbalancer/util_test.go: -------------------------------------------------------------------------------- 1 | package loadbalancer 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | corev1 "k8s.io/api/core/v1" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | func newEndpoint() *corev1.Endpoints { 12 | addr := corev1.EndpointAddress{ 13 | IP: "1.1.1.1", 14 | } 15 | port := corev1.EndpointPort{ 16 | Port: 80, 17 | } 18 | 19 | s := corev1.EndpointSubset{ 20 | Addresses: []corev1.EndpointAddress{ 21 | addr, 22 | }, 23 | Ports: []corev1.EndpointPort{ 24 | port, 25 | }, 26 | } 27 | 28 | return &corev1.Endpoints{ 29 | ObjectMeta: metav1.ObjectMeta{ 30 | Name: "test", 31 | Namespace: "default", 32 | }, 33 | Subsets: []corev1.EndpointSubset{s}, 34 | } 35 | } 36 | 37 | func TestSetServers(t *testing.T) { 38 | lb := LoadBalancer{ 39 | ServerAddresses: []string{"1.1.1.1"}, 40 | originalServerAddress: "1.1.1.1", 41 | } 42 | 43 | serverList := []string{"1.1.1.1"} 44 | result := lb.setServers(serverList) 45 | assert.Equal(t, false, result) 46 | assert.Equal(t, []string{"1.1.1.1"}, lb.ServerAddresses) 47 | assert.Equal(t, 0, len(lb.randomServers)) 48 | 49 | serverList = []string{"2.2.2.2"} 50 | result = lb.setServers(serverList) 51 | assert.Equal(t, true, result) 52 | assert.Equal(t, []string{"2.2.2.2"}, lb.ServerAddresses) 53 | assert.Equal(t, 2, len(lb.randomServers)) 54 | } 55 | 56 | func TestNextServer(t *testing.T) { 57 | lb := LoadBalancer{ 58 | randomServers: []string{"1.1.1.1", "2.2.2.2"}, 59 | currentServerAddress: "1.1.1.1", 60 | nextServerIndex: 1, 61 | } 62 | 63 | addr, err := lb.nextServer("1.1.1.1") 64 | assert.Nil(t, err) 65 | assert.Equal(t, "2.2.2.2", addr) 66 | assert.Equal(t, 2, lb.nextServerIndex) 67 | } 68 | 69 | func TestSortServer(t *testing.T) { 70 | list := []string{"2.2.2.2", "1.1.1.1", "3.3.3.3"} 71 | 72 | result, found := sortServers(list, "1.1.1.1") 73 | assert.Equal(t, true, found) 74 | assert.Equal(t, []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"}, result) 75 | 76 | result, found = sortServers(list, "4.4.4.4") 77 | assert.Equal(t, false, found) 78 | assert.Equal(t, []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"}, result) 79 | } 80 | 81 | func TestGetAddress(t *testing.T) { 82 | ep := newEndpoint() 83 | list := getAddresses(ep) 84 | assert.Equal(t, []string{"1.1.1.1:80"}, list) 85 | } 86 | -------------------------------------------------------------------------------- /pkg/reporter/event_reporter_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package reporter 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | corev1 "k8s.io/api/core/v1" 24 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 | 26 | "github.com/baidu/ote-stack/pkg/clustermessage" 27 | ) 28 | 29 | func newEvent() *corev1.Event { 30 | return &corev1.Event{ 31 | ObjectMeta: metav1.ObjectMeta{ 32 | Name: name, 33 | Namespace: namespace, 34 | }, 35 | InvolvedObject: corev1.ObjectReference{ 36 | Kind: "Pod", 37 | }, 38 | } 39 | } 40 | 41 | func (f *fixture) newEventReporter() *EventReporter { 42 | ctx := f.newReportContext() 43 | 44 | eventReporter := &EventReporter{ 45 | ctx: ctx, 46 | SyncChan: ctx.SyncChan, 47 | } 48 | 49 | return eventReporter 50 | } 51 | 52 | func TestStartEventReporter(t *testing.T) { 53 | f := newFixture(t) 54 | ctx := f.newReportContext() 55 | err := startEventReporter(ctx) 56 | assert.Nil(t, err) 57 | 58 | ctx = &ReporterContext{} 59 | err = startEventReporter(ctx) 60 | assert.NotNil(t, err) 61 | } 62 | 63 | func TestHandleEvent(t *testing.T) { 64 | f := newFixture(t) 65 | event := newEvent() 66 | eventReporter := f.newEventReporter() 67 | eventReporter.handleEvent(event) 68 | 69 | data := <-eventReporter.SyncChan 70 | assert.NotNil(t, data) 71 | assert.Equal(t, clustermessage.CommandType_EdgeReport, data.Head.Command) 72 | assert.Equal(t, clusterName, data.Head.ClusterName) 73 | 74 | close(eventReporter.SyncChan) 75 | } 76 | 77 | func TestDeleteEvent(t *testing.T) { 78 | f := newFixture(t) 79 | event := newEvent() 80 | eventReporter := f.newEventReporter() 81 | eventReporter.deleteEvent(event) 82 | 83 | data := <-eventReporter.SyncChan 84 | assert.NotNil(t, data) 85 | assert.Equal(t, clustermessage.CommandType_EdgeReport, data.Head.Command) 86 | assert.Equal(t, clusterName, data.Head.ClusterName) 87 | 88 | close(eventReporter.SyncChan) 89 | } 90 | 91 | func TestEvSendToSyncChan(t *testing.T) { 92 | f := newFixture(t) 93 | event := newEvent() 94 | eventReporter := f.newEventReporter() 95 | 96 | ers := &EventResourceStatus{ 97 | UpdateMap: map[string]*corev1.Event{ 98 | name: event, 99 | }, 100 | } 101 | 102 | eventReporter.sendToSyncChan(ers) 103 | data := <-eventReporter.SyncChan 104 | assert.NotNil(t, data) 105 | assert.Equal(t, clustermessage.CommandType_EdgeReport, data.Head.Command) 106 | assert.Equal(t, clusterName, data.Head.ClusterName) 107 | 108 | close(eventReporter.SyncChan) 109 | } 110 | -------------------------------------------------------------------------------- /pkg/reporter/reporter_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package reporter 18 | 19 | import ( 20 | "testing" 21 | "time" 22 | 23 | "github.com/stretchr/testify/assert" 24 | corev1 "k8s.io/api/core/v1" 25 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | kubeinformers "k8s.io/client-go/informers" 27 | k8sfake "k8s.io/client-go/kubernetes/fake" 28 | 29 | "github.com/baidu/ote-stack/pkg/clustermessage" 30 | ) 31 | 32 | func TestIsValid(t *testing.T) { 33 | var kubeclient *k8sfake.Clientset 34 | ctx := &ReporterContext{ 35 | BaseReporterContext: BaseReporterContext{ 36 | ClusterName: func() string { 37 | return "name1" 38 | }, 39 | SyncChan: make(chan clustermessage.ClusterMessage), 40 | StopChan: make(chan struct{}), 41 | }, 42 | InformerFactory: kubeinformers.NewSharedInformerFactory(kubeclient, func() time.Duration { return 0 }()), 43 | } 44 | 45 | //ctx.InformerFactory is empty 46 | ctx.InformerFactory = nil 47 | ok := ctx.IsValid() 48 | assert.False(t, ok) 49 | 50 | //ctx.SyncChan is empty 51 | ctx.SyncChan = nil 52 | ok = ctx.IsValid() 53 | assert.False(t, ok) 54 | 55 | //ctx.StopChan is empty 56 | ctx.StopChan = nil 57 | ok = ctx.IsValid() 58 | assert.False(t, ok) 59 | 60 | //ctx is empty 61 | ctx = nil 62 | ok = ctx.IsValid() 63 | assert.False(t, ok) 64 | } 65 | 66 | func TestNewReporterInitializers(t *testing.T) { 67 | reporter := NewReporterInitializers() 68 | assert.IsType(t, reporter, map[string]InitFunc{}) 69 | } 70 | 71 | func TestAddLabelToResource(t *testing.T) { 72 | ctx := &ReporterContext{ 73 | BaseReporterContext: BaseReporterContext{ 74 | ClusterName: func() string { 75 | return "c1" 76 | }, 77 | }, 78 | } 79 | 80 | pod := &corev1.Pod{ 81 | ObjectMeta: metav1.ObjectMeta{ 82 | ResourceVersion: "1234", 83 | }, 84 | } 85 | 86 | addLabelToResource(&pod.ObjectMeta, ctx) 87 | 88 | assert.NotNil(t, pod.Labels) 89 | assert.Equal(t, "c1", pod.Labels[ClusterLabel]) 90 | assert.Equal(t, "1234", pod.Labels[EdgeVersionLabel]) 91 | } 92 | -------------------------------------------------------------------------------- /pkg/server/apisauthentication/register.go: -------------------------------------------------------------------------------- 1 | package apisauthentication 2 | 3 | import ( 4 | "github.com/emicklei/go-restful" 5 | 6 | "github.com/baidu/ote-stack/pkg/server/apisauthentication/resource" 7 | "github.com/baidu/ote-stack/pkg/server/handler" 8 | "github.com/baidu/ote-stack/pkg/util" 9 | ) 10 | 11 | const ( 12 | ServePath = "/apis/authentication.k8s.io/v1" 13 | ) 14 | 15 | func NewServiceHandler(ctx *handler.HandlerContext) *handler.ServiceHandler { 16 | serverHandler := map[string]handler.Handler{} 17 | 18 | // TODO add needed server handler here. 19 | serverHandler[util.ResourceTokenReview] = resource.NewTokenReviewHandler(ctx) 20 | 21 | return &handler.ServiceHandler{ 22 | ServerHandler: serverHandler, 23 | Ctx: ctx, 24 | } 25 | } 26 | 27 | func NewWebsService(ctx *handler.HandlerContext) *restful.WebService { 28 | serviceHandler := NewServiceHandler(ctx) 29 | 30 | ws := new(restful.WebService) 31 | ws.Path(ServePath) 32 | // Register create handler 33 | serviceHandler.RegisterCreateHandler(ws) 34 | 35 | return ws 36 | } 37 | -------------------------------------------------------------------------------- /pkg/server/apisauthentication/resource/tokenreview.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "net/http" 5 | 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | "k8s.io/client-go/tools/cache" 8 | "k8s.io/klog" 9 | 10 | "github.com/baidu/ote-stack/pkg/server/handler" 11 | "github.com/baidu/ote-stack/pkg/util" 12 | ) 13 | 14 | type TokenReviewHandler struct { 15 | ctx *handler.HandlerContext 16 | } 17 | 18 | func NewTokenReviewHandler(ctx *handler.HandlerContext) handler.Handler { 19 | return &TokenReviewHandler{ 20 | ctx: ctx, 21 | } 22 | } 23 | 24 | func (th *TokenReviewHandler) Create(body []byte, uri string) *handler.Response { 25 | tokenreview, err := util.GetObjectFromSerializeData(util.ResourceTokenReview, body) 26 | if err != nil { 27 | klog.Errorf("get object from serialized data failed: %v", err) 28 | return &handler.Response{ 29 | Code: http.StatusBadRequest, 30 | Err: err, 31 | } 32 | } 33 | 34 | key, err := cache.MetaNamespaceKeyFunc(tokenreview) 35 | if err != nil { 36 | klog.Errorf("get tokenreview key failed: %v", err) 37 | return &handler.Response{ 38 | Code: http.StatusBadRequest, 39 | Err: err, 40 | } 41 | } 42 | 43 | return handler.DoCreate(th.ctx, util.ResourceTokenReview, key, uri, body) 44 | } 45 | 46 | func (th *TokenReviewHandler) Delete(key, uri string, body []byte) *handler.Response { 47 | return handler.DoDelete(th.ctx, util.ResourceTokenReview, key, uri, body) 48 | } 49 | 50 | func (th *TokenReviewHandler) List(name, namespace, uri string) *handler.Response { 51 | return &handler.Response{Code: http.StatusInternalServerError} 52 | } 53 | 54 | func (th *TokenReviewHandler) Get(key string) *handler.Response { 55 | return handler.DoGet(th.ctx, util.ResourceTokenReview, key) 56 | } 57 | 58 | func (th *TokenReviewHandler) UpdatePut(key, uri string, body []byte) *handler.Response { 59 | return handler.DoUpdatePut(th.ctx, util.ResourceTokenReview, key, uri, body) 60 | } 61 | 62 | func (th *TokenReviewHandler) UpdatePatch(key, uri string, body []byte) *handler.Response { 63 | return handler.DoUpdatePatch(th.ctx, util.ResourceTokenReview, key, uri, body) 64 | } 65 | 66 | func (th *TokenReviewHandler) GetInitWatchEvent(fieldSelector, namespace, name string) []metav1.WatchEvent { 67 | return []metav1.WatchEvent{} 68 | } 69 | -------------------------------------------------------------------------------- /pkg/server/apisauthorization/register.go: -------------------------------------------------------------------------------- 1 | package apisauthorization 2 | 3 | import ( 4 | "github.com/emicklei/go-restful" 5 | 6 | "github.com/baidu/ote-stack/pkg/server/apisauthorization/resource" 7 | "github.com/baidu/ote-stack/pkg/server/handler" 8 | "github.com/baidu/ote-stack/pkg/util" 9 | ) 10 | 11 | const ( 12 | ServePath = "/apis/authorization.k8s.io/v1" 13 | ) 14 | 15 | func NewServiceHandler(ctx *handler.HandlerContext) *handler.ServiceHandler { 16 | serverHandler := map[string]handler.Handler{} 17 | 18 | // TODO add needed server handler here. 19 | serverHandler[util.ResourceSubjectAccessReview] = resource.NewSubjectAccessReviewHandler(ctx) 20 | 21 | return &handler.ServiceHandler{ 22 | ServerHandler: serverHandler, 23 | Ctx: ctx, 24 | } 25 | } 26 | 27 | func NewWebsService(ctx *handler.HandlerContext) *restful.WebService { 28 | serviceHandler := NewServiceHandler(ctx) 29 | 30 | ws := new(restful.WebService) 31 | ws.Path(ServePath) 32 | // Register create handler 33 | serviceHandler.RegisterCreateHandler(ws) 34 | 35 | return ws 36 | } 37 | -------------------------------------------------------------------------------- /pkg/server/apisauthorization/resource/subjectaccessreview.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "net/http" 5 | 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | "k8s.io/client-go/tools/cache" 8 | "k8s.io/klog" 9 | 10 | "github.com/baidu/ote-stack/pkg/server/handler" 11 | "github.com/baidu/ote-stack/pkg/util" 12 | ) 13 | 14 | type SubjectAccessReviewHandler struct { 15 | ctx *handler.HandlerContext 16 | } 17 | 18 | func NewSubjectAccessReviewHandler(ctx *handler.HandlerContext) handler.Handler { 19 | return &SubjectAccessReviewHandler{ 20 | ctx: ctx, 21 | } 22 | } 23 | 24 | func (sh *SubjectAccessReviewHandler) Create(body []byte, uri string) *handler.Response { 25 | sar, err := util.GetObjectFromSerializeData(util.ResourceSubjectAccessReview, body) 26 | if err != nil { 27 | klog.Errorf("get object from serialized data failed: %v", err) 28 | return &handler.Response{ 29 | Code: http.StatusBadRequest, 30 | Err: err, 31 | } 32 | } 33 | 34 | key, err := cache.MetaNamespaceKeyFunc(sar) 35 | if err != nil { 36 | klog.Errorf("get subjectaccessreview key failed: %v", err) 37 | return &handler.Response{ 38 | Code: http.StatusBadRequest, 39 | Err: err, 40 | } 41 | } 42 | 43 | return handler.DoCreate(sh.ctx, util.ResourceSubjectAccessReview, key, uri, body) 44 | } 45 | 46 | func (sh *SubjectAccessReviewHandler) Delete(key, uri string, body []byte) *handler.Response { 47 | return handler.DoDelete(sh.ctx, util.ResourceSubjectAccessReview, key, uri, body) 48 | } 49 | 50 | func (sh *SubjectAccessReviewHandler) List(name, namespace, uri string) *handler.Response { 51 | return &handler.Response{Code: http.StatusOK} 52 | } 53 | 54 | func (sh *SubjectAccessReviewHandler) Get(key string) *handler.Response { 55 | return handler.DoGet(sh.ctx, util.ResourceSubjectAccessReview, key) 56 | } 57 | 58 | func (sh *SubjectAccessReviewHandler) UpdatePut(key, uri string, body []byte) *handler.Response { 59 | return handler.DoUpdatePut(sh.ctx, util.ResourceSubjectAccessReview, key, uri, body) 60 | } 61 | 62 | func (sh *SubjectAccessReviewHandler) UpdatePatch(key, uri string, body []byte) *handler.Response { 63 | return handler.DoUpdatePatch(sh.ctx, util.ResourceSubjectAccessReview, key, uri, body) 64 | } 65 | 66 | func (sh *SubjectAccessReviewHandler) GetInitWatchEvent(fieldSelector, namespace, name string) []metav1.WatchEvent { 67 | return []metav1.WatchEvent{} 68 | } 69 | -------------------------------------------------------------------------------- /pkg/server/apiscertificates/register.go: -------------------------------------------------------------------------------- 1 | package apiscertificates 2 | 3 | import ( 4 | "github.com/emicklei/go-restful" 5 | 6 | "github.com/baidu/ote-stack/pkg/server/apiscertificates/resource" 7 | "github.com/baidu/ote-stack/pkg/server/handler" 8 | "github.com/baidu/ote-stack/pkg/util" 9 | ) 10 | 11 | const ( 12 | ServePath = "/apis/certificates.k8s.io/v1beta1" 13 | ) 14 | 15 | func NewServiceHandler(ctx *handler.HandlerContext) *handler.ServiceHandler { 16 | serverHandler := map[string]handler.Handler{} 17 | 18 | // TODO add needed server handler here. 19 | serverHandler[util.ResourceCSR] = resource.NewCertSigningRequestHandler(ctx) 20 | 21 | return &handler.ServiceHandler{ 22 | ServerHandler: serverHandler, 23 | Ctx: ctx, 24 | } 25 | } 26 | 27 | func NewWebsService(ctx *handler.HandlerContext) *restful.WebService { 28 | serviceHandler := NewServiceHandler(ctx) 29 | 30 | ws := new(restful.WebService) 31 | ws.Path(ServePath) 32 | // Register create handler 33 | serviceHandler.RegisterCreateHandler(ws) 34 | serviceHandler.RegisterDeleteHandler(ws) 35 | serviceHandler.RegisterListHandler(ws) 36 | serviceHandler.RegisterUpdateHandler(ws) 37 | 38 | return ws 39 | } 40 | -------------------------------------------------------------------------------- /pkg/server/apiscoordination/register.go: -------------------------------------------------------------------------------- 1 | package apiscoordination 2 | 3 | import ( 4 | "github.com/emicklei/go-restful" 5 | 6 | "github.com/baidu/ote-stack/pkg/server/apiscoordination/resource" 7 | "github.com/baidu/ote-stack/pkg/server/handler" 8 | "github.com/baidu/ote-stack/pkg/util" 9 | ) 10 | 11 | const ( 12 | ServePath = "/apis/coordination.k8s.io/v1" 13 | ) 14 | 15 | func NewServiceHandler(ctx *handler.HandlerContext) *handler.ServiceHandler { 16 | serverHandler := map[string]handler.Handler{} 17 | 18 | // TODO add needed server handler here. 19 | serverHandler[util.ResourceNodeLease] = resource.NewLeaseHandler(ctx) 20 | 21 | return &handler.ServiceHandler{ 22 | ServerHandler: serverHandler, 23 | Ctx: ctx, 24 | } 25 | } 26 | 27 | func NewWebsService(ctx *handler.HandlerContext) *restful.WebService { 28 | serviceHandler := NewServiceHandler(ctx) 29 | 30 | ws := new(restful.WebService) 31 | ws.Path(ServePath) 32 | // Register create handler 33 | serviceHandler.RegisterCreateHandler(ws) 34 | serviceHandler.RegisterDeleteHandler(ws) 35 | serviceHandler.RegisterListHandler(ws) 36 | serviceHandler.RegisterUpdateHandler(ws) 37 | 38 | return ws 39 | } 40 | -------------------------------------------------------------------------------- /pkg/server/apisnetworking/register.go: -------------------------------------------------------------------------------- 1 | package apisnetworking 2 | 3 | import ( 4 | "github.com/emicklei/go-restful" 5 | 6 | "github.com/baidu/ote-stack/pkg/server/apisnetworking/resource" 7 | "github.com/baidu/ote-stack/pkg/server/handler" 8 | "github.com/baidu/ote-stack/pkg/util" 9 | ) 10 | 11 | const ( 12 | ServePath = "/apis/networking.k8s.io/v1" 13 | ) 14 | 15 | func NewServiceHandler(ctx *handler.HandlerContext) *handler.ServiceHandler { 16 | serverHandler := map[string]handler.Handler{} 17 | 18 | // TODO add needed server handler here. 19 | serverHandler[util.ResourceNetworkPolicy] = resource.NewNetworkPolicyHandler(ctx) 20 | 21 | return &handler.ServiceHandler{ 22 | ServerHandler: serverHandler, 23 | Ctx: ctx, 24 | } 25 | } 26 | 27 | func NewWebsService(ctx *handler.HandlerContext) *restful.WebService { 28 | serviceHandler := NewServiceHandler(ctx) 29 | 30 | ws := new(restful.WebService) 31 | ws.Path(ServePath) 32 | // Register create handler 33 | serviceHandler.RegisterCreateHandler(ws) 34 | serviceHandler.RegisterDeleteHandler(ws) 35 | serviceHandler.RegisterListHandler(ws) 36 | serviceHandler.RegisterUpdateHandler(ws) 37 | 38 | return ws 39 | } 40 | -------------------------------------------------------------------------------- /pkg/server/apisnode/register.go: -------------------------------------------------------------------------------- 1 | package apisnode 2 | 3 | import ( 4 | "github.com/emicklei/go-restful" 5 | 6 | "github.com/baidu/ote-stack/pkg/server/apisnode/resource" 7 | "github.com/baidu/ote-stack/pkg/server/handler" 8 | "github.com/baidu/ote-stack/pkg/util" 9 | ) 10 | 11 | const ( 12 | ServePath = "/apis/node.k8s.io/v1beta1" 13 | ) 14 | 15 | func NewServiceHandler(ctx *handler.HandlerContext) *handler.ServiceHandler { 16 | serverHandler := map[string]handler.Handler{} 17 | 18 | // TODO add needed server handler here. 19 | serverHandler[util.ResourceRuntimeClass] = resource.NewRuntimeClassHandler(ctx) 20 | 21 | return &handler.ServiceHandler{ 22 | ServerHandler: serverHandler, 23 | Ctx: ctx, 24 | } 25 | } 26 | 27 | func NewWebsService(ctx *handler.HandlerContext) *restful.WebService { 28 | serviceHandler := NewServiceHandler(ctx) 29 | 30 | ws := new(restful.WebService) 31 | ws.Path(ServePath) 32 | // Register create handler 33 | serviceHandler.RegisterCreateHandler(ws) 34 | serviceHandler.RegisterDeleteHandler(ws) 35 | serviceHandler.RegisterListHandler(ws) 36 | serviceHandler.RegisterUpdateHandler(ws) 37 | 38 | return ws 39 | } 40 | -------------------------------------------------------------------------------- /pkg/server/apisstorage/register.go: -------------------------------------------------------------------------------- 1 | package apisstorage 2 | 3 | import ( 4 | "github.com/emicklei/go-restful" 5 | 6 | "github.com/baidu/ote-stack/pkg/server/apisstorage/resource" 7 | "github.com/baidu/ote-stack/pkg/server/handler" 8 | "github.com/baidu/ote-stack/pkg/util" 9 | ) 10 | 11 | const ( 12 | ServePath = "/apis/storage.k8s.io/v1" 13 | ) 14 | 15 | func NewServiceHandler(ctx *handler.HandlerContext) *handler.ServiceHandler { 16 | serverHandler := map[string]handler.Handler{} 17 | 18 | // TODO add needed server handler here. 19 | serverHandler[util.ResourceCSIDriver] = resource.NewCSIDriverHandler(ctx) 20 | serverHandler[util.ResourceCSINode] = resource.NewCSINodeHandler(ctx) 21 | 22 | return &handler.ServiceHandler{ 23 | ServerHandler: serverHandler, 24 | Ctx: ctx, 25 | } 26 | } 27 | 28 | func NewWebsService(ctx *handler.HandlerContext) *restful.WebService { 29 | serviceHandler := NewServiceHandler(ctx) 30 | 31 | ws := new(restful.WebService) 32 | ws.Path(ServePath) 33 | // Register create handler 34 | serviceHandler.RegisterCreateHandler(ws) 35 | serviceHandler.RegisterDeleteHandler(ws) 36 | serviceHandler.RegisterListHandler(ws) 37 | serviceHandler.RegisterUpdateHandler(ws) 38 | 39 | return ws 40 | } 41 | -------------------------------------------------------------------------------- /pkg/server/apiv1/register.go: -------------------------------------------------------------------------------- 1 | package apiv1 2 | 3 | import ( 4 | "github.com/emicklei/go-restful" 5 | 6 | "github.com/baidu/ote-stack/pkg/server/apiv1/resource" 7 | "github.com/baidu/ote-stack/pkg/server/handler" 8 | "github.com/baidu/ote-stack/pkg/util" 9 | ) 10 | 11 | const ( 12 | PathAPIV1 = "/api/v1" 13 | ) 14 | 15 | func NewServiceHandler(ctx *handler.HandlerContext) *handler.ServiceHandler { 16 | serverHandler := map[string]handler.Handler{} 17 | 18 | // TODO add needed server handler here. 19 | serverHandler[util.ResourcePod] = resource.NewPodHandler(ctx) 20 | serverHandler[util.ResourceNode] = resource.NewNodeHandler(ctx) 21 | serverHandler[util.ResourceService] = resource.NewServiceHandler(ctx) 22 | serverHandler[util.ResourceEndpoint] = resource.NewEndpointHandler(ctx) 23 | serverHandler[util.ResourceConfigMap] = resource.NewConfigMapHandler(ctx) 24 | serverHandler[util.ResourceSecret] = resource.NewSecretHandler(ctx) 25 | serverHandler[util.ResourceEvent] = resource.NewEventHandler(ctx) 26 | serverHandler[util.ResourceNamespace] = resource.NewNamespaceHandler(ctx) 27 | 28 | return &handler.ServiceHandler{ 29 | ServerHandler: serverHandler, 30 | Ctx: ctx, 31 | } 32 | } 33 | 34 | func NewWebsService(ctx *handler.HandlerContext) *restful.WebService { 35 | serviceHandler := NewServiceHandler(ctx) 36 | 37 | ws := new(restful.WebService) 38 | ws.Path(PathAPIV1) 39 | // Register create handler 40 | serviceHandler.RegisterCreateHandler(ws) 41 | serviceHandler.RegisterDeleteHandler(ws) 42 | serviceHandler.RegisterListHandler(ws) 43 | serviceHandler.RegisterUpdateHandler(ws) 44 | 45 | return ws 46 | } 47 | -------------------------------------------------------------------------------- /pkg/server/apiv1/resource/event.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "net/http" 5 | 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | "k8s.io/client-go/tools/cache" 8 | "k8s.io/klog" 9 | 10 | "github.com/baidu/ote-stack/pkg/server/handler" 11 | "github.com/baidu/ote-stack/pkg/util" 12 | ) 13 | 14 | type EventHandler struct { 15 | ctx *handler.HandlerContext 16 | } 17 | 18 | func NewEventHandler(ctx *handler.HandlerContext) handler.Handler { 19 | return &EventHandler{ 20 | ctx: ctx, 21 | } 22 | } 23 | 24 | func (eh *EventHandler) Create(body []byte, uri string) *handler.Response { 25 | event, err := util.GetObjectFromSerializeData(util.ResourceEvent, body) 26 | if err != nil { 27 | klog.Errorf("get object from serialized data failed: %v", err) 28 | return &handler.Response{ 29 | Code: http.StatusBadRequest, 30 | Err: err, 31 | } 32 | } 33 | 34 | key, err := cache.MetaNamespaceKeyFunc(event) 35 | if err != nil { 36 | klog.Errorf("get event key failed: %v", err) 37 | return &handler.Response{ 38 | Code: http.StatusBadRequest, 39 | Err: err, 40 | } 41 | } 42 | 43 | return handler.DoCreate(eh.ctx, util.ResourceEvent, key, uri, body) 44 | } 45 | 46 | func (eh *EventHandler) Delete(key, uri string, body []byte) *handler.Response { 47 | return handler.DoDelete(eh.ctx, util.ResourceEvent, key, uri, body) 48 | } 49 | 50 | func (eh *EventHandler) List(name, namespace, uri string) *handler.Response { 51 | // TODO list event 52 | return &handler.Response{ 53 | Body: []byte(""), 54 | } 55 | } 56 | 57 | func (eh *EventHandler) Get(key string) *handler.Response { 58 | return handler.DoGet(eh.ctx, util.ResourceEvent, key) 59 | } 60 | 61 | func (eh *EventHandler) UpdatePut(key, uri string, body []byte) *handler.Response { 62 | return handler.DoUpdatePut(eh.ctx, util.ResourceEvent, key, uri, body) 63 | } 64 | 65 | func (eh *EventHandler) UpdatePatch(key, uri string, body []byte) *handler.Response { 66 | return handler.DoUpdatePatch(eh.ctx, util.ResourceEvent, key, uri, body) 67 | } 68 | 69 | func (eh *EventHandler) GetInitWatchEvent(fieldSelector, namespace, name string) []metav1.WatchEvent { 70 | return []metav1.WatchEvent{} 71 | } 72 | -------------------------------------------------------------------------------- /pkg/server/handler/creator.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | 8 | "github.com/emicklei/go-restful" 9 | apierrors "k8s.io/apimachinery/pkg/api/errors" 10 | "k8s.io/apimachinery/pkg/runtime/schema" 11 | "k8s.io/klog" 12 | ) 13 | 14 | func (h *ServiceHandler) RegisterCreateHandler(ws *restful.WebService) { 15 | ws.Route(ws.POST("namespaces/{namespace}/{resource}").To(h.createHandler)) 16 | ws.Route(ws.POST("{resource}").To(h.createHandler)) 17 | } 18 | 19 | func (h *ServiceHandler) createHandler(req *restful.Request, resp *restful.Response) { 20 | resource := req.PathParameter("resource") 21 | 22 | httpBody, err := ioutil.ReadAll(req.Request.Body) 23 | if err != nil { 24 | klog.Errorf("http body read error:%v", err) 25 | resp.WriteError(http.StatusBadRequest, err) 26 | return 27 | } 28 | 29 | if _, ok := h.ServerHandler[resource]; !ok { 30 | klog.Errorf("unsupport resource: %s in create operation.", resource) 31 | resp.WriteError(http.StatusBadRequest, fmt.Errorf("unsupport resource in delete operation.")) 32 | return 33 | } 34 | 35 | result := h.ServerHandler[resource].Create(httpBody, req.Request.RequestURI) 36 | if result.Err != nil { 37 | if !CheckResponseCode(result.Code) { 38 | result.Code = http.StatusInternalServerError 39 | } 40 | resp.WriteError(result.Code, result.Err) 41 | return 42 | } 43 | resp.Header().Set("Content-Type", "application/json") 44 | resp.Write(result.Body) 45 | 46 | klog.V(4).Infof("create %s success.", resource) 47 | } 48 | 49 | func DoCreate(ctx *HandlerContext, objType, key, uri string, body []byte) *Response { 50 | if ctx.Lb.IsRemoteEnable() { 51 | var code int 52 | 53 | result := ctx.K8sClient.CoreV1().RESTClient().Post().RequestURI(uri).Body(body).Do() 54 | raw, err := result.Raw() 55 | result.StatusCode(&code) 56 | 57 | if err != nil { 58 | klog.Errorf("create %s-%s failed: %v", objType, key, err) 59 | return &Response{ 60 | Err: err, 61 | Code: code, 62 | } 63 | } 64 | 65 | return &Response{ 66 | Body: raw, 67 | } 68 | } else { 69 | if _, err := ctx.Store.Get(objType, key, false); err == nil { 70 | klog.Errorf("create %s-%s failed: it is already exist", objType, key) 71 | return &Response{ 72 | Err: apierrors.NewAlreadyExists(schema.GroupResource{}, key), 73 | Code: http.StatusConflict, 74 | } 75 | } 76 | err := ctx.Store.Update(objType, key, body) 77 | if err != nil { 78 | klog.Errorf("store %s failed: %v", objType, err) 79 | return &Response{ 80 | Err: err, 81 | Code: http.StatusInternalServerError, 82 | } 83 | } 84 | 85 | return &Response{ 86 | Body: body, 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /pkg/server/handler/deleter.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | 8 | "github.com/emicklei/go-restful" 9 | "k8s.io/klog" 10 | 11 | "github.com/baidu/ote-stack/pkg/util" 12 | ) 13 | 14 | func (h *ServiceHandler) RegisterDeleteHandler(ws *restful.WebService) { 15 | ws.Route(ws.DELETE("namespaces/{namespace}/{resource}/{name}").To(h.deleteHandler)) 16 | } 17 | 18 | func (h *ServiceHandler) deleteHandler(req *restful.Request, resp *restful.Response) { 19 | namespace := req.PathParameter("namespace") 20 | resource := req.PathParameter("resource") 21 | name := req.PathParameter("name") 22 | 23 | key := util.FormKeyName(namespace, name) 24 | 25 | httpBody, err := ioutil.ReadAll(req.Request.Body) 26 | if err != nil { 27 | klog.Errorf("http body read error:%v", err) 28 | resp.WriteError(http.StatusBadRequest, err) 29 | return 30 | } 31 | 32 | if _, ok := h.ServerHandler[resource]; !ok { 33 | klog.Errorf("unsupport resource: %s in delete operation.", resource) 34 | resp.WriteError(http.StatusBadRequest, fmt.Errorf("unsupport resource in delete operation.")) 35 | return 36 | } 37 | 38 | result := h.ServerHandler[resource].Delete(key, req.Request.RequestURI, httpBody) 39 | if result.Err != nil { 40 | if !CheckResponseCode(result.Code) { 41 | result.Code = http.StatusInternalServerError 42 | } 43 | resp.WriteError(result.Code, result.Err) 44 | return 45 | } 46 | resp.Header().Set("Content-Type", "application/json") 47 | resp.Write(result.Body) 48 | 49 | klog.V(4).Infof("delete %s-%s-%s success.", resource, namespace, name) 50 | } 51 | 52 | func DoDelete(ctx *HandlerContext, objType, key, uri string, body []byte) *Response { 53 | if ctx.Lb.IsRemoteEnable() { 54 | var code int 55 | 56 | result := ctx.K8sClient.CoreV1().RESTClient().Delete().RequestURI(uri).Body(body).Do() 57 | raw, err := result.Raw() 58 | result.StatusCode(&code) 59 | 60 | if err != nil { 61 | klog.Errorf("delete %s failed: %v", objType, err) 62 | return &Response{ 63 | Code: code, 64 | Err: err, 65 | } 66 | } 67 | 68 | return &Response{ 69 | Body: raw, 70 | } 71 | } else { 72 | err := ctx.Store.Delete(objType, key) 73 | if err != nil { 74 | klog.Errorf("delete %s failed: %v", objType, err) 75 | return &Response{ 76 | Code: http.StatusInternalServerError, 77 | Err: err, 78 | } 79 | } 80 | 81 | return &Response{ 82 | Code: http.StatusOK, 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /pkg/server/handler/handler.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | 7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 | "k8s.io/client-go/kubernetes" 9 | "k8s.io/klog" 10 | 11 | "github.com/baidu/ote-stack/pkg/loadbalancer" 12 | "github.com/baidu/ote-stack/pkg/storage" 13 | "github.com/baidu/ote-stack/pkg/syncer" 14 | ) 15 | 16 | var connectionUpgradeRegex = regexp.MustCompile("(^|.*,\\s*)upgrade($|\\s*,)") 17 | 18 | type Response struct { 19 | Code int 20 | Err error 21 | Body []byte 22 | } 23 | 24 | type HandlerContext struct { 25 | Store *storage.EdgehubStorage 26 | Lb *loadbalancer.LoadBalancer 27 | K8sClient kubernetes.Interface 28 | EdgeSubscriber *syncer.ResourceSubscriber 29 | } 30 | 31 | type ServiceHandler struct { 32 | Ctx *HandlerContext 33 | ServerHandler map[string]Handler 34 | } 35 | 36 | type Handler interface { 37 | Create([]byte, string) *Response 38 | Delete(string, string, []byte) *Response 39 | List(string, string, string) *Response 40 | Get(string) *Response 41 | UpdatePut(string, string, []byte) *Response 42 | UpdatePatch(string, string, []byte) *Response 43 | GetInitWatchEvent(string, string, string) []metav1.WatchEvent 44 | } 45 | 46 | func IsFilterFromQueryParams(fieldSelector, nodeName, name string) bool { 47 | if fieldSelector != "" { 48 | result := strings.Split(fieldSelector, "=") 49 | if len(result) < 2 { 50 | return true 51 | } 52 | 53 | switch result[0] { 54 | case syncer.ObjectNameField: 55 | if result[1] != name { 56 | return false 57 | } 58 | case syncer.SpecNodeNameField: 59 | if result[1] != nodeName { 60 | return false 61 | } 62 | } 63 | } 64 | 65 | return true 66 | } 67 | 68 | func (h *HandlerContext) IsValid() bool { 69 | if h == nil { 70 | klog.Errorf("handler context is nil") 71 | return false 72 | } 73 | 74 | if h.Store == nil { 75 | klog.Errorf("handlerContext's storage is nil") 76 | return false 77 | } 78 | 79 | if h.K8sClient == nil { 80 | klog.Errorf("handlerContext's K8sClient is nil") 81 | return false 82 | } 83 | 84 | if h.Lb == nil { 85 | klog.Errorf("handlerContext's lb is nil") 86 | return false 87 | } 88 | 89 | if h.EdgeSubscriber == nil { 90 | klog.Errorf("handlerContext's EdgeSubscriber is nil") 91 | return false 92 | } 93 | 94 | return true 95 | } 96 | 97 | // CheckResponseCode check if response code is valid.Response Code should be three digits. 98 | func CheckResponseCode(code int) bool { 99 | if code < 100 || code > 999 { 100 | return false 101 | } 102 | 103 | return true 104 | } 105 | -------------------------------------------------------------------------------- /pkg/server/k3s_server_test.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | k8sfake "k8s.io/client-go/kubernetes/fake" 8 | 9 | "github.com/baidu/ote-stack/pkg/loadbalancer" 10 | "github.com/baidu/ote-stack/pkg/server/certificate" 11 | "github.com/baidu/ote-stack/pkg/server/handler" 12 | "github.com/baidu/ote-stack/pkg/storage" 13 | "github.com/baidu/ote-stack/pkg/syncer" 14 | ) 15 | 16 | func TestCheckK3sValid(t *testing.T) { 17 | ctx := &ServerContext{} 18 | server := NewEdgeK3sServer(ctx) 19 | 20 | err := server.CheckValid(ctx) 21 | assert.NotNil(t, err) 22 | 23 | ctx.BindAddr = "127.0.0.1" 24 | ctx.BindPort = 8080 25 | ctx.CertFile = "." 26 | ctx.KeyFile = "." 27 | ctx.StopChan = make(chan bool) 28 | 29 | handlerCtx := &handler.HandlerContext{ 30 | Store: &storage.EdgehubStorage{}, 31 | K8sClient: &k8sfake.Clientset{}, 32 | Lb: &loadbalancer.LoadBalancer{}, 33 | EdgeSubscriber: syncer.GetSubscriber(), 34 | } 35 | 36 | certCtx := &certificate.CertContext{ 37 | Store: &storage.EdgehubStorage{}, 38 | CaFile: ".", 39 | K8sClient: &k8sfake.Clientset{}, 40 | Lb: &loadbalancer.LoadBalancer{}, 41 | DataPath: ".", 42 | ServerURL: "127.0.0.1:80", 43 | TokenFile: ".", 44 | } 45 | 46 | ctx.HandlerCtx = handlerCtx 47 | ctx.CertCtx = certCtx 48 | err = server.CheckValid(ctx) 49 | assert.Nil(t, err) 50 | } 51 | -------------------------------------------------------------------------------- /pkg/server/k8s_server_test.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | k8sfake "k8s.io/client-go/kubernetes/fake" 8 | 9 | "github.com/baidu/ote-stack/pkg/loadbalancer" 10 | "github.com/baidu/ote-stack/pkg/server/handler" 11 | "github.com/baidu/ote-stack/pkg/storage" 12 | "github.com/baidu/ote-stack/pkg/syncer" 13 | ) 14 | 15 | func TestCheckK8sValid(t *testing.T) { 16 | ctx := &ServerContext{} 17 | server := NewEdgeK8sServer(ctx) 18 | 19 | err := server.CheckValid(ctx) 20 | assert.NotNil(t, err) 21 | 22 | ctx.BindAddr = "127.0.0.1" 23 | ctx.BindPort = 8080 24 | ctx.CaFile = "." 25 | ctx.CertFile = "." 26 | ctx.KeyFile = "." 27 | ctx.StopChan = make(chan bool) 28 | 29 | handlerCtx := &handler.HandlerContext{ 30 | Store: &storage.EdgehubStorage{}, 31 | K8sClient: &k8sfake.Clientset{}, 32 | Lb: &loadbalancer.LoadBalancer{}, 33 | EdgeSubscriber: syncer.GetSubscriber(), 34 | } 35 | 36 | ctx.HandlerCtx = handlerCtx 37 | err = server.CheckValid(ctx) 38 | assert.Nil(t, err) 39 | } 40 | -------------------------------------------------------------------------------- /pkg/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | cert "github.com/baidu/ote-stack/pkg/server/certificate" 5 | "github.com/baidu/ote-stack/pkg/server/handler" 6 | ) 7 | 8 | type EdgeServer interface { 9 | StartServer(*ServerContext) error 10 | CheckValid(*ServerContext) error 11 | } 12 | 13 | type ServerContext struct { 14 | BindAddr string 15 | BindPort int 16 | ReadTimeout int 17 | WriteTimeout int 18 | CaFile string 19 | CertFile string 20 | KeyFile string 21 | 22 | StopChan chan bool 23 | HandlerCtx *handler.HandlerContext 24 | CertCtx *cert.CertContext 25 | } 26 | -------------------------------------------------------------------------------- /pkg/storage/persistent_storage.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "fmt" 5 | 6 | "k8s.io/klog" 7 | 8 | "github.com/syndtr/goleveldb/leveldb" 9 | "github.com/syndtr/goleveldb/leveldb/util" 10 | ) 11 | 12 | type LevelDB struct { 13 | db *leveldb.DB 14 | } 15 | 16 | func newEdgehubDB(path string) (*LevelDB, error) { 17 | db, err := leveldb.OpenFile(path, nil) 18 | if err != nil { 19 | return nil, fmt.Errorf("failed to open leveldb: %v", err) 20 | } 21 | 22 | return &LevelDB{db: db}, nil 23 | } 24 | 25 | func (l *LevelDB) Get(objType string, key string) ([]byte, error) { 26 | data, err := l.db.Get([]byte(formKeyName(objType, key)), nil) 27 | if err != nil { 28 | return nil, fmt.Errorf("get %s-%s obj failed: %v", objType, key, err) 29 | } 30 | 31 | return data, nil 32 | } 33 | 34 | func (l *LevelDB) List(objType string) [][]byte { 35 | var list [][]byte 36 | iter := l.db.NewIterator(util.BytesPrefix([]byte(objType+Speration)), nil) 37 | 38 | for iter.Next() { 39 | data, err := l.db.Get(iter.Key(), nil) 40 | if err != nil { 41 | klog.Infof("level db err: %v", err) 42 | continue 43 | } 44 | list = append(list, data) 45 | } 46 | 47 | iter.Release() 48 | return list 49 | } 50 | 51 | func (l *LevelDB) Update(objType string, key string, data []byte) error { 52 | if err := l.db.Put([]byte(formKeyName(objType, key)), data, nil); err != nil { 53 | return fmt.Errorf("update %s-%s obj failed: %v", objType, key, err) 54 | } 55 | 56 | return nil 57 | } 58 | 59 | func (l *LevelDB) Delete(objType string, key string) error { 60 | if err := l.db.Delete([]byte(formKeyName(objType, key)), nil); err != nil { 61 | return fmt.Errorf("delete %s-%s obj failed: %v", objType, key, err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /pkg/storage/persistent_storage_test.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | 9 | "github.com/baidu/ote-stack/pkg/util" 10 | ) 11 | 12 | func TestLevelDB(t *testing.T) { 13 | db, err := newEdgehubDB("../../db_test/") 14 | assert.Nil(t, err) 15 | assert.NotNil(t, db) 16 | 17 | // get failed 18 | data, err := db.Get(util.ResourcePod, "test1") 19 | assert.NotNil(t, err) 20 | assert.Nil(t, data) 21 | 22 | // update success 23 | err = db.Update(util.ResourcePod, "test1", []byte("hello")) 24 | assert.Nil(t, err) 25 | 26 | // get success 27 | data, err = db.Get(util.ResourcePod, "test1") 28 | assert.Nil(t, err) 29 | assert.Equal(t, "hello", string(data)) 30 | 31 | // list success 32 | err = db.Update(util.ResourcePod, "test2", []byte("hi")) 33 | assert.Nil(t, err) 34 | list := db.List(util.ResourcePod) 35 | assert.Equal(t, 2, len(list)) 36 | assert.Equal(t, "hi", string(list[1])) 37 | 38 | // delete success 39 | err = db.Delete(util.ResourcePod, "test1") 40 | assert.Nil(t, err) 41 | err = db.Delete(util.ResourcePod, "test2") 42 | assert.Nil(t, err) 43 | 44 | db.db.Close() 45 | os.RemoveAll("../../db_test/") 46 | } 47 | -------------------------------------------------------------------------------- /pkg/syncer/configmap_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleConfigMapEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceConfigMap, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewConfigMapSyncer(ctx) 25 | 26 | configmap := &corev1.ConfigMap{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(configmap) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(configmap) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourceConfigMap, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &corev1.ConfigMap{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourceConfigMap]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, configmap, event.Object.Object) 55 | 56 | // test update event 57 | newConfigMap := &corev1.ConfigMap{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(configmap, newConfigMap) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourceConfigMap, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &corev1.ConfigMap{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourceConfigMap]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newConfigMap, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(configmap) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourceConfigMap, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourceConfigMap]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, configmap, event.Object.Object) 91 | 92 | EdgeSubscriber.Delete(util.ResourceConfigMap, "key") 93 | ctx.Store.Close() 94 | os.RemoveAll("../../db_test/") 95 | } 96 | -------------------------------------------------------------------------------- /pkg/syncer/csidriver_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "k8s.io/api/storage/v1beta1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleCSIDriverEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceCSIDriver, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewCSIDriverSyncer(ctx) 25 | 26 | cd := &v1beta1.CSIDriver{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(cd) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(cd) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourceCSIDriver, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &v1beta1.CSIDriver{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourceCSIDriver]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, cd, event.Object.Object) 55 | 56 | // test update event 57 | newCD := &v1beta1.CSIDriver{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(cd, newCD) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourceCSIDriver, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &v1beta1.CSIDriver{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourceCSIDriver]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newCD, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(cd) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourceCSIDriver, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourceCSIDriver]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, cd, event.Object.Object) 91 | 92 | EdgeSubscriber.Delete(util.ResourceCSIDriver, "key") 93 | ctx.Store.Close() 94 | os.RemoveAll("../../db_test/") 95 | } 96 | -------------------------------------------------------------------------------- /pkg/syncer/csinode_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "k8s.io/api/storage/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleCSINodeEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceCSINode, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewCSINodeSyncer(ctx) 25 | 26 | cn := &v1.CSINode{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(cn) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(cn) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourceCSINode, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &v1.CSINode{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourceCSINode]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, cn, event.Object.Object) 55 | 56 | // test update event 57 | newCN := &v1.CSINode{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(cn, newCN) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourceCSINode, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &v1.CSINode{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourceCSINode]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newCN, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(cn) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourceCSINode, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourceCSINode]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, cn, event.Object.Object) 91 | 92 | EdgeSubscriber.Delete(util.ResourceCSINode, "key") 93 | ctx.Store.Close() 94 | os.RemoveAll("../../db_test/") 95 | } 96 | -------------------------------------------------------------------------------- /pkg/syncer/csr_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "k8s.io/api/certificates/v1beta1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleCSREvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceCSR, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewCSRSyncer(ctx) 25 | 26 | csr := &v1beta1.CertificateSigningRequest{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(csr) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(csr) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourceCSR, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &v1beta1.CertificateSigningRequest{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourceCSR]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, csr, event.Object.Object) 55 | 56 | // test update event 57 | newCSR := &v1beta1.CertificateSigningRequest{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(csr, newCSR) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourceCSR, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &v1beta1.CertificateSigningRequest{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourceCSR]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newCSR, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(csr) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourceCSR, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourceCSR]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, csr, event.Object.Object) 91 | 92 | ctx.Store.Close() 93 | os.RemoveAll("../../db_test/") 94 | } 95 | -------------------------------------------------------------------------------- /pkg/syncer/endpoint_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleEndpointEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceEndpoint, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewEndpointSyncer(ctx) 25 | 26 | ep := &corev1.Endpoints{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(ep) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(ep) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourceEndpoint, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &corev1.Endpoints{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourceEndpoint]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, ep, event.Object.Object) 55 | 56 | // test update event 57 | newEp := &corev1.Endpoints{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(ep, newEp) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourceEndpoint, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &corev1.Endpoints{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourceEndpoint]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newEp, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(ep) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourceEndpoint, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourceEndpoint]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, ep, event.Object.Object) 91 | 92 | EdgeSubscriber.Delete(util.ResourceEndpoint, "key") 93 | ctx.Store.Close() 94 | os.RemoveAll("../../db_test/") 95 | } 96 | -------------------------------------------------------------------------------- /pkg/syncer/event_syncer.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "fmt" 5 | 6 | corev1 "k8s.io/api/core/v1" 7 | "k8s.io/apimachinery/pkg/watch" 8 | "k8s.io/client-go/tools/cache" 9 | "k8s.io/klog" 10 | 11 | "github.com/baidu/ote-stack/pkg/util" 12 | ) 13 | 14 | // EventSyncer is responsible for synchronizing event from apiserver. 15 | type EventSyncer struct { 16 | ctx *SyncContext 17 | Informer cache.SharedIndexInformer 18 | } 19 | 20 | func NewEventSyncer(ctx *SyncContext) Syncer { 21 | informer, ok := ctx.InformerFactory[DefaultInformerFatory] 22 | if !ok { 23 | return nil 24 | } 25 | 26 | return &EventSyncer{ 27 | ctx: ctx, 28 | Informer: informer.Core().V1().Events().Informer(), 29 | } 30 | } 31 | 32 | func (es *EventSyncer) startSyncer() error { 33 | if !es.ctx.IsValid() { 34 | return fmt.Errorf("start event syncer failed: SyncContext is invalid") 35 | } 36 | 37 | registerInformerHandler(es) 38 | 39 | return nil 40 | } 41 | 42 | // handleAddNode puts the added event into persistent storage, and return to edge node as a watch event. 43 | func (es *EventSyncer) handleAddEvent(obj interface{}) { 44 | event := obj.(*corev1.Event) 45 | es.addKindAndVersion(event) 46 | 47 | go syncToNode(watch.Added, util.ResourceEvent, event) 48 | 49 | syncToStorage(es.ctx, watch.Added, util.ResourceEvent, event) 50 | } 51 | 52 | // handleUpdateEvent puts the modified event into persistent storage, and return to edge node as a watch event. 53 | func (es *EventSyncer) handleUpdateEvent(old, new interface{}) { 54 | newEvent := new.(*corev1.Event) 55 | oldEvent := old.(*corev1.Event) 56 | if newEvent.ResourceVersion == oldEvent.ResourceVersion { 57 | // Periodic resync will send update events for all known Deployments. 58 | // Two different versions of the same Deployment will always have different RVs. 59 | return 60 | } 61 | 62 | es.addKindAndVersion(newEvent) 63 | 64 | go syncToNode(watch.Modified, util.ResourceEvent, newEvent) 65 | 66 | syncToStorage(es.ctx, watch.Modified, util.ResourceEvent, newEvent) 67 | } 68 | 69 | // handleDeleteEvent delete the event from persistent storage, and return to edge node as a watch event. 70 | func (es *EventSyncer) handleDeleteEvent(obj interface{}) { 71 | event, ok := obj.(*corev1.Event) 72 | if !ok { 73 | tombstone, ok := obj.(cache.DeletedFinalStateUnknown) 74 | if !ok { 75 | klog.Errorf("Couldn't get object from tombstone %v", obj) 76 | return 77 | } 78 | event, ok = tombstone.Obj.(*corev1.Event) 79 | if !ok { 80 | klog.Errorf("Tombstone contained object that is not a event %v", obj) 81 | return 82 | } 83 | } 84 | 85 | es.addKindAndVersion(event) 86 | 87 | go syncToNode(watch.Deleted, util.ResourceEvent, event) 88 | 89 | syncToStorage(es.ctx, watch.Deleted, util.ResourceEvent, event) 90 | } 91 | 92 | // getInformer returns informer of this syncer. 93 | func (es *EventSyncer) getInformer() cache.SharedIndexInformer { 94 | return es.Informer 95 | } 96 | 97 | func (es *EventSyncer) addKindAndVersion(event *corev1.Event) { 98 | event.APIVersion = "v1" 99 | event.Kind = "Node" 100 | } 101 | -------------------------------------------------------------------------------- /pkg/syncer/event_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/client-go/tools/cache" 12 | 13 | "github.com/baidu/ote-stack/pkg/util" 14 | ) 15 | 16 | func TestHandleEvent(t *testing.T) { 17 | ctx := newSynceContext(t) 18 | NewSyncerInformerFactory(ctx) 19 | syncer := NewEventSyncer(ctx) 20 | 21 | event := &corev1.Event{ 22 | ObjectMeta: metav1.ObjectMeta{ 23 | Name: "test", 24 | ResourceVersion: "0", 25 | }, 26 | } 27 | key, err := cache.MetaNamespaceKeyFunc(event) 28 | if err != nil { 29 | t.Error(err) 30 | } 31 | 32 | // test add event 33 | syncer.handleAddEvent(event) 34 | data, err := ctx.Store.LevelDB.Get(util.ResourceEvent, key) 35 | assert.Nil(t, err) 36 | 37 | obj := &corev1.Event{} 38 | err = json.Unmarshal(data, obj) 39 | if err != nil { 40 | t.Error(err) 41 | } 42 | 43 | assert.Equal(t, "test", obj.Name) 44 | 45 | // test update event 46 | newEvent := &corev1.Event{ 47 | ObjectMeta: metav1.ObjectMeta{ 48 | Name: "test", 49 | ResourceVersion: "1", 50 | }, 51 | } 52 | 53 | syncer.handleUpdateEvent(event, newEvent) 54 | data, err = ctx.Store.LevelDB.Get(util.ResourceEvent, key) 55 | assert.Nil(t, err) 56 | 57 | obj = &corev1.Event{} 58 | err = json.Unmarshal(data, obj) 59 | if err != nil { 60 | t.Error(err) 61 | } 62 | 63 | assert.Equal(t, "test", obj.Name) 64 | assert.Equal(t, "1", obj.ResourceVersion) 65 | 66 | // test delete event 67 | syncer.handleDeleteEvent(event) 68 | data, err = ctx.Store.LevelDB.Get(util.ResourceEvent, key) 69 | assert.NotNil(t, err) 70 | 71 | ctx.Store.Close() 72 | os.RemoveAll("../../db_test/") 73 | } 74 | -------------------------------------------------------------------------------- /pkg/syncer/lease_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "k8s.io/api/coordination/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleNodeLeaseEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceNodeLease, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewLeaseSyncer(ctx) 25 | 26 | lease := &v1.Lease{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | ResourceVersion: "0", 30 | }, 31 | } 32 | key, err := cache.MetaNamespaceKeyFunc(lease) 33 | if err != nil { 34 | t.Error(err) 35 | } 36 | 37 | // test add event 38 | syncer.handleAddEvent(lease) 39 | data, err := ctx.Store.LevelDB.Get(util.ResourceNodeLease, key) 40 | assert.Nil(t, err) 41 | 42 | obj := &v1.Lease{} 43 | err = json.Unmarshal(data, obj) 44 | if err != nil { 45 | t.Error(err) 46 | } 47 | 48 | assert.Equal(t, "test", obj.Name) 49 | 50 | event := <-EdgeSubscriber.subscriber[util.ResourceNodeLease]["key"] 51 | assert.Equal(t, string(watch.Added), event.Type) 52 | assert.Equal(t, lease, event.Object.Object) 53 | 54 | // test update event 55 | newLease := &v1.Lease{ 56 | ObjectMeta: metav1.ObjectMeta{ 57 | Name: "test", 58 | ResourceVersion: "1", 59 | }, 60 | } 61 | 62 | syncer.handleUpdateEvent(lease, newLease) 63 | data, err = ctx.Store.LevelDB.Get(util.ResourceNodeLease, key) 64 | assert.Nil(t, err) 65 | 66 | obj = &v1.Lease{} 67 | err = json.Unmarshal(data, obj) 68 | if err != nil { 69 | t.Error(err) 70 | } 71 | 72 | assert.Equal(t, "test", obj.Name) 73 | assert.Equal(t, "1", obj.ResourceVersion) 74 | 75 | event = <-EdgeSubscriber.subscriber[util.ResourceNodeLease]["key"] 76 | assert.Equal(t, string(watch.Modified), event.Type) 77 | assert.Equal(t, newLease, event.Object.Object) 78 | 79 | // test delete event 80 | syncer.handleDeleteEvent(lease) 81 | data, err = ctx.Store.LevelDB.Get(util.ResourceNodeLease, key) 82 | assert.NotNil(t, err) 83 | 84 | event = <-EdgeSubscriber.subscriber[util.ResourceNodeLease]["key"] 85 | assert.Equal(t, string(watch.Deleted), event.Type) 86 | assert.Equal(t, lease, event.Object.Object) 87 | 88 | EdgeSubscriber.Delete(util.ResourceNodeLease, "key") 89 | ctx.Store.Close() 90 | os.RemoveAll("../../db_test/") 91 | } 92 | -------------------------------------------------------------------------------- /pkg/syncer/namespace_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleNamespaceEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceNamespace, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewNamespaceSyncer(ctx) 25 | 26 | namespace := &corev1.Namespace{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | ResourceVersion: "0", 30 | }, 31 | } 32 | key, err := cache.MetaNamespaceKeyFunc(namespace) 33 | if err != nil { 34 | t.Error(err) 35 | } 36 | 37 | // test add event 38 | syncer.handleAddEvent(namespace) 39 | data, err := ctx.Store.LevelDB.Get(util.ResourceNamespace, key) 40 | assert.Nil(t, err) 41 | 42 | obj := &corev1.Namespace{} 43 | err = json.Unmarshal(data, obj) 44 | if err != nil { 45 | t.Error(err) 46 | } 47 | 48 | assert.Equal(t, "test", obj.Name) 49 | 50 | event := <-EdgeSubscriber.subscriber[util.ResourceNamespace]["key"] 51 | assert.Equal(t, string(watch.Added), event.Type) 52 | assert.Equal(t, namespace, event.Object.Object) 53 | 54 | // test update event 55 | newNamespace := &corev1.Namespace{ 56 | ObjectMeta: metav1.ObjectMeta{ 57 | Name: "test", 58 | ResourceVersion: "1", 59 | }, 60 | } 61 | 62 | syncer.handleUpdateEvent(namespace, newNamespace) 63 | data, err = ctx.Store.LevelDB.Get(util.ResourceNamespace, key) 64 | assert.Nil(t, err) 65 | 66 | obj = &corev1.Namespace{} 67 | err = json.Unmarshal(data, obj) 68 | if err != nil { 69 | t.Error(err) 70 | } 71 | 72 | assert.Equal(t, "test", obj.Name) 73 | assert.Equal(t, "1", obj.ResourceVersion) 74 | 75 | event = <-EdgeSubscriber.subscriber[util.ResourceNamespace]["key"] 76 | assert.Equal(t, string(watch.Modified), event.Type) 77 | assert.Equal(t, newNamespace, event.Object.Object) 78 | 79 | // test delete event 80 | syncer.handleDeleteEvent(namespace) 81 | data, err = ctx.Store.LevelDB.Get(util.ResourceNamespace, key) 82 | assert.NotNil(t, err) 83 | 84 | event = <-EdgeSubscriber.subscriber[util.ResourceNamespace]["key"] 85 | assert.Equal(t, string(watch.Deleted), event.Type) 86 | assert.Equal(t, namespace, event.Object.Object) 87 | 88 | EdgeSubscriber.Delete(util.ResourceNamespace, "key") 89 | ctx.Store.Close() 90 | os.RemoveAll("../../db_test/") 91 | } 92 | -------------------------------------------------------------------------------- /pkg/syncer/networkpolicy_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "k8s.io/api/networking/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleNetworkPolicyEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceNetworkPolicy, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewNetworkPolicySyncer(ctx) 25 | 26 | np := &v1.NetworkPolicy{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(np) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(np) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourceNetworkPolicy, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &v1.NetworkPolicy{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourceNetworkPolicy]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, np, event.Object.Object) 55 | 56 | // test update event 57 | newNP := &v1.NetworkPolicy{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(np, newNP) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourceNetworkPolicy, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &v1.NetworkPolicy{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourceNetworkPolicy]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newNP, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(np) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourceNetworkPolicy, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourceNetworkPolicy]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, np, event.Object.Object) 91 | 92 | EdgeSubscriber.Delete(util.ResourceNetworkPolicy, "key") 93 | ctx.Store.Close() 94 | os.RemoveAll("../../db_test/") 95 | } 96 | -------------------------------------------------------------------------------- /pkg/syncer/node_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleNodeEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceNode, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewNodeSyncer(ctx) 25 | 26 | node := &corev1.Node{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | ResourceVersion: "0", 30 | }, 31 | } 32 | key, err := cache.MetaNamespaceKeyFunc(node) 33 | if err != nil { 34 | t.Error(err) 35 | } 36 | 37 | // test add event 38 | syncer.handleAddEvent(node) 39 | data, err := ctx.Store.LevelDB.Get(util.ResourceNode, key) 40 | assert.Nil(t, err) 41 | 42 | obj := &corev1.Node{} 43 | err = json.Unmarshal(data, obj) 44 | if err != nil { 45 | t.Error(err) 46 | } 47 | 48 | assert.Equal(t, "test", obj.Name) 49 | 50 | event := <-EdgeSubscriber.subscriber[util.ResourceNode]["key"] 51 | assert.Equal(t, string(watch.Added), event.Type) 52 | assert.Equal(t, node, event.Object.Object) 53 | 54 | // test update event 55 | newNode := &corev1.Node{ 56 | ObjectMeta: metav1.ObjectMeta{ 57 | Name: "test", 58 | ResourceVersion: "1", 59 | }, 60 | } 61 | 62 | syncer.handleUpdateEvent(node, newNode) 63 | data, err = ctx.Store.LevelDB.Get(util.ResourceNode, key) 64 | assert.Nil(t, err) 65 | 66 | obj = &corev1.Node{} 67 | err = json.Unmarshal(data, obj) 68 | if err != nil { 69 | t.Error(err) 70 | } 71 | 72 | assert.Equal(t, "test", obj.Name) 73 | assert.Equal(t, "1", obj.ResourceVersion) 74 | 75 | event = <-EdgeSubscriber.subscriber[util.ResourceNode]["key"] 76 | assert.Equal(t, string(watch.Modified), event.Type) 77 | assert.Equal(t, newNode, event.Object.Object) 78 | 79 | // test delete event 80 | syncer.handleDeleteEvent(node) 81 | data, err = ctx.Store.LevelDB.Get(util.ResourceNode, key) 82 | assert.NotNil(t, err) 83 | 84 | event = <-EdgeSubscriber.subscriber[util.ResourceNode]["key"] 85 | assert.Equal(t, string(watch.Deleted), event.Type) 86 | assert.Equal(t, node, event.Object.Object) 87 | 88 | EdgeSubscriber.Delete(util.ResourceNode, "key") 89 | ctx.Store.Close() 90 | os.RemoveAll("../../db_test/") 91 | } 92 | -------------------------------------------------------------------------------- /pkg/syncer/pod_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandlePodEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourcePod, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewPodSyncer(ctx) 25 | 26 | pod := &corev1.Pod{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(pod) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(pod) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourcePod, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &corev1.Pod{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourcePod]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, pod, event.Object.Object) 55 | 56 | // test update event 57 | newPod := &corev1.Pod{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(pod, newPod) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourcePod, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &corev1.Pod{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourcePod]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newPod, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(pod) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourcePod, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourcePod]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, pod, event.Object.Object) 91 | 92 | EdgeSubscriber.Delete(util.ResourcePod, "key") 93 | ctx.Store.Close() 94 | os.RemoveAll("../../db_test/") 95 | } 96 | -------------------------------------------------------------------------------- /pkg/syncer/runtimeclass_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "k8s.io/api/node/v1beta1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleRuntimeClassEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceRuntimeClass, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewRuntimeClassSyncer(ctx) 25 | 26 | rc := &v1beta1.RuntimeClass{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | ResourceVersion: "0", 30 | }, 31 | } 32 | key, err := cache.MetaNamespaceKeyFunc(rc) 33 | if err != nil { 34 | t.Error(err) 35 | } 36 | 37 | // test add event 38 | syncer.handleAddEvent(rc) 39 | data, err := ctx.Store.LevelDB.Get(util.ResourceRuntimeClass, key) 40 | assert.Nil(t, err) 41 | 42 | obj := &v1beta1.RuntimeClass{} 43 | err = json.Unmarshal(data, obj) 44 | if err != nil { 45 | t.Error(err) 46 | } 47 | 48 | assert.Equal(t, "test", obj.Name) 49 | 50 | event := <-EdgeSubscriber.subscriber[util.ResourceRuntimeClass]["key"] 51 | assert.Equal(t, string(watch.Added), event.Type) 52 | assert.Equal(t, rc, event.Object.Object) 53 | 54 | // test update event 55 | newRC := &v1beta1.RuntimeClass{ 56 | ObjectMeta: metav1.ObjectMeta{ 57 | Name: "test", 58 | ResourceVersion: "1", 59 | }, 60 | } 61 | 62 | syncer.handleUpdateEvent(rc, newRC) 63 | data, err = ctx.Store.LevelDB.Get(util.ResourceRuntimeClass, key) 64 | assert.Nil(t, err) 65 | 66 | obj = &v1beta1.RuntimeClass{} 67 | err = json.Unmarshal(data, obj) 68 | if err != nil { 69 | t.Error(err) 70 | } 71 | 72 | assert.Equal(t, "test", obj.Name) 73 | assert.Equal(t, "1", obj.ResourceVersion) 74 | 75 | event = <-EdgeSubscriber.subscriber[util.ResourceRuntimeClass]["key"] 76 | assert.Equal(t, string(watch.Modified), event.Type) 77 | assert.Equal(t, newRC, event.Object.Object) 78 | 79 | // test delete event 80 | syncer.handleDeleteEvent(rc) 81 | data, err = ctx.Store.LevelDB.Get(util.ResourceRuntimeClass, key) 82 | assert.NotNil(t, err) 83 | 84 | event = <-EdgeSubscriber.subscriber[util.ResourceRuntimeClass]["key"] 85 | assert.Equal(t, string(watch.Deleted), event.Type) 86 | assert.Equal(t, rc, event.Object.Object) 87 | 88 | ctx.Store.Close() 89 | os.RemoveAll("../../db_test/") 90 | } 91 | -------------------------------------------------------------------------------- /pkg/syncer/secret_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleSecretEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceSecret, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewSecretSyncer(ctx) 25 | 26 | secret := &corev1.Secret{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(secret) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(secret) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourceSecret, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &corev1.Secret{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourceSecret]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, secret, event.Object.Object) 55 | 56 | // test update event 57 | newSecret := &corev1.Secret{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(secret, newSecret) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourceSecret, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &corev1.Secret{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourceSecret]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newSecret, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(secret) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourceSecret, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourceSecret]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, secret, event.Object.Object) 91 | 92 | EdgeSubscriber.Delete(util.ResourceSecret, "key") 93 | ctx.Store.Close() 94 | os.RemoveAll("../../db_test/") 95 | } 96 | -------------------------------------------------------------------------------- /pkg/syncer/service_syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/util/json" 11 | "k8s.io/apimachinery/pkg/watch" 12 | "k8s.io/client-go/tools/cache" 13 | 14 | "github.com/baidu/ote-stack/pkg/util" 15 | ) 16 | 17 | func TestHandleServiceEvent(t *testing.T) { 18 | InitSubscriber() 19 | watchChan := make(chan metav1.WatchEvent) 20 | EdgeSubscriber.Add(util.ResourceService, "key", watchChan) 21 | 22 | ctx := newSynceContext(t) 23 | NewSyncerInformerFactory(ctx) 24 | syncer := NewServiceSyncer(ctx) 25 | 26 | service := &corev1.Service{ 27 | ObjectMeta: metav1.ObjectMeta{ 28 | Name: "test", 29 | Namespace: "ns", 30 | ResourceVersion: "0", 31 | }, 32 | } 33 | key, err := cache.MetaNamespaceKeyFunc(service) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | // test add event 39 | syncer.handleAddEvent(service) 40 | data, err := ctx.Store.LevelDB.Get(util.ResourceService, key) 41 | assert.Nil(t, err) 42 | 43 | obj := &corev1.Service{} 44 | err = json.Unmarshal(data, obj) 45 | if err != nil { 46 | t.Error(err) 47 | } 48 | 49 | assert.Equal(t, "test", obj.Name) 50 | assert.Equal(t, "ns", obj.Namespace) 51 | 52 | event := <-EdgeSubscriber.subscriber[util.ResourceService]["key"] 53 | assert.Equal(t, string(watch.Added), event.Type) 54 | assert.Equal(t, service, event.Object.Object) 55 | 56 | // test update event 57 | newService := &corev1.Service{ 58 | ObjectMeta: metav1.ObjectMeta{ 59 | Name: "test", 60 | Namespace: "ns", 61 | ResourceVersion: "1", 62 | }, 63 | } 64 | 65 | syncer.handleUpdateEvent(service, newService) 66 | data, err = ctx.Store.LevelDB.Get(util.ResourceService, key) 67 | assert.Nil(t, err) 68 | 69 | obj = &corev1.Service{} 70 | err = json.Unmarshal(data, obj) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | assert.Equal(t, "test", obj.Name) 76 | assert.Equal(t, "ns", obj.Namespace) 77 | assert.Equal(t, "1", obj.ResourceVersion) 78 | 79 | event = <-EdgeSubscriber.subscriber[util.ResourceService]["key"] 80 | assert.Equal(t, string(watch.Modified), event.Type) 81 | assert.Equal(t, newService, event.Object.Object) 82 | 83 | // test delete event 84 | syncer.handleDeleteEvent(service) 85 | data, err = ctx.Store.LevelDB.Get(util.ResourceService, key) 86 | assert.NotNil(t, err) 87 | 88 | event = <-EdgeSubscriber.subscriber[util.ResourceService]["key"] 89 | assert.Equal(t, string(watch.Deleted), event.Type) 90 | assert.Equal(t, service, event.Object.Object) 91 | 92 | EdgeSubscriber.Delete(util.ResourceService, "key") 93 | ctx.Store.Close() 94 | os.RemoveAll("../../db_test/") 95 | } 96 | -------------------------------------------------------------------------------- /pkg/syncer/syncer_test.go: -------------------------------------------------------------------------------- 1 | package syncer 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "k8s.io/apimachinery/pkg/runtime" 9 | k8sfake "k8s.io/client-go/kubernetes/fake" 10 | 11 | "github.com/baidu/ote-stack/pkg/storage" 12 | ) 13 | 14 | func newSynceContext(t *testing.T) *SyncContext { 15 | store, err := storage.NewEdgehubStore(&storage.Config{ 16 | Path: "../../db_test/", 17 | }) 18 | if err != nil { 19 | t.Errorf("%v", err) 20 | return nil 21 | } 22 | 23 | return &SyncContext{ 24 | NodeName: "test", 25 | KubeClient: k8sfake.NewSimpleClientset([]runtime.Object{}...), 26 | Store: store, 27 | SyncTimeout: 60, 28 | } 29 | } 30 | 31 | func TestStartAndStopSyncer(t *testing.T) { 32 | // no store 33 | ctx := &SyncContext{ 34 | NodeName: "test", 35 | KubeClient: k8sfake.NewSimpleClientset([]runtime.Object{}...), 36 | SyncTimeout: 60, 37 | } 38 | err := StartSyncer(ctx) 39 | assert.NotNil(t, err) 40 | 41 | // no KubeClient 42 | ctx = &SyncContext{ 43 | NodeName: "test", 44 | } 45 | err = StartSyncer(ctx) 46 | assert.NotNil(t, err) 47 | 48 | // success start syncer 49 | ctx = newSynceContext(t) 50 | err = StartSyncer(ctx) 51 | assert.NotNil(t, ctx.InformerFactory) 52 | assert.NotNil(t, ctx.StopChan) 53 | assert.Nil(t, err) 54 | 55 | // failed to stop syncer 56 | close(ctx.StopChan) 57 | err = StopSyncer(ctx) 58 | assert.NotNil(t, err) 59 | 60 | // success stop syncer 61 | err = StartSyncer(ctx) 62 | assert.Nil(t, err) 63 | err = StopSyncer(ctx) 64 | assert.Nil(t, err) 65 | assert.Nil(t, ctx.InformerFactory) 66 | assert.Nil(t, Syncers) 67 | 68 | ctx.Store.Close() 69 | os.RemoveAll("../../db_test/") 70 | } 71 | -------------------------------------------------------------------------------- /pkg/tunnel/wsclient_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Baidu, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package tunnel 18 | 19 | import ( 20 | "net/http" 21 | "net/http/httptest" 22 | "net/url" 23 | "os" 24 | "testing" 25 | 26 | "github.com/gorilla/websocket" 27 | ) 28 | 29 | var ( 30 | testServer *httptest.Server 31 | ) 32 | 33 | func initTestServer() { 34 | testServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 35 | upgrader = websocket.Upgrader{} 36 | c, err := upgrader.Upgrade(w, r, nil) 37 | if err != nil { 38 | return 39 | } 40 | defer c.Close() 41 | for { 42 | mt, message, err := c.ReadMessage() 43 | if err != nil { 44 | break 45 | } 46 | err = c.WriteMessage(mt, message) 47 | if err != nil { 48 | break 49 | } 50 | } 51 | })) 52 | } 53 | 54 | func newTestWSClient() *WSClient { 55 | u := url.URL{Scheme: "ws", Host: testServer.Listener.Addr().String(), Path: "/"} 56 | conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil) 57 | if err != nil { 58 | return nil 59 | } 60 | return NewWSClient("test", conn) 61 | } 62 | 63 | func TestWriteMessage(t *testing.T) { 64 | client := newTestWSClient() 65 | if client == nil { 66 | t.Errorf("can not build websocket connection") 67 | } 68 | 69 | expectMsg := "test msg" 70 | err := client.WriteMessage([]byte(expectMsg)) 71 | if err != nil { 72 | t.Errorf("fail to send msg, err: %v", err) 73 | return 74 | } 75 | 76 | } 77 | 78 | func TestReadMessage(t *testing.T) { 79 | client := newTestWSClient() 80 | if client == nil { 81 | t.Errorf("can not build websocket connection") 82 | } 83 | 84 | // test receive 85 | expectMsg := "test msg" 86 | client.Conn.WriteMessage(websocket.BinaryMessage, []byte(expectMsg)) 87 | msg, err := client.ReadMessage() 88 | if err != nil { 89 | t.Errorf("fail to read msg, err: %v", err) 90 | } else if string(msg) != expectMsg { 91 | t.Errorf("receive msg %s, expect %s", string(msg), expectMsg) 92 | } 93 | 94 | // test error 95 | client.Close() 96 | _, err = client.ReadMessage() 97 | if err == nil { 98 | t.Errorf("expect error") 99 | } 100 | } 101 | 102 | func TestMain(m *testing.M) { 103 | initTestServer() 104 | exit := m.Run() 105 | testServer.Close() 106 | os.Exit(exit) 107 | } 108 | -------------------------------------------------------------------------------- /pkg/util/util_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | corev1 "k8s.io/api/core/v1" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | "k8s.io/apimachinery/pkg/util/json" 10 | ) 11 | 12 | func TestFormKeyName(t *testing.T) { 13 | key := FormKeyName("ns1", "name1") 14 | assert.Equal(t, "ns1/name1", key) 15 | 16 | key = FormKeyName("", "name1") 17 | assert.Equal(t, "name1", key) 18 | } 19 | 20 | func TestGetObjectFromSerializeData(t *testing.T) { 21 | pod := &corev1.Pod{ 22 | ObjectMeta: metav1.ObjectMeta{ 23 | Name: "test", 24 | }, 25 | } 26 | 27 | data, err := json.Marshal(pod) 28 | assert.Nil(t, err) 29 | assert.NotNil(t, data) 30 | 31 | obj, err := GetObjectFromSerializeData(ResourcePod, data) 32 | assert.Nil(t, err) 33 | assert.Equal(t, "test", obj.(*corev1.Pod).Name) 34 | 35 | obj, err = GetObjectFromSerializeData("ingress", data) 36 | assert.NotNil(t, err) 37 | assert.Nil(t, obj) 38 | } 39 | --------------------------------------------------------------------------------