├── .dockerignore ├── .github └── workflows │ └── hlf-image.yaml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── cmd ├── fileserver │ └── fileserver.go └── launcher │ ├── build.go │ ├── detect.go │ ├── main.go │ ├── platform.go │ ├── release.go │ ├── run.go │ └── utils_test.go ├── go.mod ├── go.sum ├── images └── fabric-peer │ ├── 2.2.0 │ ├── Dockerfile │ └── k8scc.yaml │ ├── 2.2.3 │ ├── Dockerfile │ └── k8scc.yaml │ ├── 2.3.0 │ ├── Dockerfile │ └── k8scc.yaml │ ├── 2.3.2 │ ├── Dockerfile │ └── k8scc.yaml │ ├── 2.4.0 │ ├── Dockerfile │ └── k8scc.yaml │ ├── 2.4.1 │ ├── Dockerfile │ └── k8scc.yaml │ └── 2.4.3 │ ├── Dockerfile │ └── k8scc.yaml └── init.Dockerfile /.dockerignore: -------------------------------------------------------------------------------- 1 | dist-proxy 2 | tmp 3 | .git -------------------------------------------------------------------------------- /.github/workflows/hlf-image.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | docker: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | hlf-version: 14 | - "2.2.0" 15 | - "2.2.3" 16 | - "2.3.0" 17 | - "2.3.2" 18 | - "2.4.0" 19 | - "2.4.1" 20 | - "2.4.3" 21 | steps: 22 | - 23 | name: Checkout code 24 | uses: actions/checkout@v2 25 | - 26 | name: Set up Docker Buildx 27 | uses: docker/setup-buildx-action@v1 28 | - 29 | name: Docker meta 30 | id: meta 31 | uses: docker/metadata-action@v3 32 | with: 33 | # list of Docker images to use as base name for tags 34 | images: | 35 | ghcr.io/kfsoftware/fabric-peer 36 | # generate Docker tags based on the following events/attributes 37 | flavor: 38 | prefix=${{matrix.hlf-version}}-v,onlatest=false 39 | tags: | 40 | type=schedule 41 | type=ref,event=branch 42 | type=ref,event=pr 43 | type=semver,pattern={{version}} 44 | type=semver,pattern={{major}}.{{minor}} 45 | type=semver,pattern={{major}} 46 | type=sha 47 | - 48 | name: Login to GitHub Container Registry 49 | uses: docker/login-action@v1 50 | with: 51 | registry: ghcr.io 52 | username: ${{ github.actor }} 53 | password: ${{ secrets.GITHUB_TOKEN }} 54 | 55 | - 56 | name: Build and push 57 | id: docker_build 58 | uses: docker/build-push-action@v2 59 | with: 60 | file: ./images/fabric-peer/${{matrix.hlf-version}}/Dockerfile 61 | context: . 62 | push: true 63 | tags: ${{ steps.meta.outputs.tags }} 64 | labels: ${{ steps.meta.outputs.labels }} 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | .idea 3 | dist 4 | examples -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.2-alpine3.12 as builder 2 | WORKDIR /workspace 3 | COPY go.mod go.mod 4 | COPY go.sum go.sum 5 | RUN go mod download 6 | COPY cmd/ cmd/ 7 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o fileserver ./cmd/fileserver/fileserver.go 8 | 9 | 10 | FROM alpine:20200917 11 | 12 | COPY --from=builder /workspace/fileserver . 13 | 14 | ENTRYPOINT ["/fileserver"] 15 | 16 | EXPOSE 8080 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright "2018 Aerogear" 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # External builder for Fabric on Kubernetes 2 | 3 | ** **Work based on [hlfabric-k8scc](https://github.com/postfinance/hlfabric-k8scc)** 4 | 5 | ## Introduction 6 | Running Hyperledger Fabric on Kubernetes doesn't allow observability on the chaincodes, which includes, building and executing them. To solve this, we can use external builders and launchers to adapt the way HLF launches the chaincodes. 7 | 8 | To read more about this topic [please visit the official documentation](https://hyperledger-fabric.readthedocs.io/en/release-2.2/cc_launcher.html). 9 | 10 | ## What is different from *hlfabric-k8scc* 11 | This external builder doesn't relay on a `ReadWriteMany` persistent volume claim, rather, it depends on a shared file server where the code and the build output will be stored. 12 | 13 | `ReadWriteMany` is not supported on many cloud providers, and of course not supported by test environments such as [KIND](https://github.com/kubernetes-sigs/kind/issues/1487) 14 | 15 | In order to use it, you can either use one of the public images on [quay.io](https://quay.io/repository/kfsoftware/fabric-peer?tab=tags) or build the image by yourself. 16 | 17 | ## Features 18 | - [x] Build chaincode for Golang 19 | - [x] Build chaincode for NodeJS 20 | - [x] Build chaincode for Java 21 | - [x] Proxy support 22 | 23 | ## Roadmap 24 | - [ ] Cache builds between peers in the same cluster 25 | - [ ] Integration testing 26 | 27 | ## Components 28 | External chaincode builder on Kubernetes needs a http server to store the chaincode inputs to compile them in a Pod, and to store the artifacts of the chaincode built. 29 | 30 | The contents of this server can be found [here](./cmd/fileserver/fileserver.go) 31 | 32 | ## Build 33 | 34 | ### For HLF 2.2.0 35 | ```bash 36 | docker build -t quay.io/kfsoftware/fabric-peer:amd64-2.2.0 -f ./images/fabric-peer/2.2.0/Dockerfile ./ 37 | docker push quay.io/kfsoftware/fabric-peer:amd64-2.2.0 38 | ``` 39 | 40 | ### For HLF 2.3.0 41 | ```bash 42 | docker build -t quay.io/kfsoftware/fabric-peer:amd64-2.3.0 -f ./images/fabric-peer/2.3.0/Dockerfile ./ 43 | docker push quay.io/kfsoftware/fabric-peer:amd64-2.3.0 44 | ``` 45 | 46 | ### File Server 47 | ```bash 48 | docker build -t quay.io/kfsoftware/fabric-fs:amd64-2.2.0 -f ./Dockerfile ./ 49 | docker push quay.io/kfsoftware/fabric-fs:amd64-2.2.0 50 | ``` 51 | 52 | ## Configure 53 | 54 | Inside the **core.yaml** of the peer, under chaincode, there's a property called ``externalBuilders```. 55 | 56 | If using the the image provided by this project, the contents of ```externalBuilders``` are the following: 57 | ```yaml 58 | - name: k8s-builder 59 | path: /builders/golang 60 | propagateEnvironment: 61 | - CHAINCODE_SHARED_DIR 62 | - FILE_SERVER_BASE_IP 63 | - KUBERNETES_SERVICE_HOST 64 | - KUBERNETES_SERVICE_PORT 65 | - K8SCC_CFGFILE 66 | - TMPDIR 67 | - LD_LIBRARY_PATH 68 | - LIBPATH 69 | - PATH 70 | - EXTERNAL_BUILDER_HTTP_PROXY 71 | - EXTERNAL_BUILDER_HTTPS_PROXY 72 | - EXTERNAL_BUILDER_NO_PROXY 73 | - EXTERNAL_BUILDER_PEER_URL 74 | 75 | ``` 76 | 77 | ### Behind a proxy 78 | 79 | You have to build your own image with your own **k8scc.yaml** 80 | ```yaml 81 | 82 | --- 83 | images: 84 | golang: "hyperledger/fabric-ccenv:2.2.0" 85 | java: "hyperledger/fabric-javaenv:2.2.0" 86 | node: "hyperledger/fabric-nodeenv:2.2.0" 87 | 88 | builder: 89 | resources: 90 | memory_limit: "0.5G" 91 | cpu_limit: "0.2" 92 | 93 | env: 94 | - HTTP_PROXY=http://my-enterprise-proxy:1234 95 | - HTTPS_PROXY=http://my-enterprise-proxy:1234 96 | - NO_PROXY=home.com,example.com 97 | 98 | launcher: 99 | resources: 100 | memory_limit: "0.5G" 101 | cpu_limit: "0.2" 102 | 103 | ``` -------------------------------------------------------------------------------- /cmd/fileserver/fileserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | "os" 9 | "path/filepath" 10 | ) 11 | 12 | func main() { 13 | sharedDir := os.Getenv("CHAINCODE_SHARED_DIR") 14 | fs := http.FileServer(http.Dir(sharedDir)) 15 | 16 | http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 17 | log.Printf("Url=%s Method %s", request.URL.Path, request.Method) 18 | if request.Method == "POST" { 19 | serveUpload(sharedDir, writer, request) 20 | } else if request.Method == "GET" { 21 | fs.ServeHTTP(writer, request) 22 | } 23 | }) 24 | httpAddress := os.Getenv("HTTP_ADDRESS") 25 | if httpAddress == "" { 26 | httpAddress = ":8080" 27 | } 28 | log.Printf("Listening on %s", httpAddress) 29 | err := http.ListenAndServe(httpAddress, nil) 30 | if err != nil { 31 | log.Fatalf("Failed to start server") 32 | } 33 | } 34 | 35 | func serveUpload(sharedDir string, w http.ResponseWriter, r *http.Request) { 36 | body, err := ioutil.ReadAll(r.Body) 37 | if err != nil { 38 | fmt.Println(err) 39 | return 40 | } 41 | completePath := fmt.Sprintf("%s%s", sharedDir, r.URL.Path) 42 | log.Printf("File will be uploaded to %s", completePath) 43 | dir := filepath.Dir(r.URL.Path) 44 | err = os.MkdirAll(fmt.Sprintf("%s%s", sharedDir, dir), 0755) 45 | if err != nil { 46 | fmt.Println(err) 47 | return 48 | } 49 | err = ioutil.WriteFile(completePath, body, 0755) 50 | if err != nil { 51 | fmt.Println(err) 52 | return 53 | } 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /cmd/launcher/build.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/tar" 5 | "bytes" 6 | "context" 7 | "encoding/json" 8 | "fmt" 9 | cpy "github.com/otiai10/copy" 10 | "github.com/pkg/errors" 11 | "io" 12 | "io/ioutil" 13 | apiv1 "k8s.io/api/core/v1" 14 | "k8s.io/apimachinery/pkg/api/resource" 15 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 | "log" 17 | "net/http" 18 | "os" 19 | "path/filepath" 20 | "strings" 21 | ) 22 | 23 | // Build builds a chaincode on Kubernetes 24 | func Build(ctx context.Context, cfg Config) error { 25 | log.Println("Procedure: build") 26 | 27 | if len(os.Args) != 4 { 28 | return errors.New("build requires exactly three arguments") 29 | } 30 | 31 | sourceDir := os.Args[1] 32 | metadataDir := os.Args[2] 33 | outputDir := os.Args[3] 34 | log.Printf("Source dir=%s", sourceDir) 35 | log.Printf("Metadata dir=%s", metadataDir) 36 | log.Printf("Output dir=%s", outputDir) 37 | for _, envKey := range os.Environ() { 38 | log.Printf("%s=%s", envKey, os.Getenv(envKey)) 39 | } 40 | buildInfoFile := filepath.Join(outputDir, "k8scc_buildinfo.json") 41 | 42 | // Get metadata 43 | metadata, err := getMetadata(metadataDir) 44 | if err != nil { 45 | return errors.Wrap(err, "getting metadata for chaincode") 46 | } 47 | // /tmp/fabric-fabcar_1-1860815d78bd593aed9728d27eb8bb8c180b7e7e9918057eecb0cf6e4f38223d930256401/src 48 | buildID, err := getBuildID(sourceDir) 49 | if err != nil { 50 | return errors.Wrap(err, "getting buildid for chaincode") 51 | } 52 | var buf bytes.Buffer 53 | err = compress(sourceDir, &buf) 54 | //err = tarDirectory(sourceDir, chaincodeSourceZIP) 55 | if err != nil { 56 | return errors.Wrap(err, "creating the tar") 57 | } 58 | log.Printf("Tar created ") 59 | fileServerURL := getFileServerURL() 60 | basePathURL := fmt.Sprintf("%s/%s", fileServerURL, buildID) 61 | postURL := fmt.Sprintf("%s/chaincode-source.tar", basePathURL) 62 | log.Printf("Post URL=%s", postURL) 63 | resp, err := http.Post( 64 | postURL, 65 | "application/octet-stream", 66 | &buf, 67 | ) 68 | if err != nil { 69 | return err 70 | } 71 | if resp.StatusCode != 200 { 72 | return errors.Errorf("Received %d code from server", resp.StatusCode) 73 | } 74 | log.Printf("File uploaded %d", resp.StatusCode) 75 | // Create builder Pod 76 | pod, err := createBuilderJob(ctx, cfg, metadata, basePathURL) 77 | if err != nil { 78 | return errors.Wrap(err, "creating builder pod") 79 | } 80 | 81 | // Watch builder Pod for completion or failure 82 | podSucceeded, err := watchPodUntilCompletion(ctx, pod) 83 | if err != nil { 84 | return errors.Wrap(err, "watching builder pod") 85 | } 86 | 87 | if !podSucceeded { 88 | return fmt.Errorf("build of Chaincode %s in Pod %s failed", metadata.Label, pod.Name) 89 | } 90 | transferSrcMeta := filepath.Join(sourceDir, "META-INF") 91 | 92 | // Copy META-INF, if available 93 | if _, err := os.Stat(transferSrcMeta); !os.IsNotExist(err) { 94 | err = cpy.Copy(transferSrcMeta, outputDir) 95 | if err != nil { 96 | return errors.Wrap(err, "copy META-INF to output dir") 97 | } 98 | } 99 | 100 | // Create build information 101 | buildInformation := BuildInformation{ 102 | Image: pod.Spec.InitContainers[2].Image, 103 | Platform: metadata.Type, 104 | } 105 | 106 | bi, err := json.Marshal(buildInformation) 107 | if err != nil { 108 | return errors.Wrap(err, "marshaling BuildInformation") 109 | } 110 | log.Printf("Metadata=%s", string(bi)) 111 | 112 | err = ioutil.WriteFile(buildInfoFile, bi, os.ModePerm) 113 | if err != nil { 114 | return errors.Wrap(err, "writing BuildInformation") 115 | } 116 | 117 | err = os.Chmod(buildInfoFile, os.ModePerm) 118 | if err != nil { 119 | return errors.Wrap(err, "changing permissions of BuildInformation") 120 | } 121 | cleanupPodSilent(pod) 122 | return nil 123 | } 124 | 125 | func compress(src string, buf io.Writer) error { 126 | // tar > gzip > buf 127 | tw := tar.NewWriter(buf) 128 | 129 | // walk through every file in the folder 130 | filepath.Walk(src, func(file string, fi os.FileInfo, err error) error { 131 | // generate tar header 132 | header, err := tar.FileInfoHeader(fi, file) 133 | if err != nil { 134 | return err 135 | } 136 | 137 | // must provide real name 138 | // (see https://golang.org/src/archive/tar/common.go?#L626) 139 | relname, err := filepath.Rel(src, file) 140 | if err != nil { 141 | return err 142 | } 143 | if relname == "." { 144 | return nil 145 | } 146 | header.Name = filepath.ToSlash(relname) 147 | 148 | // write header 149 | if err := tw.WriteHeader(header); err != nil { 150 | return err 151 | } 152 | // if not a dir, write file content 153 | if !fi.IsDir() { 154 | data, err := os.Open(file) 155 | if err != nil { 156 | return err 157 | } 158 | if _, err := io.Copy(tw, data); err != nil { 159 | return err 160 | } 161 | } 162 | return nil 163 | }) 164 | 165 | // produce tar 166 | if err := tw.Close(); err != nil { 167 | return err 168 | } 169 | // 170 | return nil 171 | } 172 | 173 | func createBuilderJob(ctx context.Context, cfg Config, metadata *ChaincodeMetadata, basePathURL string) (*apiv1.Pod, error) { 174 | // Setup kubernetes client 175 | clientset, err := getKubernetesClientset() 176 | if err != nil { 177 | return nil, errors.Wrap(err, "getting kubernetes clientset") 178 | } 179 | 180 | // Get builder image 181 | image, ok := cfg.Images[strings.ToLower(metadata.Type)] 182 | if !ok { 183 | return nil, fmt.Errorf("no builder image available for %q", metadata.Type) 184 | } 185 | 186 | initImage := "dviejo/fabric-init:amd64-2.2.0" 187 | 188 | // Get platform informations from hyperledger 189 | plt := GetPlatform(metadata.Type) 190 | if plt == nil { 191 | return nil, fmt.Errorf("platform %q not supported by Hyperledger Fabric", metadata.Type) 192 | } 193 | 194 | buildOpts, err := plt.DockerBuildOptions(metadata.Path) 195 | if err != nil { 196 | return nil, errors.Wrap(err, "getting build options for platform") 197 | } 198 | 199 | envvars := []apiv1.EnvVar{} 200 | for _, env := range buildOpts.Env { 201 | s := strings.SplitN(env, "=", 2) 202 | envvars = append(envvars, apiv1.EnvVar{ 203 | Name: s[0], 204 | Value: s[1], 205 | }) 206 | } 207 | for _, envItem := range cfg.Builder.Env { 208 | envvars = append(envvars, apiv1.EnvVar{ 209 | Name: envItem.Name, 210 | Value: envItem.Value, 211 | }) 212 | } 213 | // Get peer Pod 214 | myself, _ := os.Hostname() 215 | myselfPod, err := clientset.CoreV1().Pods(cfg.Namespace).Get(ctx, myself, metav1.GetOptions{}) 216 | if err != nil { 217 | return nil, errors.Wrap(err, "getting myself Pod") 218 | } 219 | 220 | // Set resources 221 | limits := apiv1.ResourceList{} 222 | if limit := cfg.Builder.Resources.LimitMemory; limit != "" { 223 | limits["memory"] = resource.MustParse(limit) 224 | } 225 | if limit := cfg.Builder.Resources.LimitCPU; limit != "" { 226 | limits["cpu"] = resource.MustParse(limit) 227 | } 228 | requests := apiv1.ResourceList{} 229 | if request := cfg.Builder.Resources.RequestsMemory; request != "" { 230 | requests["memory"] = resource.MustParse(request) 231 | } 232 | if request := cfg.Builder.Resources.RequestsCPU; request != "" { 233 | requests["cpu"] = resource.MustParse(request) 234 | } 235 | mounts := []apiv1.VolumeMount{ 236 | { 237 | Name: "chaincode", 238 | MountPath: "/chaincode", 239 | }, 240 | } 241 | 242 | // Pod 243 | podname := fmt.Sprintf("%s-ccbuild-%s", myself, metadata.MetadataID) 244 | pod := &apiv1.Pod{ 245 | ObjectMeta: metav1.ObjectMeta{ 246 | Name: podname, 247 | OwnerReferences: []metav1.OwnerReference{ 248 | { 249 | APIVersion: "v1", 250 | Kind: "Pod", 251 | Name: myselfPod.Name, 252 | UID: myselfPod.UID, 253 | BlockOwnerDeletion: BoolRef(true), 254 | }, 255 | }, 256 | Labels: map[string]string{ 257 | "externalcc-type": "builder", 258 | }, 259 | }, 260 | Spec: apiv1.PodSpec{ 261 | InitContainers: []apiv1.Container{ 262 | // setup chaincode volume 263 | { 264 | Image: initImage, 265 | Name: "setup-chaincode-volume", 266 | Command: []string{"/bin/bash"}, 267 | Args: []string{ 268 | `-c`, 269 | `mkdir -p /chaincode/input /chaincode/output && chmod 777 /chaincode/input /chaincode/output`, 270 | }, 271 | VolumeMounts: mounts, 272 | }, 273 | // download chaincode source 274 | { 275 | Image: initImage, 276 | Name: "download-chaincode-source", 277 | Command: []string{"/bin/bash"}, 278 | Args: []string{ 279 | "-c", 280 | fmt.Sprintf(`curl -s -o- -L '%s/chaincode-source.tar' | tar -C /chaincode/input -xvf - && chmod -R 777 /chaincode/input`, basePathURL), 281 | }, 282 | VolumeMounts: mounts, 283 | }, 284 | // build container 285 | { 286 | Name: "builder", 287 | Image: image, 288 | ImagePullPolicy: apiv1.PullIfNotPresent, 289 | Command: []string{ 290 | "/bin/sh", 291 | }, 292 | Args: []string{ 293 | "-c", buildOpts.Cmd, 294 | }, 295 | Env: envvars, 296 | Resources: apiv1.ResourceRequirements{Limits: limits, Requests: requests}, 297 | VolumeMounts: mounts, 298 | }, 299 | }, 300 | Containers: []apiv1.Container{ 301 | { 302 | Name: "upload-chaincode-output", 303 | Image: initImage, 304 | ImagePullPolicy: apiv1.PullIfNotPresent, 305 | VolumeMounts: mounts, 306 | Command: []string{"/bin/bash"}, 307 | Args: []string{ 308 | "-c", 309 | //"sleep 600000", 310 | fmt.Sprintf( 311 | ` 312 | cp -r ./chaincode/input/META-INF ./chaincode/output/ || echo "META-INF doesn't exist" && 313 | cd /chaincode/output && 314 | tar cvf /chaincode/output.tar $(ls -A) && 315 | curl -X POST -s --upload-file /chaincode/output.tar '%s/chaincode-output.tar'`, 316 | basePathURL, 317 | ), 318 | }, 319 | }, 320 | }, 321 | EnableServiceLinks: BoolRef(false), 322 | RestartPolicy: apiv1.RestartPolicyNever, 323 | Volumes: []apiv1.Volume{ 324 | { 325 | Name: "chaincode", 326 | }, 327 | }, 328 | }, 329 | } 330 | 331 | return clientset.CoreV1().Pods(cfg.Namespace).Create(ctx, pod, metav1.CreateOptions{}) 332 | } 333 | -------------------------------------------------------------------------------- /cmd/launcher/detect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "os" 8 | "strings" 9 | 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | // Detect detects if the provided chaincode source is buildable on Kubernetes 14 | func Detect(ctx context.Context, cfg Config) error { 15 | log.Println("Procedure: detect") 16 | 17 | if len(os.Args) != 3 { 18 | return errors.New("detect requires exactly two arguments") 19 | } 20 | 21 | // Parse metadata.json 22 | metadataDir := os.Args[2] 23 | metadata, err := getMetadata(metadataDir) 24 | if err != nil { 25 | return errors.Wrap(err, "getting metadata for chaincode") 26 | } 27 | 28 | // Check if there is a valid image configured 29 | _, ok := cfg.Images[strings.ToLower(metadata.Type)] 30 | if !ok { 31 | return fmt.Errorf("no image available for %q", metadata.Type) 32 | // Hyperledger Fabric expects a non zero exit code for not 33 | // detected technologies. main() will ensure a non zero exit code on error 34 | } 35 | 36 | // Check if platform is supported by hyperledger fabric 37 | plt := GetPlatform(metadata.Type) 38 | if plt == nil { 39 | return fmt.Errorf("platform %q not supported by Hyperledger Fabric", metadata.Type) 40 | } 41 | 42 | // Image detected successfully 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /cmd/launcher/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "crypto/sha1" // #nosec G505 7 | "encoding/hex" 8 | "encoding/json" 9 | "fmt" 10 | "io/ioutil" 11 | "log" 12 | "math/rand" 13 | "os" 14 | "os/signal" 15 | "path/filepath" 16 | "strings" 17 | "syscall" 18 | 19 | "gopkg.in/yaml.v2" 20 | 21 | "github.com/pkg/errors" 22 | apiv1 "k8s.io/api/core/v1" 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "k8s.io/client-go/informers" 25 | "k8s.io/client-go/kubernetes" 26 | "k8s.io/client-go/rest" 27 | "k8s.io/client-go/tools/cache" 28 | ) 29 | 30 | const ( 31 | namespaceFile = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" 32 | ) 33 | 34 | // Procedure implements a Hyperledger Fabric externalbuilders command 35 | type Procedure func(ctx context.Context, cfg Config) error 36 | 37 | func main() { 38 | // Select procedure 39 | procedures := map[string]Procedure{ 40 | "detect": Detect, 41 | "build": Build, 42 | "release": Release, 43 | "run": Run, 44 | } 45 | 46 | proc := getProcedureFromArg(procedures) 47 | if proc == nil { 48 | log.Fatalln("Please pass one of the following values as first argument" + 49 | "or set it as the name of the executable: detect, build, release, run") 50 | } 51 | 52 | // Read configuration 53 | cfgFile := os.Getenv("K8SCC_CFGFILE") 54 | if cfgFile == "" { 55 | cfgFile = "k8scc.yaml" 56 | } 57 | 58 | cfgData, err := ioutil.ReadFile(cfgFile) 59 | if err != nil { 60 | log.Fatalf("Loading configuration file %s: %s", cfgFile, err) 61 | } 62 | 63 | cfg := Config{} 64 | err = yaml.Unmarshal(cfgData, &cfg) 65 | if err != nil { 66 | log.Fatalf("Parsing configuration: %s", err) 67 | } 68 | 69 | // Read namespace 70 | namespace, err := ioutil.ReadFile(namespaceFile) 71 | if err != nil { 72 | log.Fatalf("Reading namespace file %s: %s", namespaceFile, err) 73 | } 74 | cfg.Namespace = string(namespace) 75 | 76 | // Handle SIGTERM and SIGINT in order to collect garbage. 77 | // We cancel the request/procedure using a context, so we can cancel it. 78 | // This will trigger a cleanup in the according functions and we will terminate. 79 | sigs := make(chan os.Signal, 1) 80 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 81 | ctx, cancel := context.WithCancel(context.Background()) 82 | go func() { 83 | sig := <-sigs 84 | log.Printf("Received %s, stopping launcher", sig) 85 | cancel() 86 | }() 87 | 88 | // Run procedure 89 | err = proc(ctx, cfg) 90 | if err != nil { 91 | log.Fatalln(err) 92 | } 93 | } 94 | 95 | func getProcedureFromArg(procs map[string]Procedure) Procedure { 96 | for argi := 0; argi < len(os.Args) && argi < 2; argi++ { 97 | function := filepath.Base(os.Args[argi]) 98 | proc, ok := procs[function] 99 | if ok { 100 | return proc 101 | } 102 | } 103 | 104 | return nil 105 | } 106 | 107 | type ResourcesConfig struct { 108 | LimitMemory string `yaml:"memory_limit"` 109 | LimitCPU string `yaml:"cpu_limit"` 110 | RequestsMemory string `yaml:"memory_requests"` 111 | RequestsCPU string `yaml:"cpu_requests"` 112 | } 113 | 114 | // Config defines the configuration for the Kubernetes chaincode builder and launcher 115 | type Config struct { 116 | Images map[string]string `yaml:"images"` // map[technology]image 117 | 118 | Builder struct { 119 | Resources ResourcesConfig `yaml:"resources"` 120 | Env []struct { 121 | Name string `yaml:"name"` 122 | Value string `yaml:"value"` 123 | } `yaml:"env"` 124 | } `yaml:"builder"` 125 | 126 | Launcher struct { 127 | Resources ResourcesConfig `yaml:"resources"` 128 | } `yaml:"launcher"` 129 | 130 | // Internal configurations 131 | Namespace string `yaml:"-"` 132 | } 133 | 134 | // BuildInformation is used to serialize build data for consumption by the launcher 135 | type BuildInformation struct { 136 | Image string 137 | Platform string 138 | } 139 | 140 | // ChaincodeMetadata is based on 141 | // https://github.com/hyperledger/fabric/blob/v2.0.1/core/chaincode/persistence/chaincode_package.go#L226 142 | type ChaincodeMetadata struct { 143 | Type string `json:"type"` // golang, java, node 144 | Path string `json:"path"` 145 | Label string `json:"label"` 146 | MetadataID string 147 | Resources ResourcesConfig `json:"resources"` 148 | } 149 | 150 | // ChaincodeRunConfig is based on 151 | // https://github.com/hyperledger/fabric/blob/v2.1.1/core/container/externalbuilder/externalbuilder.go#L335 152 | type ChaincodeRunConfig struct { 153 | CCID string `json:"chaincode_id"` 154 | PeerAddress string `json:"peer_address"` 155 | ClientCert string `json:"client_cert"` // PEM encoded client certificate 156 | ClientKey string `json:"client_key"` // PEM encoded client key 157 | RootCert string `json:"root_cert"` // PEM encoded peer chaincode certificate 158 | MSPID string `json:"mspid"` 159 | Resources ResourcesConfig `json:"resources"` 160 | 161 | // Custom fields 162 | ShortName string 163 | Image string 164 | Platform string 165 | } 166 | 167 | func streamPodLogs(ctx context.Context, pod *apiv1.Pod) error { 168 | // Setup kubernetes client 169 | clientset, err := getKubernetesClientset() 170 | if err != nil { 171 | return errors.Wrap(err, "getting kubernetes clientset") 172 | } 173 | 174 | req := clientset.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &apiv1.PodLogOptions{Follow: true}) 175 | logs, err := req.Stream(ctx) 176 | if err != nil { 177 | return errors.Wrap(err, "opening log stream") 178 | } 179 | defer logs.Close() 180 | 181 | log.Printf("Start log of pod %s", pod.Name) 182 | 183 | s := bufio.NewScanner(logs) 184 | for s.Scan() { 185 | log.Printf("%s: %s", pod.Name, s.Text()) 186 | } 187 | 188 | if err := s.Err(); err != nil { 189 | log.Println(err) 190 | log.Printf("%s error: %s", pod.Name, err) 191 | } 192 | 193 | log.Printf("End log of pod %s", pod.Name) 194 | 195 | return nil 196 | } 197 | 198 | func cleanupPodSilent(pod *apiv1.Pod) { 199 | err := cleanupPod(pod) 200 | log.Println(err) 201 | } 202 | 203 | func cleanupPod(pod *apiv1.Pod) error { 204 | clientset, err := getKubernetesClientset() 205 | if err != nil { 206 | return errors.Wrap(err, "getting kubernetes clientset") 207 | } 208 | 209 | ctx := context.Background() 210 | err = clientset.CoreV1().Pods(pod.Namespace).Delete(ctx, pod.Name, metav1.DeleteOptions{}) 211 | return err 212 | } 213 | 214 | func watchPodUntilCompletion(ctx context.Context, pod *apiv1.Pod) (bool, error) { 215 | // Setup kubernetes client 216 | clientset, err := getKubernetesClientset() 217 | if err != nil { 218 | return false, errors.Wrap(err, "getting kubernetes clientset") 219 | } 220 | 221 | /* Create log attacher 222 | var attachOnce sync.Once 223 | attachLogs := func() { 224 | go func() { 225 | err := streamPodLogs(pod) 226 | if err != nil { 227 | log.Printf("While streaming pod logs: %q", err) 228 | } 229 | }() 230 | }*/ 231 | 232 | // Create informer 233 | factory := informers.NewSharedInformerFactoryWithOptions(clientset, 0, informers.WithNamespace(pod.Namespace)) 234 | informer := factory.Core().V1().Pods().Informer() 235 | c := make(chan struct{}) 236 | defer close(c) 237 | 238 | podSuccessfull := make(chan bool) 239 | defer close(podSuccessfull) 240 | informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ 241 | UpdateFunc: func(oldPod, newPod interface{}) { 242 | p := newPod.(*apiv1.Pod) 243 | if p.Name == pod.Name { 244 | log.Printf("Received update on pod %s, phase %s", p.Name, p.Status.Phase) 245 | // TODO: Can we miss an update, so not getting logs? 246 | 247 | switch p.Status.Phase { 248 | case apiv1.PodSucceeded: 249 | podSuccessfull <- true 250 | case apiv1.PodFailed, apiv1.PodUnknown: 251 | podSuccessfull <- false 252 | case apiv1.PodPending, apiv1.PodRunning: 253 | // Do nothing as this state is good 254 | default: 255 | podSuccessfull <- false // Unknown phase 256 | } 257 | } 258 | }, 259 | DeleteFunc: func(oldPod interface{}) { 260 | p := oldPod.(*apiv1.Pod) 261 | if p.Name == pod.Name { 262 | log.Printf("Pod %s, phase %s got deleted", p.Name, p.Status.Phase) 263 | podSuccessfull <- false 264 | } 265 | }, 266 | }) 267 | go informer.Run(c) 268 | 269 | // Wait for result of informer and stop it afterwards. 270 | res := <-podSuccessfull 271 | c <- struct{}{} 272 | 273 | // Stream logs 274 | // TODO: This should be done as soon as the pod is running or has an result 275 | err = streamPodLogs(ctx, pod) 276 | if err != nil { 277 | log.Printf("While streaming pod logs: %q", err) 278 | } 279 | 280 | return res, nil 281 | } 282 | 283 | func getMetadata(metadataDir string) (*ChaincodeMetadata, error) { 284 | metadataFile := filepath.Join(metadataDir, "metadata.json") 285 | metadataData, err := ioutil.ReadFile(metadataFile) 286 | if err != nil { 287 | return nil, errors.Wrap(err, "Reading metadata.json") 288 | } 289 | 290 | metadata := ChaincodeMetadata{} 291 | err = json.Unmarshal(metadataData, &metadata) 292 | if err != nil { 293 | return nil, errors.Wrap(err, "Unmarshaling metadata.json") 294 | } 295 | 296 | // Create hash in order to track this CC 297 | h := sha1.New() // #nosec G401 298 | _, err = h.Write(metadataData) 299 | if err != nil { 300 | return nil, errors.Wrap(err, "hashing metadata") 301 | } 302 | 303 | metadata.MetadataID = fmt.Sprintf("%x", h.Sum(nil))[0:8] 304 | 305 | return &metadata, nil 306 | } 307 | 308 | // BoolRef returns the reference to a boolean 309 | func BoolRef(b bool) *bool { 310 | return &b 311 | } 312 | 313 | func getKubernetesClientset() (*kubernetes.Clientset, error) { 314 | // Setup kubernetes client 315 | config, err := rest.InClusterConfig() 316 | if err != nil { 317 | return nil, errors.Wrap(err, "getting kubernetes in-cluster config") 318 | } 319 | 320 | clientset, err := kubernetes.NewForConfig(config) 321 | return clientset, errors.Wrap(err, "creating kubernetes client") 322 | } 323 | 324 | func getBuildID(sourceDir string) (string, error) { 325 | folderName := filepath.Base(filepath.Dir(sourceDir)) 326 | chunks := strings.Split(folderName, "-") 327 | log.Printf("Directory %s", folderName) 328 | lastChunk := chunks[len(chunks)-1] 329 | if len(lastChunk) < 10 { 330 | return lastChunk, nil 331 | } 332 | return lastChunk[:10], nil 333 | } 334 | func getBuildIDForRun(sourceDir string) (string, error) { 335 | folderName := filepath.Base(filepath.Dir(sourceDir)) 336 | chunks := strings.Split(folderName, "-") 337 | log.Printf("Directory %s", folderName) 338 | lastChunk := chunks[len(chunks)-1] 339 | if len(lastChunk) < 10 { 340 | return lastChunk, nil 341 | } 342 | return lastChunk[:10], nil 343 | } 344 | 345 | func TempFileName(prefix, suffix string) string { 346 | randBytes := make([]byte, 16) 347 | rand.Read(randBytes) 348 | return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+suffix) 349 | } 350 | 351 | func getFileServerURL() string { 352 | fileServerIP := os.Getenv("FILE_SERVER_BASE_IP") 353 | fileServerURL := fmt.Sprintf("http://%s:8080", fileServerIP) 354 | log.Printf("File Server URL=%s", fileServerURL) 355 | return fileServerURL 356 | } 357 | -------------------------------------------------------------------------------- /cmd/launcher/platform.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "strings" 6 | 7 | pb "github.com/hyperledger/fabric-protos-go/peer" 8 | "github.com/hyperledger/fabric/core/chaincode/platforms" 9 | "github.com/hyperledger/fabric/core/container/dockercontroller" 10 | ) 11 | 12 | // GetPlatform returns the chaincode platform as defined by HyperLedger Fabric Peer 13 | func GetPlatform(ccType string) platforms.Platform { 14 | for _, plt := range platforms.SupportedPlatforms { 15 | if plt.Name() == strings.ToUpper(ccType) { 16 | return plt 17 | } 18 | } 19 | 20 | return nil 21 | } 22 | 23 | // GetRunArgs returns the chaincode run arguments as defined by HyperLedger Fabric Peer 24 | func GetRunArgs(ccType, peerAddress string) []string { 25 | // platforms are defined as uppercase in protobuf 26 | ccType = strings.ToUpper(ccType) 27 | 28 | dvm := dockercontroller.DockerVM{} 29 | args, err := dvm.GetArgs(ccType, peerAddress) 30 | if err != nil { 31 | log.Printf("dockercontroller.GetArgs returned %q, but we will use a default", err) 32 | return []string{"chaincode", "-peer.address", peerAddress} 33 | } 34 | 35 | return args 36 | } 37 | 38 | // GetMountDir returns the mount directory for the chaincode depending on the platform. 39 | // This is required as DockerVM.GetArgs assumes a platform dependend setup. 40 | func GetCCMountDir(ccType string) string { 41 | // platforms are defined as uppercase in protobuf 42 | ccType = strings.ToUpper(ccType) 43 | 44 | switch ccType { 45 | case pb.ChaincodeSpec_GOLANG.String(): 46 | // https://github.com/hyperledger/fabric/blob/v2.1.1/core/chaincode/platforms/golang/platform.go#L192 47 | return "/usr/local/bin" 48 | case pb.ChaincodeSpec_JAVA.String(): 49 | // https://github.com/hyperledger/fabric/blob/v2.1.1/core/chaincode/platforms/java/platform.go#L125 50 | return "/root/chaincode-java/chaincode" 51 | case pb.ChaincodeSpec_NODE.String(): 52 | // https://github.com/hyperledger/fabric/blob/v2.1.1/core/chaincode/platforms/node/platform.go#L170 53 | return "/usr/local/src" 54 | default: 55 | // Fall back to Go dir 56 | log.Printf("Unknown platform %q for chaincode mount dir, we will use a default", ccType) 57 | return "/usr/local/bin" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /cmd/launcher/release.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | 9 | cpy "github.com/otiai10/copy" 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | // Release copies the META-INF data from the chaincode source to the release directory 14 | // on the peer 15 | func Release(ctx context.Context, cfg Config) error { 16 | log.Println("Procedure: release") 17 | 18 | if len(os.Args) != 3 { 19 | return errors.New("release requires exactly two arguments") 20 | } 21 | 22 | sourceDir := os.Args[1] 23 | outputDir := os.Args[2] 24 | log.Printf("Source dir=%s Output Dir=%s \n", sourceDir, outputDir) 25 | 26 | // Copy statedb from bld dir, if available 27 | statedbSrc := filepath.Join(sourceDir, "statedb") 28 | statedbDest := filepath.Join(outputDir, "statedb") 29 | if _, err := os.Stat(statedbSrc); !os.IsNotExist(err) { 30 | err = cpy.Copy(statedbSrc, statedbDest) 31 | if err != nil { 32 | return errors.Wrap(err, "accessing statedb folder") 33 | } 34 | } 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /cmd/launcher/run.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "log" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | 14 | "github.com/pkg/errors" 15 | apiv1 "k8s.io/api/core/v1" 16 | "k8s.io/apimachinery/pkg/api/resource" 17 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 | ) 19 | 20 | // Run implements the chaincode launcher on Kubernetes whose function is implemented after 21 | // https://github.com/hyperledger/fabric/blob/v2.1.1/integration/externalbuilders/golang/bin/run 22 | func Run(ctx context.Context, cfg Config) error { 23 | log.Println("Procedure: run") 24 | 25 | if len(os.Args) != 3 { 26 | return errors.New("run requires exactly two arguments") 27 | } 28 | 29 | outputDir := os.Args[1] 30 | metadataDir := os.Args[2] 31 | log.Printf("RUN Output dir=%s", outputDir) 32 | log.Printf("RUN Metadata dir=%s", metadataDir) 33 | buildID, err := getBuildIDForRun(outputDir) 34 | if err != nil { 35 | return errors.Wrap(err, fmt.Sprintf("getting build id from output dir=%s", outputDir)) 36 | } 37 | 38 | // Read run configuration 39 | runConfig, err := getChaincodeRunConfig(metadataDir, outputDir) 40 | if err != nil { 41 | return errors.Wrap(err, "getting run config for chaincode") 42 | } 43 | // Create chaincode pod 44 | pod, err := createChaincodePod( 45 | ctx, 46 | cfg, 47 | runConfig, 48 | buildID, 49 | ) 50 | if err != nil { 51 | return errors.Wrap(err, "creating chaincode pod") 52 | } 53 | defer cleanupPodSilent(pod) // Cleanup pod on finish 54 | 55 | // Watch chaincode Pod for completion or failure 56 | podSucceeded, err := watchPodUntilCompletion(ctx, pod) 57 | if err != nil { 58 | return errors.Wrap(err, "watching chaincode pod") 59 | } 60 | 61 | if !podSucceeded { 62 | return fmt.Errorf("chaincode %s in Pod %s failed", runConfig.CCID, pod.Name) 63 | } 64 | 65 | return nil 66 | } 67 | 68 | func getChaincodeRunConfig(metadataDir string, outputDir string) (*ChaincodeRunConfig, error) { 69 | // Read chaincode.json 70 | metadataFile := filepath.Join(metadataDir, "chaincode.json") 71 | metadataData, err := ioutil.ReadFile(metadataFile) 72 | if err != nil { 73 | return nil, errors.Wrap(err, "Reading chaincode.json") 74 | } 75 | 76 | metadata := ChaincodeRunConfig{} 77 | err = json.Unmarshal(metadataData, &metadata) 78 | if err != nil { 79 | return nil, errors.Wrap(err, "Unmarshaling chaincode.json") 80 | } 81 | peerUrl, found := os.LookupEnv("EXTERNAL_BUILDER_PEER_URL") 82 | if found { 83 | metadata.PeerAddress = peerUrl 84 | } 85 | // Create shortname 86 | parts := strings.SplitN(metadata.CCID, ":", 2) 87 | if len(parts) != 2 { 88 | return nil, errors.New("Cannot parse chaincode name") 89 | } 90 | 91 | name := strings.ReplaceAll(parts[0], "_", "-") 92 | hash := parts[1] 93 | if len(hash) < 8 { 94 | return nil, errors.New("Hash of chaincode ID too short") 95 | } 96 | 97 | metadata.ShortName = fmt.Sprintf("%s-%s", name, hash[0:8]) 98 | 99 | // Read BuildInformation 100 | buildInfoFile := filepath.Join(outputDir, "k8scc_buildinfo.json") 101 | buildInfoData, err := ioutil.ReadFile(buildInfoFile) 102 | if err != nil { 103 | return nil, errors.Wrap(err, "Reading k8scc_buildinfo.json") 104 | } 105 | 106 | buildInformation := BuildInformation{} 107 | err = json.Unmarshal(buildInfoData, &buildInformation) 108 | if err != nil { 109 | return nil, errors.Wrap(err, "Unmarshaling k8scc_buildinfo.json") 110 | } 111 | 112 | if buildInformation.Image == "" { 113 | return nil, errors.New("No image found in buildinfo") 114 | } 115 | 116 | metadata.Image = buildInformation.Image 117 | metadata.Platform = buildInformation.Platform 118 | 119 | return &metadata, nil 120 | } 121 | 122 | func createChaincodePod(ctx context.Context, cfg Config, runConfig *ChaincodeRunConfig, buildID string) (*apiv1.Pod, error) { 123 | 124 | // Setup kubernetes client 125 | clientset, err := getKubernetesClientset() 126 | if err != nil { 127 | return nil, errors.Wrap(err, "getting kubernetes clientset") 128 | } 129 | myself, _ := os.Hostname() 130 | podname := fmt.Sprintf("%s-cc-%s", myself, runConfig.ShortName) 131 | existingPod, err := clientset.CoreV1().Pods(cfg.Namespace).Get(ctx, podname, metav1.GetOptions{}) 132 | if err == nil { 133 | log.Printf("Killing previous pod: %s/%s", existingPod.Namespace, existingPod.Name) 134 | err = clientset.CoreV1().Pods(existingPod.Namespace).Delete(ctx, existingPod.Name, metav1.DeleteOptions{}) 135 | if err != nil { 136 | log.Printf("Error killing previous pod %s/%s: %v", existingPod.Namespace, existingPod.Name, err) 137 | return nil, err 138 | } 139 | } 140 | // Get peer Pod 141 | myselfPod, err := clientset.CoreV1().Pods(cfg.Namespace).Get(ctx, myself, metav1.GetOptions{}) 142 | if err != nil { 143 | return nil, errors.Wrap(err, "getting myself Pod") 144 | } 145 | 146 | // Set resources 147 | limits := apiv1.ResourceList{} 148 | if limit := cfg.Launcher.Resources.LimitMemory; limit != "" { 149 | limits["memory"] = resource.MustParse(limit) 150 | } 151 | if limit := cfg.Launcher.Resources.LimitCPU; limit != "" { 152 | limits["cpu"] = resource.MustParse(limit) 153 | } 154 | requests := apiv1.ResourceList{} 155 | if request := cfg.Launcher.Resources.RequestsMemory; request != "" { 156 | requests["memory"] = resource.MustParse(request) 157 | } 158 | if request := cfg.Launcher.Resources.RequestsCPU; request != "" { 159 | requests["cpu"] = resource.MustParse(request) 160 | } 161 | 162 | if limit := runConfig.Resources.LimitMemory; limit != "" { 163 | limits["memory"] = resource.MustParse(limit) 164 | } 165 | if limit := runConfig.Resources.LimitCPU; limit != "" { 166 | limits["cpu"] = resource.MustParse(limit) 167 | } 168 | if request := runConfig.Resources.RequestsMemory; request != "" { 169 | requests["memory"] = resource.MustParse(request) 170 | } 171 | if request := runConfig.Resources.RequestsCPU; request != "" { 172 | requests["cpu"] = resource.MustParse(request) 173 | } 174 | 175 | // Configuration 176 | hasTLS := "true" 177 | if runConfig.ClientCert == "" { 178 | hasTLS = "false" 179 | } 180 | initImage := "dviejo/fabric-init:amd64-2.2.0" 181 | 182 | // file server URL 183 | fileServerURL := getFileServerURL() 184 | basePathURL := fmt.Sprintf("%s/%s", fileServerURL, buildID) 185 | log.Printf("Chaincode base path URL=%s", basePathURL) 186 | chaincodeOutputURL := fmt.Sprintf("%s/chaincode-output.tar", basePathURL) 187 | initVolumeMounts := []apiv1.VolumeMount{ 188 | { 189 | Name: "chaincode", 190 | MountPath: "/chaincode", 191 | }, 192 | } 193 | 194 | // Pod 195 | pod := &apiv1.Pod{ 196 | ObjectMeta: metav1.ObjectMeta{ 197 | Name: podname, 198 | OwnerReferences: []metav1.OwnerReference{ 199 | { 200 | APIVersion: "v1", 201 | Kind: "Pod", 202 | Name: myselfPod.Name, 203 | UID: myselfPod.UID, 204 | BlockOwnerDeletion: BoolRef(true), 205 | }, 206 | }, 207 | Labels: map[string]string{ 208 | "externalcc-type": "launcher", 209 | }, 210 | }, 211 | Spec: apiv1.PodSpec{ 212 | 213 | InitContainers: []apiv1.Container{ 214 | { 215 | Name: "download-chaincode-output", 216 | Image: initImage, 217 | Command: []string{"/bin/bash"}, 218 | Args: []string{ 219 | "-c", 220 | fmt.Sprintf(` 221 | mkdir -p /chaincode/output && chmod -R 777 /chaincode/output && curl -s -o- -L '%s' | tar -C /chaincode/output -xvf - 222 | `, chaincodeOutputURL), 223 | }, 224 | VolumeMounts: initVolumeMounts, 225 | }, 226 | { 227 | Name: "populate-chaincode-artifacts", 228 | Image: initImage, 229 | Command: []string{"/bin/bash"}, 230 | Args: []string{ 231 | `-c`, 232 | fmt.Sprintf(` 233 | mkdir -p /chaincode/artifacts 234 | # rootcert file 235 | head -c -1 < /chaincode/artifacts/root.crt 236 | %[1]s 237 | EOF_1 238 | head -c -1 < /chaincode/artifacts/client_pem.key 239 | %[2]s 240 | EOF_2 241 | head -c -1 < /chaincode/artifacts/client_pem.crt 242 | %[3]s 243 | EOF_3 244 | head -c -1 < /chaincode/artifacts/client.key 245 | %[4]s 246 | EOF_4 247 | head -c -1 < /chaincode/artifacts/client.crt 248 | %[5]s 249 | EOF_5 250 | 251 | `, 252 | runConfig.RootCert, 253 | runConfig.ClientKey, 254 | runConfig.ClientCert, 255 | base64.StdEncoding.EncodeToString([]byte(runConfig.ClientKey)), 256 | base64.StdEncoding.EncodeToString([]byte(runConfig.ClientCert)), 257 | ), 258 | }, 259 | VolumeMounts: initVolumeMounts, 260 | }, 261 | }, 262 | Containers: []apiv1.Container{ 263 | { 264 | Name: "chaincode", 265 | Image: runConfig.Image, 266 | ImagePullPolicy: apiv1.PullIfNotPresent, 267 | Env: []apiv1.EnvVar{ 268 | { 269 | Name: "CORE_CHAINCODE_ID_NAME", 270 | Value: runConfig.CCID, 271 | }, 272 | { 273 | Name: "CORE_CHAINCODE_ID", 274 | Value: runConfig.CCID, 275 | }, 276 | { 277 | Name: "CORE_PEER_LOCALMSPID", 278 | Value: runConfig.MSPID, 279 | }, 280 | { 281 | Name: "CORE_TLS_CLIENT_CERT_PATH", 282 | Value: "/chaincode/artifacts/client.crt", 283 | }, 284 | { 285 | Name: "CORE_TLS_CLIENT_KEY_PATH", 286 | Value: "/chaincode/artifacts/client.key", 287 | }, 288 | { 289 | Name: "CORE_TLS_CLIENT_CERT_FILE", 290 | Value: "/chaincode/artifacts/client_pem.crt", 291 | }, 292 | { 293 | Name: "CORE_TLS_CLIENT_KEY_FILE", 294 | Value: "/chaincode/artifacts/client_pem.key", 295 | }, 296 | { 297 | Name: "CORE_PEER_TLS_ROOTCERT_FILE", 298 | Value: "/chaincode/artifacts/root.crt", 299 | }, 300 | { 301 | Name: "CORE_PEER_TLS_ENABLED", 302 | Value: hasTLS, 303 | }, 304 | }, 305 | WorkingDir: GetCCMountDir(runConfig.Platform), // Set the CWD to the path where the chaincode is 306 | Command: GetRunArgs(runConfig.Platform, runConfig.PeerAddress), 307 | Resources: apiv1.ResourceRequirements{Limits: limits, Requests: requests}, 308 | VolumeMounts: []apiv1.VolumeMount{ 309 | { 310 | Name: "chaincode", 311 | MountPath: "/chaincode/artifacts", 312 | SubPath: "artifacts", 313 | }, 314 | { 315 | Name: "chaincode", 316 | MountPath: GetCCMountDir(runConfig.Platform), 317 | SubPath: "output", 318 | }, 319 | }, 320 | }, 321 | }, 322 | EnableServiceLinks: BoolRef(false), 323 | RestartPolicy: apiv1.RestartPolicyAlways, 324 | Volumes: []apiv1.Volume{ 325 | { 326 | Name: "chaincode", 327 | }, 328 | }, 329 | }, 330 | } 331 | 332 | return clientset.CoreV1().Pods(cfg.Namespace).Create(ctx, pod, metav1.CreateOptions{}) 333 | } 334 | -------------------------------------------------------------------------------- /cmd/launcher/utils_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "github.com/mholt/archiver" 6 | "github.com/stretchr/testify/assert" 7 | "io/ioutil" 8 | "testing" 9 | ) 10 | 11 | func TestFoo(t *testing.T) { 12 | sourceDir := "/disco-grande/go/src/github.com/kfsoftware/externalbuilder/examples" 13 | zipFile := "/disco-grande/go/src/github.com/kfsoftware/externalbuilder/tmp/example.tar" 14 | err := archiver.Archive([]string{sourceDir}, zipFile) 15 | assert.NoError(t, err) 16 | var buf bytes.Buffer 17 | err = compress(sourceDir, &buf) 18 | assert.NoError(t, err) 19 | err = ioutil.WriteFile(zipFile, buf.Bytes(), 0777) 20 | assert.NoError(t, err) 21 | 22 | } 23 | 24 | func TestGetBuildID(t *testing.T) { 25 | folder := "/tmp/fabric-ip-register-cc-ea2aaf81f5d991a883563c349e793ef0a642d577ceebb9a6778832c7fca23882425116466/bld" 26 | buildID, err := getBuildID(folder) 27 | assert.NoError(t, err) 28 | assert.Len(t, buildID, 10) 29 | } 30 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kfsoftware/externalbuilder 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/Knetic/govaluate v3.0.0+incompatible // indirect 7 | github.com/Shopify/sarama v1.27.2 // indirect 8 | github.com/dsnet/compress v0.0.1 // indirect 9 | github.com/frankban/quicktest v1.11.2 // indirect 10 | github.com/fsouza/go-dockerclient v1.6.5 // indirect 11 | github.com/golang/snappy v0.0.2 // indirect 12 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 // indirect 13 | github.com/hashicorp/go-version v1.2.1 // indirect 14 | github.com/hyperledger/fabric v2.1.1+incompatible 15 | github.com/hyperledger/fabric-amcl v0.0.0-20200424173818-327c9e2cf77a // indirect 16 | github.com/hyperledger/fabric-protos-go v0.0.0-20200923192742-3897341ac036 17 | github.com/lithammer/shortuuid/v3 v3.0.4 18 | github.com/mholt/archiver v3.1.1+incompatible 19 | github.com/miekg/pkcs11 v1.0.3 // indirect 20 | github.com/nwaples/rardecode v1.1.0 // indirect 21 | github.com/otiai10/copy v1.2.0 22 | github.com/pkg/errors v0.9.1 23 | github.com/spf13/viper v1.7.1 // indirect 24 | github.com/stretchr/testify v1.6.1 25 | github.com/sykesm/zap-logfmt v0.0.4 // indirect 26 | github.com/ulikunitz/xz v0.5.8 // indirect 27 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect 28 | gopkg.in/yaml.v2 v2.3.0 29 | k8s.io/api v0.18.0 30 | k8s.io/apimachinery v0.18.0 31 | k8s.io/client-go v0.18.0 32 | k8s.io/utils v0.0.0-20200912215256-4140de9c8800 // indirect 33 | ) 34 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= 2 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 4 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 5 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 6 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 9 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 10 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 11 | cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= 12 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 13 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 14 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 15 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= 16 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 17 | github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 18 | github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= 19 | github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= 20 | github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 21 | github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 22 | github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= 23 | github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 24 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 25 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 26 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 27 | github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= 28 | github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 29 | github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= 30 | github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873 h1:93nQ7k53GjoMQ07HVP8g6Zj1fQZDDj7Xy2VkNNtvX8o= 31 | github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= 32 | github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg= 33 | github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= 34 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 35 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 36 | github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 37 | github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 38 | github.com/Shopify/sarama v1.27.2 h1:1EyY1dsxNDUQEv0O/4TsjosHI2CgB1uo9H/v56xzTxc= 39 | github.com/Shopify/sarama v1.27.2/go.mod h1:g5s5osgELxgM+Md9Qni9rzo7Rbt+vvFQI4bt/Mc93II= 40 | github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= 41 | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= 42 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 43 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 44 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 45 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 46 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 47 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 48 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 49 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 50 | github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= 51 | github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 52 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 53 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 54 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 55 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 56 | github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= 57 | github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= 58 | github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= 59 | github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY= 60 | github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= 61 | github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= 62 | github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c h1:8ahmSVELW1wghbjerVAyuEYD5+Dio66RYvSS0iGfL1M= 63 | github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= 64 | github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= 65 | github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= 66 | github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= 67 | github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= 68 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 69 | github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 70 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 71 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 72 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 73 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 74 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 75 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 76 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 77 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 78 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 79 | github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= 80 | github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 81 | github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23 h1:oqgGT9O61YAYvI41EBsLePOr+LE6roB0xY4gpkZuFSE= 82 | github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 83 | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= 84 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 85 | github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= 86 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 87 | github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 88 | github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= 89 | github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= 90 | github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= 91 | github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 92 | github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= 93 | github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= 94 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= 95 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 96 | github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= 97 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= 98 | github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 99 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 100 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 101 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 102 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 103 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 104 | github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 105 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 106 | github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= 107 | github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= 108 | github.com/frankban/quicktest v1.10.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= 109 | github.com/frankban/quicktest v1.11.2 h1:mjwHjStlXWibxOohM7HYieIViKyh56mmt3+6viyhDDI= 110 | github.com/frankban/quicktest v1.11.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= 111 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 112 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 113 | github.com/fsouza/go-dockerclient v1.6.5 h1:vuFDnPcds3LvTWGYb9h0Rty14FLgkjHZdwLDROCdgsw= 114 | github.com/fsouza/go-dockerclient v1.6.5/go.mod h1:GOdftxWLWIbIWKbIMDroKFJzPdg6Iw7r+jX1DDZdVsA= 115 | github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 116 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 117 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 118 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 119 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 120 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 121 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 122 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 123 | github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= 124 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 125 | github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= 126 | github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= 127 | github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= 128 | github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= 129 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 130 | github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= 131 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 132 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 133 | github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= 134 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 135 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 136 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 137 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= 138 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 139 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 140 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 141 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 142 | github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 143 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 144 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 145 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 146 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 147 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 148 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 149 | github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= 150 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 151 | github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= 152 | github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 153 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 154 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 155 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 156 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 157 | github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= 158 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 159 | github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= 160 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 161 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 162 | github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= 163 | github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 164 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 165 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 166 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 167 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 168 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 169 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 170 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 171 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 172 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 173 | github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI= 174 | github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 175 | github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= 176 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 177 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 178 | github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 179 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 180 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 181 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= 182 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 183 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0= 184 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= 185 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 186 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 187 | github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= 188 | github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= 189 | github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 190 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 191 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 192 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 193 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 194 | github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= 195 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 196 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 197 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 198 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 199 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 200 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 201 | github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= 202 | github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 203 | github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= 204 | github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 205 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 206 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 207 | github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= 208 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 209 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 210 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 211 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 212 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= 213 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 214 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= 215 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 216 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 217 | github.com/hyperledger/fabric v2.1.1+incompatible h1:cYYRv3vVg4kA6DmrixLxwn1nwBEUuYda8DsMwlaMKbY= 218 | github.com/hyperledger/fabric v2.1.1+incompatible/go.mod h1:tGFAOCT696D3rG0Vofd2dyWYLySHlh0aQjf7Q1HAju0= 219 | github.com/hyperledger/fabric-amcl v0.0.0-20200424173818-327c9e2cf77a h1:JAKZdGuUIjVmES0X31YUD7UqMR2rz/kxLluJuGvsXPk= 220 | github.com/hyperledger/fabric-amcl v0.0.0-20200424173818-327c9e2cf77a/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= 221 | github.com/hyperledger/fabric-protos-go v0.0.0-20200923192742-3897341ac036 h1:iedaA+oyDySW7mbIAkKDlpfd50HP0FdGMW312Rkz1C4= 222 | github.com/hyperledger/fabric-protos-go v0.0.0-20200923192742-3897341ac036/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 223 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 224 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 225 | github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= 226 | github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= 227 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 228 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 229 | github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= 230 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 231 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 232 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 233 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 234 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 235 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 236 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 237 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 238 | github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 239 | github.com/klauspost/compress v1.11.0 h1:wJbzvpYMVGG9iTI9VxpnNZfd4DzMPoCWze3GgSqz8yg= 240 | github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 241 | github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 242 | github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 243 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 244 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 245 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 246 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 247 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 248 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 249 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 250 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 251 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 252 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 253 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 254 | github.com/lithammer/shortuuid/v3 v3.0.4 h1:uj4xhotfY92Y1Oa6n6HUiFn87CdoEHYUlTy0+IgbLrs= 255 | github.com/lithammer/shortuuid/v3 v3.0.4/go.mod h1:RviRjexKqIzx/7r1peoAITm6m7gnif/h+0zmolKJjzw= 256 | github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= 257 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 258 | github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 259 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 260 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 261 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 262 | github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= 263 | github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= 264 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 265 | github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= 266 | github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= 267 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 268 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 269 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 270 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= 271 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= 272 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 273 | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= 274 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 275 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 276 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 277 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 278 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 279 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 280 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 281 | github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= 282 | github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 283 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 284 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 285 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 286 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 287 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 288 | github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= 289 | github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= 290 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 291 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 292 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 293 | github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 294 | github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= 295 | github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 296 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 297 | github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= 298 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 299 | github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 300 | github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= 301 | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 302 | github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= 303 | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 304 | github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= 305 | github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= 306 | github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= 307 | github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= 308 | github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= 309 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 310 | github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= 311 | github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= 312 | github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= 313 | github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI= 314 | github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= 315 | github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= 316 | github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc= 317 | github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= 318 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 319 | github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= 320 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 321 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 322 | github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= 323 | github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 324 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 325 | github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 326 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 327 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 328 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 329 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 330 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 331 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 332 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 333 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 334 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 335 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 336 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 337 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 338 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 339 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 340 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 341 | github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= 342 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 343 | github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= 344 | github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 345 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 346 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 347 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 348 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 349 | github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= 350 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 351 | github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= 352 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 353 | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 354 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 355 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 356 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 357 | github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 358 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 359 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 360 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 361 | github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= 362 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 363 | github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= 364 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 365 | github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= 366 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 367 | github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 368 | github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= 369 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 370 | github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 371 | github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 372 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 373 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 374 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 375 | github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= 376 | github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 377 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 378 | github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= 379 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 380 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 381 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 382 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 383 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 384 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 385 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 386 | github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= 387 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 388 | github.com/sykesm/zap-logfmt v0.0.4 h1:U2WzRvmIWG1wDLCFY3sz8UeEmsdHQjHFNlIdmroVFaI= 389 | github.com/sykesm/zap-logfmt v0.0.4/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA= 390 | github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= 391 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 392 | github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= 393 | github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= 394 | github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 395 | github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 396 | github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= 397 | github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= 398 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= 399 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= 400 | github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= 401 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= 402 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 403 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 404 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 405 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 406 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 407 | go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= 408 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 409 | go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= 410 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 411 | go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= 412 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 413 | go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= 414 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 415 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= 416 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 417 | go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= 418 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 419 | go.uber.org/zap v1.12.0 h1:dySoUQPFBGj6xwjmBzageVL8jGi8uxc6bEmJQjA06bw= 420 | go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 421 | golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 422 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 423 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 424 | golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 425 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 426 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 427 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 428 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 429 | golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= 430 | golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 431 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 432 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 433 | golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= 434 | golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 435 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 436 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 437 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 438 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 439 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 440 | golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= 441 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 442 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 443 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 444 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 445 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 446 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 447 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 448 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 449 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= 450 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 451 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 452 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 453 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 454 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 455 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 456 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b h1:GgiSbuUyC0BlbUmHQBgFqu32eiRR/CEYdjOjOd4zE6Y= 457 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 458 | golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 459 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 460 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 461 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 462 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 463 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 464 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 465 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 466 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 467 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 468 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 469 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 470 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 471 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 472 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 473 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 474 | golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= 475 | golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 476 | golang.org/x/net v0.0.0-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI= 477 | golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 478 | golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= 479 | golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 480 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 481 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 482 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= 483 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 484 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 485 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 486 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 487 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 488 | golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= 489 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 490 | golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 491 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 492 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 493 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 494 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 495 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 496 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 497 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 498 | golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 499 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 500 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 501 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 502 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 503 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 504 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 505 | golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 506 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 507 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 508 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 509 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 510 | golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU= 511 | golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 512 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 513 | golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= 514 | golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 515 | golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 516 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 517 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 518 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 519 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 520 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 521 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 522 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 523 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= 524 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 525 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 526 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 527 | golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 528 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 529 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 530 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 531 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 532 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 533 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 534 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 535 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 536 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 537 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 538 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 539 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 540 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 541 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 542 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 543 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 544 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 545 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 546 | golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 547 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa h1:5E4dL8+NgFOgjwbTKz+OOEGGhP+ectTmF842l6KjupQ= 548 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 549 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 550 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 551 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 552 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 553 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 554 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 555 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 556 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 557 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 558 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 559 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 560 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 561 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 562 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 563 | google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= 564 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 565 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 566 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 567 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 568 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 569 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 570 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 571 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= 572 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 573 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 574 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 575 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215 h1:0Uz5jLJQioKgVozXa1gzGbzYxbb/rhQEVvSWxzw5oUs= 576 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 577 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 578 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 579 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 580 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 581 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 582 | google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= 583 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 584 | google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= 585 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 586 | google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= 587 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 588 | gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 589 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 590 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 591 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 592 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 593 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= 594 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 595 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 596 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= 597 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 598 | gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= 599 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 600 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 601 | gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= 602 | gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 603 | gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= 604 | gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= 605 | gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= 606 | gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= 607 | gopkg.in/jcmturner/goidentity.v3 v3.0.0 h1:1duIyWiTaYvVx3YX2CYtpJbUFd7/UuPYCfgXtQ3VTbI= 608 | gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= 609 | gopkg.in/jcmturner/gokrb5.v7 v7.5.0 h1:a9tsXlIDD9SKxotJMK3niV7rPZAJeX2aD/0yg3qlIrg= 610 | gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= 611 | gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU= 612 | gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= 613 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 614 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 615 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 616 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 617 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 618 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 619 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 620 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 621 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 622 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 623 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 624 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= 625 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 626 | gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= 627 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 628 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 629 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 630 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 631 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 632 | honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= 633 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 634 | k8s.io/api v0.18.0 h1:lwYk8Vt7rsVTwjRU6pzEsa9YNhThbmbocQlKvNBB4EQ= 635 | k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= 636 | k8s.io/apimachinery v0.18.0 h1:fuPfYpk3cs1Okp/515pAf0dNhL66+8zk8RLbSX+EgAE= 637 | k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= 638 | k8s.io/client-go v0.18.0 h1:yqKw4cTUQraZK3fcVCMeSa+lqKwcjZ5wtcOIPnxQno4= 639 | k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= 640 | k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 641 | k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 642 | k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 643 | k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= 644 | k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= 645 | k8s.io/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok= 646 | k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= 647 | k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= 648 | k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= 649 | k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 650 | k8s.io/utils v0.0.0-20200912215256-4140de9c8800 h1:9ZNvfPvVIEsp/T1ez4GQuzCcCTEQWhovSofhqR73A6g= 651 | k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= 652 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 653 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= 654 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= 655 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= 656 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 657 | sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= 658 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= 659 | -------------------------------------------------------------------------------- /images/fabric-peer/2.2.0/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.2-alpine3.12 as builder 2 | WORKDIR /workspace 3 | COPY go.mod go.mod 4 | COPY go.sum go.sum 5 | RUN go mod download 6 | COPY cmd/ cmd/ 7 | RUN CGO_ENABLED=0 go build -o launcher ./cmd/launcher 8 | 9 | FROM hyperledger/fabric-peer:amd64-2.2.0 10 | RUN mkdir -p /builders/golang/bin 11 | 12 | COPY --from=builder /workspace/launcher /builders/golang/bin/externalcc 13 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/detect 14 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/build 15 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/release 16 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/run 17 | 18 | COPY images/fabric-peer/2.2.0/k8scc.yaml /builders/golang/bin/k8scc.yaml 19 | -------------------------------------------------------------------------------- /images/fabric-peer/2.2.0/k8scc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | images: 3 | golang: "hyperledger/fabric-ccenv:2.2.0" 4 | java: "hyperledger/fabric-javaenv:2.2.0" 5 | node: "hyperledger/fabric-nodeenv:2.2.0" 6 | 7 | builder: 8 | resources: 9 | memory_limit: "0.5G" 10 | cpu_limit: "0.2" 11 | env: [ ] 12 | launcher: 13 | resources: 14 | memory_limit: "0.5G" 15 | cpu_limit: "0.2" 16 | -------------------------------------------------------------------------------- /images/fabric-peer/2.2.3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.2-alpine3.12 as builder 2 | WORKDIR /workspace 3 | COPY go.mod go.mod 4 | COPY go.sum go.sum 5 | RUN go mod download 6 | COPY cmd/ cmd/ 7 | RUN CGO_ENABLED=0 go build -o launcher ./cmd/launcher 8 | 9 | FROM hyperledger/fabric-peer:amd64-2.2.3 10 | RUN mkdir -p /builders/golang/bin 11 | 12 | COPY --from=builder /workspace/launcher /builders/golang/bin/externalcc 13 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/detect 14 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/build 15 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/release 16 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/run 17 | 18 | COPY images/fabric-peer/2.2.3/k8scc.yaml /builders/golang/bin/k8scc.yaml 19 | -------------------------------------------------------------------------------- /images/fabric-peer/2.2.3/k8scc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | images: 3 | golang: "hyperledger/fabric-ccenv:2.2.3" 4 | java: "hyperledger/fabric-javaenv:2.2.3" 5 | node: "hyperledger/fabric-nodeenv:2.2.3" 6 | 7 | builder: 8 | resources: 9 | memory_limit: "0.5G" 10 | cpu_limit: "0.2" 11 | env: [ ] 12 | launcher: 13 | resources: 14 | memory_limit: "0.5G" 15 | cpu_limit: "0.2" 16 | -------------------------------------------------------------------------------- /images/fabric-peer/2.3.0/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.2-alpine3.12 as builder 2 | WORKDIR /workspace 3 | COPY go.mod go.mod 4 | COPY go.sum go.sum 5 | RUN go mod download 6 | COPY cmd/ cmd/ 7 | RUN CGO_ENABLED=0 go build -o launcher ./cmd/launcher 8 | 9 | 10 | FROM hyperledger/fabric-peer:amd64-2.3.0 11 | RUN mkdir -p /builders/golang/bin 12 | 13 | COPY --from=builder /workspace/launcher /builders/golang/bin/externalcc 14 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/detect 15 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/build 16 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/release 17 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/run 18 | 19 | COPY images/fabric-peer/2.3.0/k8scc.yaml /builders/golang/bin/k8scc.yaml 20 | -------------------------------------------------------------------------------- /images/fabric-peer/2.3.0/k8scc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | images: 3 | golang: "hyperledger/fabric-ccenv:2.3.0" 4 | java: "hyperledger/fabric-javaenv:2.3.0" 5 | node: "hyperledger/fabric-nodeenv:2.3.0" 6 | 7 | builder: 8 | resources: 9 | memory_limit: "0.5G" 10 | cpu_limit: "0.2" 11 | env: [] 12 | launcher: 13 | resources: 14 | memory_limit: "0.5G" 15 | cpu_limit: "0.2" 16 | -------------------------------------------------------------------------------- /images/fabric-peer/2.3.2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.2-alpine3.12 as builder 2 | WORKDIR /workspace 3 | COPY go.mod go.mod 4 | COPY go.sum go.sum 5 | RUN go mod download 6 | COPY cmd/ cmd/ 7 | RUN CGO_ENABLED=0 go build -o launcher ./cmd/launcher 8 | 9 | 10 | FROM hyperledger/fabric-peer:amd64-2.3.2 11 | RUN mkdir -p /builders/golang/bin 12 | 13 | COPY --from=builder /workspace/launcher /builders/golang/bin/externalcc 14 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/detect 15 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/build 16 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/release 17 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/run 18 | 19 | COPY images/fabric-peer/2.3.2/k8scc.yaml /builders/golang/bin/k8scc.yaml 20 | -------------------------------------------------------------------------------- /images/fabric-peer/2.3.2/k8scc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | images: 3 | golang: "hyperledger/fabric-ccenv:2.3.2" 4 | java: "hyperledger/fabric-javaenv:2.3.2" 5 | node: "hyperledger/fabric-nodeenv:2.3.2" 6 | 7 | builder: 8 | resources: 9 | memory_limit: "0.5G" 10 | cpu_limit: "0.2" 11 | env: [] 12 | launcher: 13 | resources: 14 | memory_limit: "0.5G" 15 | cpu_limit: "0.2" 16 | -------------------------------------------------------------------------------- /images/fabric-peer/2.4.0/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.2-alpine3.12 as builder 2 | WORKDIR /workspace 3 | COPY go.mod go.mod 4 | COPY go.sum go.sum 5 | RUN go mod download 6 | COPY cmd/ cmd/ 7 | RUN CGO_ENABLED=0 go build -o launcher ./cmd/launcher 8 | 9 | 10 | FROM hyperledger/fabric-peer:amd64-2.4.0 11 | RUN mkdir -p /builders/golang/bin 12 | 13 | COPY --from=builder /workspace/launcher /builders/golang/bin/externalcc 14 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/detect 15 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/build 16 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/release 17 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/run 18 | 19 | COPY images/fabric-peer/2.4.0/k8scc.yaml /builders/golang/bin/k8scc.yaml 20 | -------------------------------------------------------------------------------- /images/fabric-peer/2.4.0/k8scc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | images: 3 | golang: "hyperledger/fabric-ccenv:2.4.0" 4 | java: "hyperledger/fabric-javaenv:2.4.0" 5 | node: "hyperledger/fabric-nodeenv:2.4.0" 6 | 7 | builder: 8 | resources: 9 | memory_limit: "0.5G" 10 | cpu_limit: "0.2" 11 | env: [] 12 | launcher: 13 | resources: 14 | memory_limit: "0.5G" 15 | cpu_limit: "0.2" 16 | -------------------------------------------------------------------------------- /images/fabric-peer/2.4.1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.2-alpine3.12 as builder 2 | WORKDIR /workspace 3 | COPY go.mod go.mod 4 | COPY go.sum go.sum 5 | RUN go mod download 6 | COPY cmd/ cmd/ 7 | RUN CGO_ENABLED=0 go build -o launcher ./cmd/launcher 8 | 9 | 10 | FROM hyperledger/fabric-peer:amd64-2.4.1 11 | RUN mkdir -p /builders/golang/bin 12 | 13 | COPY --from=builder /workspace/launcher /builders/golang/bin/externalcc 14 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/detect 15 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/build 16 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/release 17 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/run 18 | 19 | COPY images/fabric-peer/2.4.1/k8scc.yaml /builders/golang/bin/k8scc.yaml 20 | -------------------------------------------------------------------------------- /images/fabric-peer/2.4.1/k8scc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | images: 3 | golang: "hyperledger/fabric-ccenv:2.4.1" 4 | java: "hyperledger/fabric-javaenv:2.4.1" 5 | node: "hyperledger/fabric-nodeenv:2.4.1" 6 | 7 | builder: 8 | resources: 9 | memory_limit: "0.5G" 10 | cpu_limit: "0.2" 11 | env: [] 12 | launcher: 13 | resources: 14 | memory_limit: "0.5G" 15 | cpu_limit: "0.2" 16 | -------------------------------------------------------------------------------- /images/fabric-peer/2.4.3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15.2-alpine3.12 as builder 2 | WORKDIR /workspace 3 | COPY go.mod go.mod 4 | COPY go.sum go.sum 5 | RUN go mod download 6 | COPY cmd/ cmd/ 7 | RUN CGO_ENABLED=0 go build -o launcher ./cmd/launcher 8 | 9 | 10 | FROM hyperledger/fabric-peer:amd64-2.4.3 11 | RUN mkdir -p /builders/golang/bin 12 | 13 | COPY --from=builder /workspace/launcher /builders/golang/bin/externalcc 14 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/detect 15 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/build 16 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/release 17 | RUN ln -s /builders/golang/bin/externalcc /builders/golang/bin/run 18 | 19 | COPY images/fabric-peer/2.4.3/k8scc.yaml /builders/golang/bin/k8scc.yaml 20 | -------------------------------------------------------------------------------- /images/fabric-peer/2.4.3/k8scc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | images: 3 | golang: "hyperledger/fabric-ccenv:2.4.1" 4 | java: "hyperledger/fabric-javaenv:2.4.1" 5 | node: "hyperledger/fabric-nodeenv:2.4.1" 6 | 7 | builder: 8 | resources: 9 | memory_limit: "0.5G" 10 | cpu_limit: "0.2" 11 | env: [] 12 | launcher: 13 | resources: 14 | memory_limit: "0.5G" 15 | cpu_limit: "0.2" 16 | -------------------------------------------------------------------------------- /init.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | RUN apt-get update && apt-get install zip curl --yes --------------------------------------------------------------------------------