diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d5a6e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +quarkcm +quarkcmclient/target/ +__debug_bin diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d428a1f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "main.go" + } + ] +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a2832e1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM golang AS builder + +RUN apt-get update && \ + apt-get install -y --no-install-recommends build-essential && \ + apt-get clean && \ + mkdir -p "$GOPATH/src/github.com/CentaurusInfra/quarkcm" + +ADD . "$GOPATH/src/github.com/CentaurusInfra/quarkcm" + +RUN cd "$GOPATH/src/github.com/CentaurusInfra/quarkcm" && \ + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a --installsuffix cgo --ldflags="-s" -o /quarkcm + +FROM bitnami/minideb:stretch +RUN install_packages ca-certificates + +COPY --from=builder /quarkcm /bin/quarkcm + +ENTRYPOINT ["/bin/quarkcm"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..56d882d --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 quarkcm Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0750ca7 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +.PHONY: default build docker-image test stop clean-images clean + +BINARY = quarkcm + +VERSION= +BUILD= + +PKG = github.com/CentaurusInfra/quarkcm +GOCMD = go +BUILD_DATE = `date +%FT%T%z` +GOFLAGS ?= $(GOFLAGS:) +LDFLAGS := "-X '$(PKG)/cmd.buildDate=$(BUILD_DATE)'" + +default: build test + +build: proto + "$(GOCMD)" build ${GOFLAGS} -ldflags ${LDFLAGS} -o "${BINARY}" + +docker-image: + @docker build -t "${BINARY}" . + +test: + "$(GOCMD)" test -race -v ./... + +stop: + @docker stop "${BINARY}" + +clean-images: stop + @docker rmi "${BUILDER}" "${BINARY}" + +clean: + "$(GOCMD)" clean -i + +proto: + protoc --go_out=. --go-grpc_out=. pkg/grpc/quarkcmsvc.proto diff --git a/README.md b/README.md index 278929a..95906b5 100644 --- a/README.md +++ b/README.md @@ -1 +1,13 @@ -# rdma-cm \ No newline at end of file +# quarkcm + +quarkcm is Connection Manager for Quark CDMA Networking Solution. + +## push to docker hub +sudo docker login -u quarkcm + +sudo docker image build -t quarkcm/quarkcm:v0.1.0 -f Dockerfile . +sudo docker image push quarkcm/quarkcm:v0.1.0 + + +## deploy to cluster +kubectl apply -f deploy-quarkcm.yaml diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..2806148 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,62 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "fmt" + "os" + + c "github.com/CentaurusInfra/quarkcm/pkg/client" + "github.com/spf13/cobra" +) + +// RootCmd represents the base command when called without any subcommands +var RootCmd = &cobra.Command{ + Use: "quarkcm", + Short: "Quark Connection Manager", + Long: ` + quarkcm: Quark Connection Manager + +quarkcm is Quark's Connection Manager +that watching the cluster for changes +and syncing to RDMASvc. + +`, + + Run: func(cmd *cobra.Command, args []string) { + c.Run() + }, +} + +// Execute adds all child commands to the root command sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + if err := RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) + } +} + +func init() { + cobra.OnInitialize() + + // Disable Help subcommand + RootCmd.SetHelpCommand(&cobra.Command{ + Use: "no-help", + Hidden: true, + }) +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 0000000..2dd0016 --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,40 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "print version", + Long: `print version`, + Run: func(cmd *cobra.Command, args []string) { + versionPrettyString() + }, +} + +func versionPrettyString() { + fmt.Println("v0.1.0") +} + +func init() { + RootCmd.AddCommand(versionCmd) +} diff --git a/deploy-quarkcm.yaml b/deploy-quarkcm.yaml new file mode 100644 index 0000000..6c1fc98 --- /dev/null +++ b/deploy-quarkcm.yaml @@ -0,0 +1,61 @@ +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: quarkcm-operator +rules: +- apiGroups: [""] + resources: ["pods", "nodes"] + verbs: ["get", "watch", "list"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: quarkcm-operator + namespace: default +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: quarkcm-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: quarkcm-operator +subjects: + - kind: ServiceAccount + name: quarkcm-operator + namespace: default +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: quarkcm-daemon + namespace: default +spec: + selector: + matchLabels: + job: quarkcm-daemon + template: + metadata: + labels: + job: quarkcm-daemon + spec: + tolerations: + # The daemon shall run on the master node + - effect: NoSchedule + operator: Exists + serviceAccountName: quarkcm-operator + terminationGracePeriodSeconds: 0 + hostNetwork: true + hostPID: true + containers: + - name: quarkcm-daemon + image: quarkcm/quarkcm:v0.1.0 + securityContext: + privileged: true + volumes: + - name: quarkcm-volume + hostPath: + path: /var + type: Directory diff --git a/docs/design.md b/docs/design.md new file mode 100644 index 0000000..17a7298 --- /dev/null +++ b/docs/design.md @@ -0,0 +1,3 @@ +# quarkcm + +quarkcm is Connection Manager for Quark CDMA Networking Solution. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..89aecd1 --- /dev/null +++ b/go.mod @@ -0,0 +1,37 @@ +module github.com/CentaurusInfra/quarkcm + +go 1.14 + +require ( + github.com/fatih/structtag v1.2.0 + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect + github.com/google/uuid v1.1.2 + github.com/googleapis/gnostic v0.1.0 // indirect + github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/magiconair/properties v1.7.4 // indirect + github.com/mitchellh/mapstructure v0.0.0-20180111000720-b4575eea38cc // indirect + github.com/mkmik/multierror v0.3.0 + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/pelletier/go-toml v1.0.1 // indirect + github.com/segmentio/textio v1.2.0 + github.com/spf13/cast v1.1.0 // indirect + github.com/spf13/cobra v0.0.1 + github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec // indirect + github.com/spf13/viper v1.0.0 + golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect + golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect + google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect + google.golang.org/grpc v1.45.0 + google.golang.org/protobuf v1.28.0 + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/yaml.v2 v2.3.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c + k8s.io/api v0.16.8 + k8s.io/apimachinery v0.16.8 + k8s.io/client-go v0.16.8 + k8s.io/klog v1.0.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..55e1016 --- /dev/null +++ b/go.sum @@ -0,0 +1,340 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= +github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb h1:1OvvPvZkn/yCQ3xBcM8y4020wdkMXPHLB4+NfoGWh4U= +github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.7.4 h1:UVo0TkHGd4lQSN1dVDzs9URCIgReuSIcCXpAVB9nZ80= +github.com/magiconair/properties v1.7.4/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mitchellh/mapstructure v0.0.0-20180111000720-b4575eea38cc h1:5T6hzGUO5OrL6MdYXYoLQtRWJDDgjdlOVBn9mIqGY1g= +github.com/mitchellh/mapstructure v0.0.0-20180111000720-b4575eea38cc/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mkmik/multierror v0.3.0 h1:FHr3n5BEVlzlTz8GRbuwimkL2zbdD2gTPcSh0wpRpUg= +github.com/mkmik/multierror v0.3.0/go.mod h1:wjBYXRpDhh+8mIp+iLBOq0kZ3Y4ICTncojwvP8LUYLQ= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pelletier/go-toml v1.0.1 h1:0nx4vKBl23+hEaCOV1mFhKS9vhhBtFYWC7rQY0vJAyE= +github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/segmentio/textio v1.2.0 h1:Ug4IkV3kh72juJbG8azoSBlgebIbUUxVNrfFcKHfTSQ= +github.com/segmentio/textio v1.2.0/go.mod h1:+Rb7v0YVODP+tK5F7FD9TCkV7gOYx9IgLHWiqtvY8ag= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.1.0 h1:0Rhw4d6C8J9VPu6cjZLIhZ8+aAOHcDvGeKn+cq5Aq3k= +github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/cobra v0.0.1 h1:zZh3X5aZbdnoj+4XkaBxKfhO4ot82icYdhhREIAXIj8= +github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig= +github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I= +github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw= +golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac h1:qSNTkEN+L2mvWcLgJOR+8bdHX9rN/IdU3A1Ghpfb1Rg= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.16.8 h1:T72itM0CUT8KHqPAqbjTeSY0n24RyVM71nLiMlq/cAw= +k8s.io/api v0.16.8/go.mod h1:a8EOdYHO8en+YHhPBLiW5q+3RfHTr7wxTqqp7emJ7PM= +k8s.io/apimachinery v0.16.8 h1:wgFRqtel3w3rcclpba+iBkVlKeBlh42OzNp7FalXVCg= +k8s.io/apimachinery v0.16.8/go.mod h1:Xk2vD2TRRpuWYLQNM6lT9R7DSFZUYG03SarNkbGrnKE= +k8s.io/client-go v0.16.8 h1:CmsQXJpSWq1aUyQ5Lp/rRPiMK2OYfJv32Ftl0D1D42U= +k8s.io/client-go v0.16.8/go.mod h1:WmPuN0yJTKHXoklExKxzo3jSXmr3EnN+65uaTb5VuNs= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE= +k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/main.go b/main.go new file mode 100644 index 0000000..f7726d0 --- /dev/null +++ b/main.go @@ -0,0 +1,29 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "github.com/CentaurusInfra/quarkcm/cmd" + "k8s.io/klog" +) + +func main() { + klog.InitFlags(nil) + defer klog.Flush() + + cmd.Execute() +} diff --git a/pkg/client/run.go b/pkg/client/run.go new file mode 100644 index 0000000..1f0b5ff --- /dev/null +++ b/pkg/client/run.go @@ -0,0 +1,28 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "github.com/CentaurusInfra/quarkcm/pkg/controller" + "github.com/CentaurusInfra/quarkcm/pkg/grpc" +) + +// Run runs the event loop processing with given handler +func Run() { + grpc.StartServer() + controller.Start() +} diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go new file mode 100644 index 0000000..69ceb84 --- /dev/null +++ b/pkg/constants/constants.go @@ -0,0 +1,25 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package constants + +const ( + ResourceType_Pod string = "pod" + ResourceType_Node string = "node" + + EventType_Set string = "set" + EventType_Delete string = "delete" +) diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go new file mode 100644 index 0000000..09771de --- /dev/null +++ b/pkg/controller/controller.go @@ -0,0 +1,159 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "fmt" + "os" + "os/signal" + "strings" + "syscall" + "time" + + "github.com/CentaurusInfra/quarkcm/pkg/handlers" + "github.com/CentaurusInfra/quarkcm/pkg/objects" + "github.com/CentaurusInfra/quarkcm/pkg/utils" + "k8s.io/klog" + + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" +) + +const maxRetries = 5 + +type Controller struct { + resourceType string + clientset kubernetes.Interface + queue workqueue.RateLimitingInterface + informer cache.SharedIndexInformer + eventHandler handlers.Handler +} + +func Start() { + var kubeClient kubernetes.Interface + + if _, err := rest.InClusterConfig(); err != nil { + kubeClient = utils.GetClientOutOfCluster() + } else { + kubeClient = utils.GetClient() + } + + nodeController := NewNodeController(kubeClient) + nodeStopCh := make(chan struct{}) + defer close(nodeStopCh) + + nodeController.Start(nodeStopCh) // Sync start node controller first, to generating node ip set for filtering pod ip + go nodeController.Wait(nodeStopCh) + + podController := NewPodController(kubeClient) + podStopCh := make(chan struct{}) + defer close(podStopCh) + + go podController.Run(podStopCh) + + sigterm := make(chan os.Signal, 1) + signal.Notify(sigterm, syscall.SIGTERM) + signal.Notify(sigterm, syscall.SIGINT) + <-sigterm +} + +func (c *Controller) Run(stopCh <-chan struct{}) { + c.Start(stopCh) + c.Wait(stopCh) +} + +func (c *Controller) Start(stopCh <-chan struct{}) { + defer utilruntime.HandleCrash() + + klog.Infof("Starting quarkcm %s controller", c.resourceType) + go c.informer.Run(stopCh) + + if !cache.WaitForCacheSync(stopCh, c.HasSynced) { + utilruntime.HandleError(fmt.Errorf("%s controller timed out waiting for caches to sync", c.resourceType)) + return + } + klog.Infof("quarkcm %s controller synced and ready", c.resourceType) +} + +func (c *Controller) Wait(stopCh <-chan struct{}) { + defer utilruntime.HandleCrash() + defer c.queue.ShutDown() + wait.Until(c.runWorker, time.Second, stopCh) +} + +// HasSynced is required for the cache.Controller interface. +func (c *Controller) HasSynced() bool { + return c.informer.HasSynced() +} + +// LastSyncResourceVersion is required for the cache.Controller interface. +func (c *Controller) LastSyncResourceVersion() string { + return c.informer.LastSyncResourceVersion() +} + +func (c *Controller) runWorker() { + for c.processNextItem() { + // continue looping + } +} + +func (c *Controller) processNextItem() bool { + queueItem, quit := c.queue.Get() + eventItem := queueItem.(objects.EventItem) + + if quit { + return false + } + defer c.queue.Done(queueItem) + err := c.processItem(eventItem) + if err == nil { + // No error, reset the ratelimit counters + c.queue.Forget(queueItem) + } else if c.queue.NumRequeues(queueItem) < maxRetries { + klog.Errorf("error processing %s (will retry): %v. Tracking Id: %s", eventItem.Key, err, eventItem.Id) + c.queue.AddRateLimited(queueItem) + } else { + // err != nil and too many retries + klog.Errorf("error processing %s (giving up): %v. Tracking Id: %s", eventItem.Key, err, eventItem.Id) + c.queue.Forget(queueItem) + utilruntime.HandleError(err) + } + + return true +} + +func (c *Controller) processItem(eventItem objects.EventItem) error { + obj, _, err := c.informer.GetIndexer().GetByKey(eventItem.Key) + if err != nil { + return fmt.Errorf("error fetching object with key %s from store: %v. Tracking Id: %s", eventItem.Key, err, eventItem.Id) + } + eventItem.Obj = obj + + // namespace retrived from event key incase namespace value is empty + if eventItem.Namespace == "" && strings.Contains(eventItem.Key, "/") { + substring := strings.Split(eventItem.Key, "/") + eventItem.Namespace = substring[0] + eventItem.Key = substring[1] + } + + c.eventHandler.Handle(eventItem) + return nil +} diff --git a/pkg/controller/controllerbuilder.go b/pkg/controller/controllerbuilder.go new file mode 100644 index 0000000..042d9a8 --- /dev/null +++ b/pkg/controller/controllerbuilder.go @@ -0,0 +1,112 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "github.com/CentaurusInfra/quarkcm/pkg/constants" + "github.com/CentaurusInfra/quarkcm/pkg/handlers" + "github.com/CentaurusInfra/quarkcm/pkg/objects" + "github.com/google/uuid" + api_v1 "k8s.io/api/core/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/klog" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" +) + +func NewPodController(client kubernetes.Interface) *Controller { + var eventHandler handlers.Handler = new(handlers.PodHandler) + informer := cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) { + return client.CoreV1().Pods("").List(options) + }, + WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) { + return client.CoreV1().Pods("").Watch(options) + }, + }, + &api_v1.Pod{}, + 0, + cache.Indexers{}, + ) + return newResourceController(client, eventHandler, informer, constants.ResourceType_Pod) +} + +func NewNodeController(client kubernetes.Interface) *Controller { + var eventHandler handlers.Handler = new(handlers.NodeHandler) + informer := cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) { + return client.CoreV1().Nodes().List(options) + }, + WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) { + return client.CoreV1().Nodes().Watch(options) + }, + }, + &api_v1.Node{}, + 0, + cache.Indexers{}, + ) + return newResourceController(client, eventHandler, informer, constants.ResourceType_Node) +} + +func newResourceController(client kubernetes.Interface, eventHandler handlers.Handler, informer cache.SharedIndexInformer, resourceType string) *Controller { + queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()) + var eventItem objects.EventItem + var err error + informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + eventItem.Key, err = cache.MetaNamespaceKeyFunc(obj) + eventItem.EventType = constants.EventType_Set + eventItem.Id = uuid.New().String() + klog.Infof("Processing add to %v: %s. Tracking Id: %s", resourceType, eventItem.Key, eventItem.Id) + if err == nil { + queue.Add(eventItem) + } + }, + UpdateFunc: func(old, new interface{}) { + eventItem.Key, err = cache.MetaNamespaceKeyFunc(old) + eventItem.EventType = constants.EventType_Set + eventItem.Id = uuid.New().String() + klog.Infof("Processing update to %v: %s. Tracking Id: %s", resourceType, eventItem.Key, eventItem.Id) + if err == nil { + queue.Add(eventItem) + } + }, + DeleteFunc: func(obj interface{}) { + eventItem.Key, err = cache.DeletionHandlingMetaNamespaceKeyFunc(obj) + eventItem.EventType = constants.EventType_Delete + eventItem.Id = uuid.New().String() + klog.Infof("Processing delete to %v: %s. Tracking Id: %s", resourceType, eventItem.Key, eventItem.Id) + if err == nil { + queue.Add(eventItem) + } + }, + }) + + return &Controller{ + resourceType: resourceType, + clientset: client, + informer: informer, + queue: queue, + eventHandler: eventHandler, + } +} diff --git a/pkg/datastore/datastore.go b/pkg/datastore/datastore.go new file mode 100644 index 0000000..95655cf --- /dev/null +++ b/pkg/datastore/datastore.go @@ -0,0 +1,248 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package datastore + +import ( + "encoding/json" + "sync" + + "github.com/CentaurusInfra/quarkcm/pkg/constants" + "github.com/CentaurusInfra/quarkcm/pkg/objects" + "github.com/google/uuid" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog" +) + +type DataStore struct { + NodeResourceVersion int + NodeMap map[string]*objects.NodeObject // map[node name] => node object + NodeEventMap map[int]*objects.NodeEventObject // map[resource version] => node event object + NodeQueueMap map[uuid.UUID]workqueue.RateLimitingInterface // map[guid] => node queue + NodeIPMap map[string]bool // map[node ip] => not using, this map is used as hashset + + PodResourceVersion int + PodMap map[string]*objects.PodObject // map[key] => pod object + PodEventMap map[int]*objects.PodEventObject // map[resource version] => pod event object + PodQueueMap map[uuid.UUID]workqueue.RateLimitingInterface // map[guid] => pod queue +} + +var lock = &sync.Mutex{} +var dataStore *DataStore + +func Instance() *DataStore { + if dataStore == nil { + lock.Lock() + defer lock.Unlock() + if dataStore == nil { + dataStore = &DataStore{ + NodeResourceVersion: 0, + NodeMap: map[string]*objects.NodeObject{}, + NodeEventMap: map[int]*objects.NodeEventObject{}, + NodeQueueMap: map[uuid.UUID]workqueue.RateLimitingInterface{}, + NodeIPMap: map[string]bool{}, + + PodResourceVersion: 0, + PodMap: map[string]*objects.PodObject{}, + PodEventMap: map[int]*objects.PodEventObject{}, + PodQueueMap: map[uuid.UUID]workqueue.RateLimitingInterface{}, + } + } + } + return dataStore +} + +func calculateNextNodeResourceVersion() int { + instance := Instance() + lock.Lock() + defer lock.Unlock() + instance.NodeResourceVersion += 1 + return instance.NodeResourceVersion +} + +func calculateNextPodResourceVersion() int { + instance := Instance() + lock.Lock() + defer lock.Unlock() + instance.PodResourceVersion += 1 + return instance.PodResourceVersion +} + +func SetNode(name string, nodeHostname string, nodeIP string, creationTimestamp int64, trackingId string) { + nodeMap := Instance().NodeMap + node, exists := nodeMap[name] + changed := false + if exists { + if node.Hostname != nodeHostname || node.IP != nodeIP { + changed = true + } else { + klog.Infof("Handling node completed. Node %s is unchanged. Tracking Id: %s", name, trackingId) + } + } else { + changed = true + } + + if changed { + resourceVersion := calculateNextNodeResourceVersion() + newNode := &objects.NodeObject{ + Name: name, + Hostname: nodeHostname, + IP: nodeIP, + CreationTimestamp: creationTimestamp, + ResourceVersion: resourceVersion, + } + newNodeEvent := &objects.NodeEventObject{ + ResourceVersion: resourceVersion, + EventType: constants.EventType_Set, + NodeObject: *newNode, + } + nodeMap[name] = newNode + Instance().NodeEventMap[resourceVersion] = newNodeEvent + EnqueueNode(*newNodeEvent) + + Instance().NodeIPMap[nodeIP] = true + + nodeStr, _ := json.Marshal(nodeMap[name]) + klog.Infof("Handling node completed. Node set as %s. Tracking Id: %s", nodeStr, trackingId) + } +} + +func DeleteNode(name string, trackingId string) { + nodeMap := Instance().NodeMap + node, exists := nodeMap[name] + if exists { + delete(Instance().NodeIPMap, node.IP) + resourceVersion := calculateNextNodeResourceVersion() + newNodeEvent := &objects.NodeEventObject{ + ResourceVersion: resourceVersion, + EventType: constants.EventType_Delete, + NodeObject: *node, + } + Instance().NodeEventMap[resourceVersion] = newNodeEvent + EnqueueNode(*newNodeEvent) + delete(nodeMap, name) + klog.Infof("Handling node completed. Node %s is deleted. Tracking Id: %s", name, trackingId) + } +} + +func ListNode(minResourceVersion int) []objects.NodeEventObject { + maxResourceVersion := Instance().NodeResourceVersion + nodeEventMap := Instance().NodeEventMap + + var nodeEvents []objects.NodeEventObject + for i := minResourceVersion + 1; i <= maxResourceVersion; i++ { + nodeEvents = append(nodeEvents, *nodeEventMap[i]) + } + return nodeEvents +} + +func EnqueueNode(nodeEventObject objects.NodeEventObject) { + for _, queue := range Instance().NodeQueueMap { + queue.Add(nodeEventObject) + } +} + +func AddNodeQueue(key uuid.UUID, queue workqueue.RateLimitingInterface) { + Instance().NodeQueueMap[key] = queue +} + +func RemoveNodeQueue(key uuid.UUID) { + delete(Instance().NodeQueueMap, key) +} + +func SetPod(key string, podIP string, nodeName string, trackingId string) { + _, isNodeIP := Instance().NodeIPMap[podIP] + if isNodeIP { + klog.Infof("IP of pod %s is the same as node's ip. Ignore the pod. Tracking Id: %s", key, trackingId) + return + } + + podMap := Instance().PodMap + pod, exists := podMap[key] + changed := false + if exists { + if pod.IP != podIP || pod.NodeName != nodeName { + changed = true + } else { + klog.Infof("Handling pod completed. Pod %s is unchanged. Tracking Id: %s", key, trackingId) + } + } else { + changed = true + } + + if changed { + resourceVersion := calculateNextPodResourceVersion() + newPod := &objects.PodObject{ + Key: key, + IP: podIP, + NodeName: nodeName, + ResourceVersion: resourceVersion, + } + newPodEvent := &objects.PodEventObject{ + ResourceVersion: resourceVersion, + EventType: constants.EventType_Set, + PodObject: *newPod, + } + podMap[key] = newPod + Instance().PodEventMap[resourceVersion] = newPodEvent + EnqueuePod(*newPodEvent) + + podStr, _ := json.Marshal(podMap[key]) + klog.Infof("Handling pod completed. Pod set as %s. Tracking Id: %s", podStr, trackingId) + } +} + +func DeletePod(key string, trackingId string) { + podMap := Instance().PodMap + pod, exists := podMap[key] + if exists { + resourceVersion := calculateNextPodResourceVersion() + newPodEvent := &objects.PodEventObject{ + ResourceVersion: resourceVersion, + EventType: constants.EventType_Delete, + PodObject: *pod, + } + Instance().PodEventMap[resourceVersion] = newPodEvent + EnqueuePod(*newPodEvent) + delete(podMap, key) + klog.Infof("Handling pod completed. Pod %s is deleted. Tracking Id: %s", key, trackingId) + } +} + +func ListPod(minResourceVersion int) []objects.PodEventObject { + maxResourceVersion := Instance().PodResourceVersion + podEventMap := Instance().PodEventMap + + var podEvents []objects.PodEventObject + for i := minResourceVersion + 1; i <= maxResourceVersion; i++ { + podEvents = append(podEvents, *podEventMap[i]) + } + return podEvents +} + +func EnqueuePod(podEventObject objects.PodEventObject) { + for _, queue := range Instance().PodQueueMap { + queue.Add(podEventObject) + } +} + +func AddPodQueue(key uuid.UUID, queue workqueue.RateLimitingInterface) { + Instance().PodQueueMap[key] = queue +} + +func RemovePodQueue(key uuid.UUID) { + delete(Instance().PodQueueMap, key) +} diff --git a/pkg/grpc/quarkcmsvc.go b/pkg/grpc/quarkcmsvc.go new file mode 100644 index 0000000..d81852d --- /dev/null +++ b/pkg/grpc/quarkcmsvc.go @@ -0,0 +1,236 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package grpc + +import ( + context "context" + "encoding/binary" + "encoding/json" + "flag" + "fmt" + "net" + "os" + + "github.com/google/uuid" + "google.golang.org/grpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog" + + "github.com/CentaurusInfra/quarkcm/pkg/datastore" + "github.com/CentaurusInfra/quarkcm/pkg/objects" +) + +var ( + port = flag.Int("port", 51051, "The server port") +) + +type server struct { + UnimplementedQuarkCMServiceServer +} + +func StartServer() { + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) + if err != nil { + klog.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + RegisterQuarkCMServiceServer(s, &server{}) + klog.Infof("grpc server listening at %v", lis.Addr()) + go s.Serve(lis) +} + +// To quickly test this function, execute: +// grpcurl -plaintext -import-path pkg/grpc/ -proto quarkcmsvc.proto -d '{"client_name": "a client name"}' [::]:51051 quarkcmsvc.QuarkCMService/TestPing +func (s *server) TestPing(ctx context.Context, in *TestRequestMessage) (*TestResponseMessage, error) { + inStr, _ := json.Marshal(in) + klog.Infof("grpc Service called TestPing %s", inStr) + hostname, _ := os.Hostname() + return &TestResponseMessage{ServerName: hostname}, nil +} + +func (s *server) ListNode(ctx context.Context, in *emptypb.Empty) (*NodeListMessage, error) { + klog.Info("grpc Service called ListNode") + + nodeEventObjects := datastore.ListNode(0) + length := len(nodeEventObjects) + nodeMessages := make([]*NodeMessage, 0, length) + for i := 0; i < length; i++ { + nodeEventObject := nodeEventObjects[i] + nodeMessages = append(nodeMessages, &NodeMessage{ + Name: nodeEventObject.NodeObject.Name, + Hostname: nodeEventObject.NodeObject.Hostname, + Ip: convertIP(nodeEventObject.NodeObject.IP), + CreationTimestamp: nodeEventObject.NodeObject.CreationTimestamp, + ResourceVersion: int32(nodeEventObject.ResourceVersion), + EventType: nodeEventObject.EventType, + }) + } + + return &NodeListMessage{Nodes: nodeMessages}, nil +} + +func (s *server) WatchNode(maxResourceVersionMessage *MaxResourceVersionMessage, stream QuarkCMService_WatchNodeServer) error { + klog.Info("grpc Service called WatchNode") + + key := uuid.New() + queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()) + defer queue.ShutDown() + datastore.AddNodeQueue(key, queue) + defer datastore.RemoveNodeQueue(key) + + nodeEventObjects := datastore.ListNode(int(maxResourceVersionMessage.MaxResourceVersion)) + for _, nodeEventObject := range nodeEventObjects { + if err := sendNodeStream(stream, &nodeEventObject); err != nil { + return err + } + } + + for { + exit, err := processNextNode(queue, stream) + if exit { + break + } + if err != nil { + return err + } + } + + return nil +} + +func processNextNode(queue workqueue.RateLimitingInterface, stream QuarkCMService_WatchNodeServer) (bool, error) { + nodeEventObject, exit := dequeueNode(queue) + if exit { + return exit, nil + } + return exit, sendNodeStream(stream, nodeEventObject) +} + +func dequeueNode(queue workqueue.RateLimitingInterface) (*objects.NodeEventObject, bool) { + queueItem, exit := queue.Get() + if exit { + return nil, exit + } + nodeEventObject := queueItem.(objects.NodeEventObject) + queue.Forget(queueItem) + // defer queue.Done(queueItem) + queue.Done(queueItem) + return &nodeEventObject, exit +} + +func sendNodeStream(stream QuarkCMService_WatchNodeServer, nodeEventObject *objects.NodeEventObject) error { + nodeMessage := &NodeMessage{ + Name: nodeEventObject.NodeObject.Name, + Hostname: nodeEventObject.NodeObject.Hostname, + Ip: convertIP(nodeEventObject.NodeObject.IP), + CreationTimestamp: nodeEventObject.NodeObject.CreationTimestamp, + ResourceVersion: int32(nodeEventObject.ResourceVersion), + EventType: nodeEventObject.EventType, + } + if err := stream.Send(nodeMessage); err != nil { + return err + } + return nil +} + +func (s *server) ListPod(ctx context.Context, in *emptypb.Empty) (*PodListMessage, error) { + klog.Info("grpc Service called ListPod") + + podEventObjects := datastore.ListPod(0) + length := len(podEventObjects) + podMessages := make([]*PodMessage, 0, length) + for i := 0; i < length; i++ { + podEventObject := podEventObjects[i] + podMessages = append(podMessages, &PodMessage{ + Key: podEventObject.PodObject.Key, + Ip: convertIP(podEventObject.PodObject.IP), + NodeName: podEventObject.PodObject.NodeName, + ResourceVersion: int32(podEventObject.ResourceVersion), + EventType: podEventObject.EventType, + }) + } + + return &PodListMessage{Pods: podMessages}, nil +} + +func (s *server) WatchPod(maxResourceVersionMessage *MaxResourceVersionMessage, stream QuarkCMService_WatchPodServer) error { + klog.Info("grpc Service called WatchPod") + + key := uuid.New() + queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()) + defer queue.ShutDown() + datastore.AddPodQueue(key, queue) + defer datastore.RemovePodQueue(key) + + podEventObjects := datastore.ListPod(int(maxResourceVersionMessage.MaxResourceVersion)) + for _, podEventObject := range podEventObjects { + if err := sendPodStream(stream, &podEventObject); err != nil { + return err + } + } + + for { + exit, err := processNextPod(queue, stream) + if exit { + break + } + if err != nil { + return err + } + } + + return nil +} + +func processNextPod(queue workqueue.RateLimitingInterface, stream QuarkCMService_WatchPodServer) (bool, error) { + podEventObject, exit := dequeuePod(queue) + if exit { + return exit, nil + } + return exit, sendPodStream(stream, podEventObject) +} + +func dequeuePod(queue workqueue.RateLimitingInterface) (*objects.PodEventObject, bool) { + queueItem, exit := queue.Get() + if exit { + return nil, exit + } + podEventObject := queueItem.(objects.PodEventObject) + queue.Forget(queueItem) + // defer queue.Done(queueItem) + queue.Done(queueItem) + return &podEventObject, exit +} + +func sendPodStream(stream QuarkCMService_WatchPodServer, podEventObject *objects.PodEventObject) error { + podMessage := &PodMessage{ + Key: podEventObject.PodObject.Key, + Ip: convertIP(podEventObject.PodObject.IP), + NodeName: podEventObject.PodObject.NodeName, + ResourceVersion: int32(podEventObject.ResourceVersion), + EventType: podEventObject.EventType, + } + if err := stream.Send(podMessage); err != nil { + return err + } + return nil +} + +func convertIP(ip string) uint32 { + return binary.BigEndian.Uint32(net.ParseIP(ip).To4()) +} diff --git a/pkg/grpc/quarkcmsvc.pb.go b/pkg/grpc/quarkcmsvc.pb.go new file mode 100644 index 0000000..420d4d4 --- /dev/null +++ b/pkg/grpc/quarkcmsvc.pb.go @@ -0,0 +1,669 @@ +// +//Copyright 2022 quarkcm Authors. +// +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.15.8 +// source: pkg/grpc/quarkcmsvc.proto + +package grpc + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type TestRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientName string `protobuf:"bytes,1,opt,name=client_name,json=clientName,proto3" json:"client_name,omitempty"` +} + +func (x *TestRequestMessage) Reset() { + *x = TestRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestRequestMessage) ProtoMessage() {} + +func (x *TestRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestRequestMessage.ProtoReflect.Descriptor instead. +func (*TestRequestMessage) Descriptor() ([]byte, []int) { + return file_pkg_grpc_quarkcmsvc_proto_rawDescGZIP(), []int{0} +} + +func (x *TestRequestMessage) GetClientName() string { + if x != nil { + return x.ClientName + } + return "" +} + +type TestResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServerName string `protobuf:"bytes,1,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"` +} + +func (x *TestResponseMessage) Reset() { + *x = TestResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestResponseMessage) ProtoMessage() {} + +func (x *TestResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestResponseMessage.ProtoReflect.Descriptor instead. +func (*TestResponseMessage) Descriptor() ([]byte, []int) { + return file_pkg_grpc_quarkcmsvc_proto_rawDescGZIP(), []int{1} +} + +func (x *TestResponseMessage) GetServerName() string { + if x != nil { + return x.ServerName + } + return "" +} + +type NodeMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"` + Ip uint32 `protobuf:"varint,3,opt,name=ip,proto3" json:"ip,omitempty"` + CreationTimestamp int64 `protobuf:"varint,4,opt,name=creation_timestamp,json=creationTimestamp,proto3" json:"creation_timestamp,omitempty"` + ResourceVersion int32 `protobuf:"varint,5,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` + EventType string `protobuf:"bytes,6,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"` +} + +func (x *NodeMessage) Reset() { + *x = NodeMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NodeMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeMessage) ProtoMessage() {} + +func (x *NodeMessage) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeMessage.ProtoReflect.Descriptor instead. +func (*NodeMessage) Descriptor() ([]byte, []int) { + return file_pkg_grpc_quarkcmsvc_proto_rawDescGZIP(), []int{2} +} + +func (x *NodeMessage) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NodeMessage) GetHostname() string { + if x != nil { + return x.Hostname + } + return "" +} + +func (x *NodeMessage) GetIp() uint32 { + if x != nil { + return x.Ip + } + return 0 +} + +func (x *NodeMessage) GetCreationTimestamp() int64 { + if x != nil { + return x.CreationTimestamp + } + return 0 +} + +func (x *NodeMessage) GetResourceVersion() int32 { + if x != nil { + return x.ResourceVersion + } + return 0 +} + +func (x *NodeMessage) GetEventType() string { + if x != nil { + return x.EventType + } + return "" +} + +type NodeListMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Nodes []*NodeMessage `protobuf:"bytes,1,rep,name=nodes,proto3" json:"nodes,omitempty"` +} + +func (x *NodeListMessage) Reset() { + *x = NodeListMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NodeListMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeListMessage) ProtoMessage() {} + +func (x *NodeListMessage) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeListMessage.ProtoReflect.Descriptor instead. +func (*NodeListMessage) Descriptor() ([]byte, []int) { + return file_pkg_grpc_quarkcmsvc_proto_rawDescGZIP(), []int{3} +} + +func (x *NodeListMessage) GetNodes() []*NodeMessage { + if x != nil { + return x.Nodes + } + return nil +} + +type PodMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Ip uint32 `protobuf:"varint,2,opt,name=ip,proto3" json:"ip,omitempty"` + NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + ResourceVersion int32 `protobuf:"varint,4,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` + EventType string `protobuf:"bytes,5,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"` +} + +func (x *PodMessage) Reset() { + *x = PodMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PodMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PodMessage) ProtoMessage() {} + +func (x *PodMessage) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PodMessage.ProtoReflect.Descriptor instead. +func (*PodMessage) Descriptor() ([]byte, []int) { + return file_pkg_grpc_quarkcmsvc_proto_rawDescGZIP(), []int{4} +} + +func (x *PodMessage) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *PodMessage) GetIp() uint32 { + if x != nil { + return x.Ip + } + return 0 +} + +func (x *PodMessage) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *PodMessage) GetResourceVersion() int32 { + if x != nil { + return x.ResourceVersion + } + return 0 +} + +func (x *PodMessage) GetEventType() string { + if x != nil { + return x.EventType + } + return "" +} + +type PodListMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pods []*PodMessage `protobuf:"bytes,1,rep,name=pods,proto3" json:"pods,omitempty"` +} + +func (x *PodListMessage) Reset() { + *x = PodListMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PodListMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PodListMessage) ProtoMessage() {} + +func (x *PodListMessage) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PodListMessage.ProtoReflect.Descriptor instead. +func (*PodListMessage) Descriptor() ([]byte, []int) { + return file_pkg_grpc_quarkcmsvc_proto_rawDescGZIP(), []int{5} +} + +func (x *PodListMessage) GetPods() []*PodMessage { + if x != nil { + return x.Pods + } + return nil +} + +type MaxResourceVersionMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MaxResourceVersion int32 `protobuf:"varint,1,opt,name=max_resource_version,json=maxResourceVersion,proto3" json:"max_resource_version,omitempty"` +} + +func (x *MaxResourceVersionMessage) Reset() { + *x = MaxResourceVersionMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MaxResourceVersionMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MaxResourceVersionMessage) ProtoMessage() {} + +func (x *MaxResourceVersionMessage) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_quarkcmsvc_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MaxResourceVersionMessage.ProtoReflect.Descriptor instead. +func (*MaxResourceVersionMessage) Descriptor() ([]byte, []int) { + return file_pkg_grpc_quarkcmsvc_proto_rawDescGZIP(), []int{6} +} + +func (x *MaxResourceVersionMessage) GetMaxResourceVersion() int32 { + if x != nil { + return x.MaxResourceVersion + } + return 0 +} + +var File_pkg_grpc_quarkcmsvc_proto protoreflect.FileDescriptor + +var file_pkg_grpc_quarkcmsvc_proto_rawDesc = []byte{ + 0x0a, 0x19, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x71, 0x75, 0x61, 0x72, 0x6b, + 0x63, 0x6d, 0x73, 0x76, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x71, 0x75, 0x61, + 0x72, 0x6b, 0x63, 0x6d, 0x73, 0x76, 0x63, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x35, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x36, 0x0a, 0x13, 0x54, + 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x22, 0xc6, 0x01, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x02, 0x69, 0x70, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, + 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x40, 0x0a, 0x0f, + 0x4e, 0x6f, 0x64, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x2d, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x71, 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, 0x73, 0x76, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x95, + 0x01, 0x0a, 0x0a, 0x50, 0x6f, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x70, 0x12, + 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3c, 0x0a, 0x0e, 0x50, 0x6f, 0x64, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x04, 0x70, 0x6f, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x71, 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, + 0x73, 0x76, 0x63, 0x2e, 0x50, 0x6f, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x04, + 0x70, 0x6f, 0x64, 0x73, 0x22, 0x4d, 0x0a, 0x19, 0x4d, 0x61, 0x78, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x30, 0x0a, 0x14, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x12, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x32, 0x83, 0x03, 0x0a, 0x0e, 0x51, 0x75, 0x61, 0x72, 0x6b, 0x43, 0x4d, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x50, 0x69, + 0x6e, 0x67, 0x12, 0x1e, 0x2e, 0x71, 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, 0x73, 0x76, 0x63, 0x2e, + 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x1a, 0x1f, 0x2e, 0x71, 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, 0x73, 0x76, 0x63, 0x2e, + 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, + 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x71, 0x75, 0x61, 0x72, + 0x6b, 0x63, 0x6d, 0x73, 0x76, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x09, 0x57, 0x61, 0x74, 0x63, + 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x2e, 0x71, 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, 0x73, + 0x76, 0x63, 0x2e, 0x4d, 0x61, 0x78, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x17, 0x2e, 0x71, + 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, 0x73, 0x76, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x07, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x6f, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x71, + 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, 0x73, 0x76, 0x63, 0x2e, 0x50, 0x6f, 0x64, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x08, 0x57, 0x61, + 0x74, 0x63, 0x68, 0x50, 0x6f, 0x64, 0x12, 0x25, 0x2e, 0x71, 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, + 0x73, 0x76, 0x63, 0x2e, 0x4d, 0x61, 0x78, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x16, 0x2e, + 0x71, 0x75, 0x61, 0x72, 0x6b, 0x63, 0x6d, 0x73, 0x76, 0x63, 0x2e, 0x50, 0x6f, 0x64, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x0a, 0x5a, 0x08, 0x70, 0x6b, 0x67, + 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_pkg_grpc_quarkcmsvc_proto_rawDescOnce sync.Once + file_pkg_grpc_quarkcmsvc_proto_rawDescData = file_pkg_grpc_quarkcmsvc_proto_rawDesc +) + +func file_pkg_grpc_quarkcmsvc_proto_rawDescGZIP() []byte { + file_pkg_grpc_quarkcmsvc_proto_rawDescOnce.Do(func() { + file_pkg_grpc_quarkcmsvc_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_grpc_quarkcmsvc_proto_rawDescData) + }) + return file_pkg_grpc_quarkcmsvc_proto_rawDescData +} + +var file_pkg_grpc_quarkcmsvc_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_pkg_grpc_quarkcmsvc_proto_goTypes = []interface{}{ + (*TestRequestMessage)(nil), // 0: quarkcmsvc.TestRequestMessage + (*TestResponseMessage)(nil), // 1: quarkcmsvc.TestResponseMessage + (*NodeMessage)(nil), // 2: quarkcmsvc.NodeMessage + (*NodeListMessage)(nil), // 3: quarkcmsvc.NodeListMessage + (*PodMessage)(nil), // 4: quarkcmsvc.PodMessage + (*PodListMessage)(nil), // 5: quarkcmsvc.PodListMessage + (*MaxResourceVersionMessage)(nil), // 6: quarkcmsvc.MaxResourceVersionMessage + (*emptypb.Empty)(nil), // 7: google.protobuf.Empty +} +var file_pkg_grpc_quarkcmsvc_proto_depIdxs = []int32{ + 2, // 0: quarkcmsvc.NodeListMessage.nodes:type_name -> quarkcmsvc.NodeMessage + 4, // 1: quarkcmsvc.PodListMessage.pods:type_name -> quarkcmsvc.PodMessage + 0, // 2: quarkcmsvc.QuarkCMService.TestPing:input_type -> quarkcmsvc.TestRequestMessage + 7, // 3: quarkcmsvc.QuarkCMService.ListNode:input_type -> google.protobuf.Empty + 6, // 4: quarkcmsvc.QuarkCMService.WatchNode:input_type -> quarkcmsvc.MaxResourceVersionMessage + 7, // 5: quarkcmsvc.QuarkCMService.ListPod:input_type -> google.protobuf.Empty + 6, // 6: quarkcmsvc.QuarkCMService.WatchPod:input_type -> quarkcmsvc.MaxResourceVersionMessage + 1, // 7: quarkcmsvc.QuarkCMService.TestPing:output_type -> quarkcmsvc.TestResponseMessage + 3, // 8: quarkcmsvc.QuarkCMService.ListNode:output_type -> quarkcmsvc.NodeListMessage + 2, // 9: quarkcmsvc.QuarkCMService.WatchNode:output_type -> quarkcmsvc.NodeMessage + 5, // 10: quarkcmsvc.QuarkCMService.ListPod:output_type -> quarkcmsvc.PodListMessage + 4, // 11: quarkcmsvc.QuarkCMService.WatchPod:output_type -> quarkcmsvc.PodMessage + 7, // [7:12] is the sub-list for method output_type + 2, // [2:7] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_pkg_grpc_quarkcmsvc_proto_init() } +func file_pkg_grpc_quarkcmsvc_proto_init() { + if File_pkg_grpc_quarkcmsvc_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_pkg_grpc_quarkcmsvc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_grpc_quarkcmsvc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_grpc_quarkcmsvc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NodeMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_grpc_quarkcmsvc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NodeListMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_grpc_quarkcmsvc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PodMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_grpc_quarkcmsvc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PodListMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_grpc_quarkcmsvc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MaxResourceVersionMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_pkg_grpc_quarkcmsvc_proto_rawDesc, + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_pkg_grpc_quarkcmsvc_proto_goTypes, + DependencyIndexes: file_pkg_grpc_quarkcmsvc_proto_depIdxs, + MessageInfos: file_pkg_grpc_quarkcmsvc_proto_msgTypes, + }.Build() + File_pkg_grpc_quarkcmsvc_proto = out.File + file_pkg_grpc_quarkcmsvc_proto_rawDesc = nil + file_pkg_grpc_quarkcmsvc_proto_goTypes = nil + file_pkg_grpc_quarkcmsvc_proto_depIdxs = nil +} diff --git a/pkg/grpc/quarkcmsvc.proto b/pkg/grpc/quarkcmsvc.proto new file mode 100644 index 0000000..a4e6353 --- /dev/null +++ b/pkg/grpc/quarkcmsvc.proto @@ -0,0 +1,68 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +syntax = "proto3"; +package quarkcmsvc; +import "google/protobuf/empty.proto"; + +option go_package = "pkg/grpc"; + +service QuarkCMService { + // Test + rpc TestPing (TestRequestMessage) returns (TestResponseMessage) {} + + rpc ListNode (google.protobuf.Empty) returns (NodeListMessage) {} + rpc WatchNode (MaxResourceVersionMessage) returns (stream NodeMessage) {} + rpc ListPod (google.protobuf.Empty) returns (PodListMessage) {} + rpc WatchPod (MaxResourceVersionMessage) returns (stream PodMessage) {} +} + +message TestRequestMessage { + string client_name = 1; +} + +message TestResponseMessage { + string server_name = 1; +} + +message NodeMessage { + string name = 1; + string hostname = 2; + uint32 ip = 3; + int64 creation_timestamp = 4; + int32 resource_version = 5; + string event_type = 6; +} + +message NodeListMessage { + repeated NodeMessage nodes = 1; +} + +message PodMessage { + string key = 1; + uint32 ip = 2; + string node_name = 3; + int32 resource_version = 4; + string event_type = 5; +} + +message PodListMessage { + repeated PodMessage pods = 1; +} + +message MaxResourceVersionMessage { + int32 max_resource_version = 1; +} diff --git a/pkg/grpc/quarkcmsvc_grpc.pb.go b/pkg/grpc/quarkcmsvc_grpc.pb.go new file mode 100644 index 0000000..324d310 --- /dev/null +++ b/pkg/grpc/quarkcmsvc_grpc.pb.go @@ -0,0 +1,307 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.15.8 +// source: pkg/grpc/quarkcmsvc.proto + +package grpc + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// QuarkCMServiceClient is the client API for QuarkCMService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type QuarkCMServiceClient interface { + // Test + TestPing(ctx context.Context, in *TestRequestMessage, opts ...grpc.CallOption) (*TestResponseMessage, error) + ListNode(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*NodeListMessage, error) + WatchNode(ctx context.Context, in *MaxResourceVersionMessage, opts ...grpc.CallOption) (QuarkCMService_WatchNodeClient, error) + ListPod(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*PodListMessage, error) + WatchPod(ctx context.Context, in *MaxResourceVersionMessage, opts ...grpc.CallOption) (QuarkCMService_WatchPodClient, error) +} + +type quarkCMServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewQuarkCMServiceClient(cc grpc.ClientConnInterface) QuarkCMServiceClient { + return &quarkCMServiceClient{cc} +} + +func (c *quarkCMServiceClient) TestPing(ctx context.Context, in *TestRequestMessage, opts ...grpc.CallOption) (*TestResponseMessage, error) { + out := new(TestResponseMessage) + err := c.cc.Invoke(ctx, "/quarkcmsvc.QuarkCMService/TestPing", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *quarkCMServiceClient) ListNode(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*NodeListMessage, error) { + out := new(NodeListMessage) + err := c.cc.Invoke(ctx, "/quarkcmsvc.QuarkCMService/ListNode", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *quarkCMServiceClient) WatchNode(ctx context.Context, in *MaxResourceVersionMessage, opts ...grpc.CallOption) (QuarkCMService_WatchNodeClient, error) { + stream, err := c.cc.NewStream(ctx, &QuarkCMService_ServiceDesc.Streams[0], "/quarkcmsvc.QuarkCMService/WatchNode", opts...) + if err != nil { + return nil, err + } + x := &quarkCMServiceWatchNodeClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type QuarkCMService_WatchNodeClient interface { + Recv() (*NodeMessage, error) + grpc.ClientStream +} + +type quarkCMServiceWatchNodeClient struct { + grpc.ClientStream +} + +func (x *quarkCMServiceWatchNodeClient) Recv() (*NodeMessage, error) { + m := new(NodeMessage) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *quarkCMServiceClient) ListPod(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*PodListMessage, error) { + out := new(PodListMessage) + err := c.cc.Invoke(ctx, "/quarkcmsvc.QuarkCMService/ListPod", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *quarkCMServiceClient) WatchPod(ctx context.Context, in *MaxResourceVersionMessage, opts ...grpc.CallOption) (QuarkCMService_WatchPodClient, error) { + stream, err := c.cc.NewStream(ctx, &QuarkCMService_ServiceDesc.Streams[1], "/quarkcmsvc.QuarkCMService/WatchPod", opts...) + if err != nil { + return nil, err + } + x := &quarkCMServiceWatchPodClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type QuarkCMService_WatchPodClient interface { + Recv() (*PodMessage, error) + grpc.ClientStream +} + +type quarkCMServiceWatchPodClient struct { + grpc.ClientStream +} + +func (x *quarkCMServiceWatchPodClient) Recv() (*PodMessage, error) { + m := new(PodMessage) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// QuarkCMServiceServer is the server API for QuarkCMService service. +// All implementations must embed UnimplementedQuarkCMServiceServer +// for forward compatibility +type QuarkCMServiceServer interface { + // Test + TestPing(context.Context, *TestRequestMessage) (*TestResponseMessage, error) + ListNode(context.Context, *emptypb.Empty) (*NodeListMessage, error) + WatchNode(*MaxResourceVersionMessage, QuarkCMService_WatchNodeServer) error + ListPod(context.Context, *emptypb.Empty) (*PodListMessage, error) + WatchPod(*MaxResourceVersionMessage, QuarkCMService_WatchPodServer) error + mustEmbedUnimplementedQuarkCMServiceServer() +} + +// UnimplementedQuarkCMServiceServer must be embedded to have forward compatible implementations. +type UnimplementedQuarkCMServiceServer struct { +} + +func (UnimplementedQuarkCMServiceServer) TestPing(context.Context, *TestRequestMessage) (*TestResponseMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method TestPing not implemented") +} +func (UnimplementedQuarkCMServiceServer) ListNode(context.Context, *emptypb.Empty) (*NodeListMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListNode not implemented") +} +func (UnimplementedQuarkCMServiceServer) WatchNode(*MaxResourceVersionMessage, QuarkCMService_WatchNodeServer) error { + return status.Errorf(codes.Unimplemented, "method WatchNode not implemented") +} +func (UnimplementedQuarkCMServiceServer) ListPod(context.Context, *emptypb.Empty) (*PodListMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPod not implemented") +} +func (UnimplementedQuarkCMServiceServer) WatchPod(*MaxResourceVersionMessage, QuarkCMService_WatchPodServer) error { + return status.Errorf(codes.Unimplemented, "method WatchPod not implemented") +} +func (UnimplementedQuarkCMServiceServer) mustEmbedUnimplementedQuarkCMServiceServer() {} + +// UnsafeQuarkCMServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to QuarkCMServiceServer will +// result in compilation errors. +type UnsafeQuarkCMServiceServer interface { + mustEmbedUnimplementedQuarkCMServiceServer() +} + +func RegisterQuarkCMServiceServer(s grpc.ServiceRegistrar, srv QuarkCMServiceServer) { + s.RegisterService(&QuarkCMService_ServiceDesc, srv) +} + +func _QuarkCMService_TestPing_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TestRequestMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuarkCMServiceServer).TestPing(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quarkcmsvc.QuarkCMService/TestPing", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuarkCMServiceServer).TestPing(ctx, req.(*TestRequestMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _QuarkCMService_ListNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuarkCMServiceServer).ListNode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quarkcmsvc.QuarkCMService/ListNode", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuarkCMServiceServer).ListNode(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _QuarkCMService_WatchNode_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(MaxResourceVersionMessage) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(QuarkCMServiceServer).WatchNode(m, &quarkCMServiceWatchNodeServer{stream}) +} + +type QuarkCMService_WatchNodeServer interface { + Send(*NodeMessage) error + grpc.ServerStream +} + +type quarkCMServiceWatchNodeServer struct { + grpc.ServerStream +} + +func (x *quarkCMServiceWatchNodeServer) Send(m *NodeMessage) error { + return x.ServerStream.SendMsg(m) +} + +func _QuarkCMService_ListPod_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuarkCMServiceServer).ListPod(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/quarkcmsvc.QuarkCMService/ListPod", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuarkCMServiceServer).ListPod(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _QuarkCMService_WatchPod_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(MaxResourceVersionMessage) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(QuarkCMServiceServer).WatchPod(m, &quarkCMServiceWatchPodServer{stream}) +} + +type QuarkCMService_WatchPodServer interface { + Send(*PodMessage) error + grpc.ServerStream +} + +type quarkCMServiceWatchPodServer struct { + grpc.ServerStream +} + +func (x *quarkCMServiceWatchPodServer) Send(m *PodMessage) error { + return x.ServerStream.SendMsg(m) +} + +// QuarkCMService_ServiceDesc is the grpc.ServiceDesc for QuarkCMService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var QuarkCMService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "quarkcmsvc.QuarkCMService", + HandlerType: (*QuarkCMServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "TestPing", + Handler: _QuarkCMService_TestPing_Handler, + }, + { + MethodName: "ListNode", + Handler: _QuarkCMService_ListNode_Handler, + }, + { + MethodName: "ListPod", + Handler: _QuarkCMService_ListPod_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "WatchNode", + Handler: _QuarkCMService_WatchNode_Handler, + ServerStreams: true, + }, + { + StreamName: "WatchPod", + Handler: _QuarkCMService_WatchPod_Handler, + ServerStreams: true, + }, + }, + Metadata: "pkg/grpc/quarkcmsvc.proto", +} diff --git a/pkg/handlers/handler.go b/pkg/handlers/handler.go new file mode 100644 index 0000000..c54f349 --- /dev/null +++ b/pkg/handlers/handler.go @@ -0,0 +1,23 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handlers + +import "github.com/CentaurusInfra/quarkcm/pkg/objects" + +type Handler interface { + Handle(eventItem objects.EventItem) +} diff --git a/pkg/handlers/nodehandler.go b/pkg/handlers/nodehandler.go new file mode 100644 index 0000000..36eda66 --- /dev/null +++ b/pkg/handlers/nodehandler.go @@ -0,0 +1,50 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handlers + +import ( + "github.com/CentaurusInfra/quarkcm/pkg/constants" + "github.com/CentaurusInfra/quarkcm/pkg/datastore" + "github.com/CentaurusInfra/quarkcm/pkg/objects" + v1 "k8s.io/api/core/v1" + "k8s.io/klog" +) + +type NodeHandler struct { +} + +func (d *NodeHandler) Handle(eventItem objects.EventItem) { + klog.Infof("Handle node event %s:%s. Tracking Id: %s", eventItem.Key, eventItem.EventType, eventItem.Id) + if eventItem.EventType == constants.EventType_Delete { + datastore.DeleteNode(eventItem.Key, eventItem.Id) + } else { + handleNodeSet(eventItem, eventItem.Obj.(*v1.Node)) + } +} + +func handleNodeSet(eventItem objects.EventItem, node *v1.Node) { + var hostname string + var nodeIP string + for _, item := range node.Status.Addresses { + if item.Type == "InternalIP" { + nodeIP = item.Address + } else if item.Type == "Hostname" { + hostname = item.Address + } + } + datastore.SetNode(eventItem.Key, hostname, nodeIP, node.ObjectMeta.CreationTimestamp.Unix(), eventItem.Id) +} diff --git a/pkg/handlers/podhandler.go b/pkg/handlers/podhandler.go new file mode 100644 index 0000000..1532be8 --- /dev/null +++ b/pkg/handlers/podhandler.go @@ -0,0 +1,52 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handlers + +import ( + "fmt" + + "github.com/CentaurusInfra/quarkcm/pkg/constants" + "github.com/CentaurusInfra/quarkcm/pkg/datastore" + "github.com/CentaurusInfra/quarkcm/pkg/objects" + v1 "k8s.io/api/core/v1" + "k8s.io/klog" +) + +type PodHandler struct { +} + +func (d *PodHandler) Init() error { + return nil +} + +func (d *PodHandler) Handle(eventItem objects.EventItem) { + klog.Infof("Handle pod event %s:%s. Tracking Id: %s", eventItem.Key, eventItem.EventType, eventItem.Id) + podKey := fmt.Sprintf("%s/%s", eventItem.Namespace, eventItem.Key) + if eventItem.EventType == constants.EventType_Delete { + datastore.DeletePod(podKey, eventItem.Id) + } else { + handlePodSet(eventItem, podKey, eventItem.Obj.(*v1.Pod)) + } +} + +func handlePodSet(eventItem objects.EventItem, key string, pod *v1.Pod) { + if len(pod.Spec.NodeName) == 0 || len(pod.Status.PodIP) == 0 { + klog.Infof("Handling pod completed. Pod %s is not ready. Tracking Id: %s", eventItem.Key, eventItem.Id) + return + } + datastore.SetPod(key, pod.Status.PodIP, pod.Spec.NodeName, eventItem.Id) +} diff --git a/pkg/objects/eventitem.go b/pkg/objects/eventitem.go new file mode 100644 index 0000000..3579eea --- /dev/null +++ b/pkg/objects/eventitem.go @@ -0,0 +1,25 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package objects + +type EventItem struct { + Id string + Key string + EventType string + Namespace string + Obj interface{} +} diff --git a/pkg/objects/nodeeventobject.go b/pkg/objects/nodeeventobject.go new file mode 100644 index 0000000..a76c7b5 --- /dev/null +++ b/pkg/objects/nodeeventobject.go @@ -0,0 +1,23 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package objects + +type NodeEventObject struct { + ResourceVersion int + EventType string + NodeObject NodeObject +} diff --git a/pkg/objects/nodeobject.go b/pkg/objects/nodeobject.go new file mode 100644 index 0000000..9e58837 --- /dev/null +++ b/pkg/objects/nodeobject.go @@ -0,0 +1,25 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package objects + +type NodeObject struct { + Name string + Hostname string + IP string + CreationTimestamp int64 + ResourceVersion int +} diff --git a/pkg/objects/podeventobject.go b/pkg/objects/podeventobject.go new file mode 100644 index 0000000..83f6714 --- /dev/null +++ b/pkg/objects/podeventobject.go @@ -0,0 +1,23 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package objects + +type PodEventObject struct { + ResourceVersion int + EventType string + PodObject PodObject +} diff --git a/pkg/objects/podobject.go b/pkg/objects/podobject.go new file mode 100644 index 0000000..c69a904 --- /dev/null +++ b/pkg/objects/podobject.go @@ -0,0 +1,24 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package objects + +type PodObject struct { + Key string + IP string + NodeName string + ResourceVersion int +} diff --git a/pkg/utils/k8sutil.go b/pkg/utils/k8sutil.go new file mode 100644 index 0000000..a513b3c --- /dev/null +++ b/pkg/utils/k8sutil.go @@ -0,0 +1,64 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "os" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog" +) + +// GetClient returns a k8s clientset to the request from inside of cluster +func GetClient() kubernetes.Interface { + config, err := rest.InClusterConfig() + if err != nil { + klog.Fatalf("Can not get kubernetes config: %v", err) + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + klog.Fatalf("Can not create kubernetes client: %v", err) + } + + return clientset +} + +func buildOutOfClusterConfig() (*rest.Config, error) { + kubeconfigPath := os.Getenv("KUBECONFIG") + if kubeconfigPath == "" { + kubeconfigPath = os.Getenv("HOME") + "/.kube/config" + } + return clientcmd.BuildConfigFromFlags("", kubeconfigPath) +} + +// GetClientOutOfCluster returns a k8s clientset to the request from outside of cluster +func GetClientOutOfCluster() kubernetes.Interface { + config, err := buildOutOfClusterConfig() + if err != nil { + klog.Fatalf("Can not get kubernetes config: %v", err) + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + klog.Fatalf("Can not get kubernetes config: %v", err) + } + + return clientset +} diff --git a/quarkcmclient/Cargo.lock b/quarkcmclient/Cargo.lock new file mode 100644 index 0000000..0d36659 --- /dev/null +++ b/quarkcmclient/Cargo.lock @@ -0,0 +1,1030 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" + +[[package]] +name = "async-stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47594e438a243791dba58124b6669561f5baa14cb12046641d8008bf035e5a25" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a671c9ae99531afdd5d3ee8340b8da547779430689947144c140fc74a740244" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", +] + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fixedbitset" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6330e8a36bd8c859f3fa6d9382911fbb7147ec39807f63b923933a247240b9ba" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "libc" +version = "0.2.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mio" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "petgraph" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "prettyplease" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b83ec2d0af5c5c556257ff52c9f98934e243b9fd39604bfb2a9b75ec2e97f18" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "prost" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd5316aa8f5c82add416dfbc25116b84b748a21153f512917e8143640a71bbd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328f9f29b82409216decb172d81e936415d21245befa79cd34c3f29d87d1c50b" +dependencies = [ + "bytes", + "cfg-if", + "cmake", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df35198f0777b75e9ff669737c6da5136b59dba33cf5a010a6d1cc4d56defc6f" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926681c118ae6e512a3ccefd4abbe5521a14f4cc1e207356d4d00c0b7f2006fd" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "quarkcmclient" +version = "0.1.0" +dependencies = [ + "hostname", + "lazy_static", + "prost", + "spin 0.9.2", + "tokio", + "tokio-stream", + "tonic", + "tonic-build", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +dependencies = [ + "lock_api", +] + +[[package]] +name = "syn" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "tokio" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30fb54bf1e446f44d870d260d99957e7d11fb9d0a0f5bd1a662ad1411cc103f9" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d17087af5c80e5d5fc8ba9878e60258065a0a757e35efe7a05b7904bece1943" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "quote", + "syn", +] + +[[package]] +name = "tower" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80b9fa4360528139bc96100c160b7ae879f5567f49f1782b0b02035b0358ebf3" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/quarkcmclient/Cargo.toml b/quarkcmclient/Cargo.toml new file mode 100644 index 0000000..fa59a16 --- /dev/null +++ b/quarkcmclient/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "quarkcmclient" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +hostname = "^0.3" +prost = "0.10" +spin = "0.9.2" +tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } +tokio-stream = { version = "0.1", features = ["net"] } +tonic = "0.7" + +[dependencies.lazy_static] +version = "1.4" +features = ["spin_no_std"] + +[build-dependencies] +tonic-build = "0.7" \ No newline at end of file diff --git a/quarkcmclient/build.rs b/quarkcmclient/build.rs new file mode 100644 index 0000000..ab44f90 --- /dev/null +++ b/quarkcmclient/build.rs @@ -0,0 +1,4 @@ +fn main() -> Result<(), Box> { + tonic_build::compile_protos("../pkg/grpc/quarkcmsvc.proto")?; + Ok(()) +} \ No newline at end of file diff --git a/quarkcmclient/src/constants.rs b/quarkcmclient/src/constants.rs new file mode 100644 index 0000000..8727f40 --- /dev/null +++ b/quarkcmclient/src/constants.rs @@ -0,0 +1,26 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// #[derive(Debug)] +// pub struct Constants { +// pub const EVENT_TYPE_SET: string = "set" +// pub const EVENT_TYPE_DELETE: string = "delete" +// } + +pub const EVENT_TYPE_SET: &str = "set"; +pub const EVENT_TYPE_DELETE: &str = "delete"; + +pub const GRPC_SERVER_ADDRESS: &str = "http://[::1]:51051"; \ No newline at end of file diff --git a/quarkcmclient/src/main.rs b/quarkcmclient/src/main.rs new file mode 100644 index 0000000..b5027d9 --- /dev/null +++ b/quarkcmclient/src/main.rs @@ -0,0 +1,48 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +pub mod constants; +pub mod rdma_ctrlconn; + +mod svc_client; +use crate::rdma_ctrlconn::*; +use svc_client::node_informer::NodeInformer; +use svc_client::pod_informer::PodInformer; + +use lazy_static::lazy_static; + +lazy_static! { + pub static ref RDMA_CTLINFO: CtrlInfo = CtrlInfo::default(); +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut pod_informer = PodInformer::new().await?; + let mut node_informer = NodeInformer::new().await?; + + let (pod_informer_result, node_informer_result) = + tokio::join!(pod_informer.run(), node_informer.run(),); + match pod_informer_result { + Err(e) => println!("Pod informer error: {:?}", e), + _ => (), + } + match node_informer_result { + Err(e) => println!("Node informer error: {:?}", e), + _ => (), + } + println!("Exit!"); + Ok(()) +} diff --git a/quarkcmclient/src/rdma_ctrlconn.rs b/quarkcmclient/src/rdma_ctrlconn.rs new file mode 100644 index 0000000..83a3a88 --- /dev/null +++ b/quarkcmclient/src/rdma_ctrlconn.rs @@ -0,0 +1,56 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use spin::Mutex; +use std::collections::HashMap; + +#[derive(Debug)] +pub struct CtrlInfo { + // nodes: node ip --> Node + pub nodes: Mutex>, + + // pods: pod ip --> Pod + pub pods: Mutex>, + + pub exiting: Mutex +} + +impl Default for CtrlInfo { + fn default() -> Self { + return Self { + nodes: Mutex::>::new(HashMap::::new()), + pods: Mutex::>::new(HashMap::::new()), + exiting: Mutex::::new(false), + }; + } +} + +#[derive(Debug)] +pub struct Node { + pub name: String, + pub hostname: String, + pub ip: u32, + pub timestamp: i64, + pub resource_version: i32, +} + +#[derive(Debug)] +pub struct Pod { + pub key: String, + pub ip: u32, + pub node_name: String, + pub resource_version: i32, +} diff --git a/quarkcmclient/src/svc_client/mod.rs b/quarkcmclient/src/svc_client/mod.rs new file mode 100644 index 0000000..bc47bd2 --- /dev/null +++ b/quarkcmclient/src/svc_client/mod.rs @@ -0,0 +1,18 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +pub mod pod_informer; +pub mod node_informer; \ No newline at end of file diff --git a/quarkcmclient/src/svc_client/node_informer.rs b/quarkcmclient/src/svc_client/node_informer.rs new file mode 100644 index 0000000..7866c8d --- /dev/null +++ b/quarkcmclient/src/svc_client/node_informer.rs @@ -0,0 +1,118 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use crate::constants::*; +use crate::rdma_ctrlconn::*; +use crate::RDMA_CTLINFO; +use svc_client::quark_cm_service_client::QuarkCmServiceClient; +use svc_client::MaxResourceVersionMessage; +use svc_client::NodeMessage; +use tokio::time::*; +use tonic::Request; + +pub mod svc_client { + tonic::include_proto!("quarkcmsvc"); +} + +#[derive(Debug)] +pub struct NodeInformer { + pub max_resource_version: i32, +} + +impl NodeInformer { + pub async fn new() -> Result> { + let mut informer = Self { + max_resource_version: 0, + }; + let mut client = QuarkCmServiceClient::connect(GRPC_SERVER_ADDRESS).await?; + + let ref nodes_message = client.list_node(()).await?.into_inner().nodes; + if nodes_message.len() > 0 { + for node_message in nodes_message { + informer.handle(node_message); + } + } + + Ok(informer) + } +} + +impl NodeInformer { + pub async fn run(&mut self) -> Result<(), Box> { + loop { + match self.run_watch().await { + Ok(_) => {} + Err(e) => { + println!("Node watch error: {:?}", e); + } + } + + if *RDMA_CTLINFO.exiting.lock() { + println!("NodeInformer exit!"); + break; + } else { + // println!("NodeInformer sleeps 1 second for next watch session."); + sleep(Duration::from_secs(1)).await; + } + } + Ok(()) + } + + async fn run_watch(&mut self) -> Result<(), Box> { + let mut client = QuarkCmServiceClient::connect(GRPC_SERVER_ADDRESS).await?; + let mut node_stream = client + .watch_node(Request::new(MaxResourceVersionMessage { + max_resource_version: self.max_resource_version, + // max_resource_version: 0, + })) + .await? + .into_inner(); + + while let Some(node_message) = node_stream.message().await? { + self.handle(&node_message); + } + Ok(()) + } + + fn handle(&mut self, node_message: &NodeMessage) { + let ip = node_message.ip; + let mut nodes_map = RDMA_CTLINFO.nodes.lock(); + if node_message.event_type == EVENT_TYPE_SET { + let node = Node { + name: node_message.name.clone(), + hostname: node_message.hostname.clone(), + ip: ip, + timestamp: node_message.creation_timestamp, + resource_version: node_message.resource_version, + }; + nodes_map.insert(ip, node); + if node_message.resource_version > self.max_resource_version { + self.max_resource_version = node_message.resource_version; + } + } else if node_message.event_type == EVENT_TYPE_DELETE { + if nodes_map.contains_key(&ip) { + if nodes_map[&ip].resource_version < node_message.resource_version { + nodes_map.remove(&ip); + } + } + } + if node_message.resource_version > self.max_resource_version { + self.max_resource_version = node_message.resource_version; + } + println!("Handled Node: {:?}", node_message); + println!("Debug: nodes_map len:{} {:?}", nodes_map.len(), nodes_map); + } +} diff --git a/quarkcmclient/src/svc_client/pod_informer.rs b/quarkcmclient/src/svc_client/pod_informer.rs new file mode 100644 index 0000000..7db7dc6 --- /dev/null +++ b/quarkcmclient/src/svc_client/pod_informer.rs @@ -0,0 +1,117 @@ +/* +Copyright 2022 quarkcm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use crate::constants::*; +use crate::rdma_ctrlconn::*; +use crate::RDMA_CTLINFO; +use svc_client::quark_cm_service_client::QuarkCmServiceClient; +use svc_client::MaxResourceVersionMessage; +use svc_client::PodMessage; +use tokio::time::*; +use tonic::Request; + +pub mod svc_client { + tonic::include_proto!("quarkcmsvc"); +} + +#[derive(Debug)] +pub struct PodInformer { + pub max_resource_version: i32, +} + +impl PodInformer { + pub async fn new() -> Result> { + let mut informer = Self { + max_resource_version: 0, + }; + let mut client = QuarkCmServiceClient::connect(GRPC_SERVER_ADDRESS).await?; + + let ref pods_message = client.list_pod(()).await?.into_inner().pods; + if pods_message.len() > 0 { + for pod_message in pods_message { + informer.handle(pod_message); + } + } + + Ok(informer) + } +} + +impl PodInformer { + pub async fn run(&mut self) -> Result<(), Box> { + loop { + match self.run_watch().await { + Ok(_) => {} + Err(e) => { + println!("Pod watch error: {:?}", e); + } + } + + if *RDMA_CTLINFO.exiting.lock() { + println!("PodInformer exit!"); + break; + } else { + // println!("PodInformer sleeps 1 second for next watch session."); + sleep(Duration::from_secs(1)).await; + } + } + Ok(()) + } + + async fn run_watch(&mut self) -> Result<(), Box> { + let mut client = QuarkCmServiceClient::connect(GRPC_SERVER_ADDRESS).await?; + let mut pod_stream = client + .watch_pod(Request::new(MaxResourceVersionMessage { + max_resource_version: self.max_resource_version, + // max_resource_version: 0, + })) + .await? + .into_inner(); + + while let Some(pod_message) = pod_stream.message().await? { + self.handle(&pod_message); + } + Ok(()) + } + + fn handle(&mut self, pod_message: &PodMessage) { + let ip = pod_message.ip; + let mut pods_map = RDMA_CTLINFO.pods.lock(); + if pod_message.event_type == EVENT_TYPE_SET { + let pod = Pod { + key: pod_message.key.clone(), + ip: ip, + node_name: pod_message.node_name.clone(), + resource_version: pod_message.resource_version, + }; + pods_map.insert(ip, pod); + if pod_message.resource_version > self.max_resource_version { + self.max_resource_version = pod_message.resource_version; + } + } else if pod_message.event_type == EVENT_TYPE_DELETE { + if pods_map.contains_key(&ip) { + if pods_map[&ip].resource_version < pod_message.resource_version { + pods_map.remove(&ip); + } + } + } + if pod_message.resource_version > self.max_resource_version { + self.max_resource_version = pod_message.resource_version; + } + println!("Handled Pod: {:?}", pod_message); + println!("Debug: pods_map len:{} {:?}", pods_map.len(), pods_map); + } +}