├── defaults ├── ari.d │ ├── keep.conf │ └── k8s-asterisk-config.conf.tmpl ├── cli.d │ └── keep.conf ├── cli_custom.conf ├── manager.d │ └── keep.conf ├── pjsip.d │ ├── keep.conf │ └── k8s-asterisk-config.conf.tmpl ├── pjsip_custom.conf ├── extensions.d │ └── keep.conf ├── extensions_custom.conf ├── voicemail.d │ └── keep.conf ├── pjsip.conf ├── manager.conf ├── extensions.conf ├── ari_custom.conf ├── musiconhold.conf ├── voicemail.conf ├── voicemail_custom.conf ├── logger.conf ├── ari.conf ├── manager_custom.conf ├── confbridge.conf ├── cli.conf ├── http.conf ├── cdr.conf ├── asterisk.conf ├── cdr_custom.conf ├── indications.conf └── modules.conf ├── .gitignore ├── Dockerfile.goreleaser ├── check.sh ├── random.go ├── Dockerfile ├── release.sh ├── .github └── workflows │ ├── go.yml │ ├── release.yaml │ └── master.yaml ├── LICENSE ├── go.mod ├── CODE_OF_CONDUCT.md ├── .goreleaser.yml ├── Documentation ├── pjsip-ext-ext.svg ├── pjsip-int-ext.svg └── pjsip-int-int.svg ├── main.go ├── README.md └── go.sum /defaults/ari.d/keep.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /defaults/cli.d/keep.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /defaults/cli_custom.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /defaults/manager.d/keep.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /defaults/pjsip.d/keep.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /defaults/pjsip_custom.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /defaults/extensions.d/keep.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /defaults/extensions_custom.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /defaults/voicemail.d/keep.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /asterisk-config 2 | /vendor/ 3 | /test/ 4 | /local_test.sh 5 | -------------------------------------------------------------------------------- /defaults/pjsip.conf: -------------------------------------------------------------------------------- 1 | #include pjsip_custom.conf 2 | #include pjsip.d/*.conf 3 | -------------------------------------------------------------------------------- /defaults/manager.conf: -------------------------------------------------------------------------------- 1 | #include manager_custom.conf 2 | #include manager.d/*.conf 3 | -------------------------------------------------------------------------------- /defaults/extensions.conf: -------------------------------------------------------------------------------- 1 | #include extensions_custom.conf 2 | #include extensions.d/*.conf 3 | -------------------------------------------------------------------------------- /defaults/ari_custom.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | enabled = yes 3 | pretty = yes 4 | allowed_origins = * 5 | -------------------------------------------------------------------------------- /defaults/musiconhold.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | 3 | [default] 4 | mode = files 5 | directory = moh 6 | -------------------------------------------------------------------------------- /defaults/voicemail.conf: -------------------------------------------------------------------------------- 1 | #include voicemail_custom.conf 2 | #include voicemail.d/*.conf 3 | 4 | -------------------------------------------------------------------------------- /defaults/voicemail_custom.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | format = wav49|gsm|wav 3 | 4 | [default] 5 | 6 | -------------------------------------------------------------------------------- /defaults/logger.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | 3 | [logfiles] 4 | 5 | console = verbose,notice,warning,error 6 | 7 | -------------------------------------------------------------------------------- /defaults/ari.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | enabled = yes 3 | 4 | #include ari_custom.conf 5 | #include ari.d/*.conf 6 | -------------------------------------------------------------------------------- /defaults/manager_custom.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | enabled = yes 3 | port = 5038 4 | bindaddr = 127.0.0.1 5 | webenabled = no 6 | 7 | -------------------------------------------------------------------------------- /defaults/confbridge.conf: -------------------------------------------------------------------------------- 1 | ; All conferences use default settings. This config must be present to load the confbridge application 2 | -------------------------------------------------------------------------------- /defaults/ari.d/k8s-asterisk-config.conf.tmpl: -------------------------------------------------------------------------------- 1 | [k8s-asterisk-config] 2 | type = user 3 | password = {{.Env "ARI_AUTOSECRET"}} 4 | password_format = plain 5 | -------------------------------------------------------------------------------- /defaults/cli.conf: -------------------------------------------------------------------------------- 1 | [startup_commands] 2 | dialplan set global ASTERISK_CONFIG_SYSTEM_READY 1 = yes 3 | 4 | #include cli_custom.conf 5 | #include cli.d/*.conf 6 | -------------------------------------------------------------------------------- /defaults/http.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | enabled=yes 3 | bindaddr=127.0.0.1 4 | bindport=8088 5 | sessionlimit=500 6 | session_inactivity=30000 7 | session_keep_alive=15000 8 | -------------------------------------------------------------------------------- /Dockerfile.goreleaser: -------------------------------------------------------------------------------- 1 | FROM gcr.io/distroless/static 2 | COPY asterisk-config /go/bin/asterisk-config 3 | COPY defaults /defaults 4 | ENTRYPOINT ["/go/bin/asterisk-config"] 5 | -------------------------------------------------------------------------------- /defaults/cdr.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | enable=yes 3 | 4 | [custom] 5 | ; We log the unique ID as it can be useful for troubleshooting any issues 6 | ; that arise. 7 | loguniqueid=yes 8 | -------------------------------------------------------------------------------- /check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | #dep ensure 3 | #gometalinter --skip test --skip defaults --cyclo-over=15 --deadline=90s --vendor ./... 4 | golangci-lint run 5 | go test ./... 6 | go build ./... 7 | go build 8 | -------------------------------------------------------------------------------- /random.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/nats-io/nuid" 4 | 5 | var secretGenerator *nuid.NUID 6 | 7 | func init() { 8 | secretGenerator = nuid.New() 9 | } 10 | 11 | func genSecret() string { 12 | return secretGenerator.Next() 13 | } 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.17 AS builder 2 | WORKDIR /go/src 3 | COPY . . 4 | RUN go get -d -v 5 | RUN CGO_ENABLED=0 go build -o /go/bin/app 6 | 7 | FROM gcr.io/distroless/static 8 | COPY defaults /defaults 9 | COPY --from=builder /go/bin/app /go/bin/app 10 | ENTRYPOINT ["/go/bin/app"] 11 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Only run if we are inside Travis-CI 4 | if [ ! -e $CI ]; then 5 | echo "Logging in to Docker..." 6 | echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin 7 | 8 | # Create the release 9 | echo "Creating release..." 10 | goreleaser release 11 | fi 12 | 13 | -------------------------------------------------------------------------------- /defaults/asterisk.conf: -------------------------------------------------------------------------------- 1 | [options] 2 | ; If we want to start Asterisk with a default verbosity for the verbose 3 | ; or debug logger channel types, then we use these settings (by default 4 | ; they are disabled). 5 | ;verbose = 5 6 | ;debug = 2 7 | 8 | ; User and group to run asterisk as. NOTE: This will require changes to 9 | ; directory and device permissions. 10 | ;runuser = asterisk ; The user to run as. The default is root. 11 | ;rungroup = asterisk ; The group to run as. The default is root 12 | 13 | ;defaultlanguage = es 14 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v3 18 | with: 19 | go-version: 1.18 20 | 21 | - name: lint 22 | uses: golangci/golangci-lint-action@v3 23 | 24 | - name: Build 25 | run: go build -v ./... 26 | 27 | - name: Test 28 | run: go test -v ./... 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 CyCore Systems, Inc. 2 | 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /defaults/cdr_custom.conf: -------------------------------------------------------------------------------- 1 | [mappings] 2 | ; Our CDR log will be written to /var/log/asterisk/cdr-custom/Master.csv 3 | ; with the following schema. 4 | ;Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})},${CDR(sequence)} 5 | -------------------------------------------------------------------------------- /defaults/indications.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | country = us ; We are in Waldo, Al, USA so the US is our default. 3 | 4 | [us] 5 | description = United States / North America 6 | ringcadence = 2000,4000 7 | dial = 350+440 8 | busy = 480+620/500,0/500 9 | ring = 440+480/2000,0/4000 10 | congestion = 480+620/250,0/250 11 | callwaiting = 440/300,0/10000 12 | dialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440 13 | record = 1400/500,0/15000 14 | info = !950/330,!1400/330,!1800/330,0 15 | stutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440 16 | 17 | ; Additional country configurations can be found in the Asterisk source 18 | ; at /configs/samples/indications.conf.sample 19 | -------------------------------------------------------------------------------- /defaults/pjsip.d/k8s-asterisk-config.conf.tmpl: -------------------------------------------------------------------------------- 1 | [k8s-internal-ipv4-internal-media] 2 | type=transport 3 | protocol=udp 4 | bind=0.0.0.0:5080 5 | local_net={{.Network "privateIPv4"}} 6 | external_media_address={{.Network "privateIPv4"}} 7 | external_signaling_address={{.Network "privateIPv4"}} 8 | 9 | [k8s-internal-ipv4-external-media] 10 | type=transport 11 | protocol=udp 12 | bind=0.0.0.0:5070 13 | local_net={{.Network "privateIPv4"}} 14 | external_media_address={{.Network "publicIPv4"}} 15 | external_signaling_address={{.Network "privateIPv4"}} 16 | 17 | [k8s-external-ipv4-external-media] 18 | type=transport 19 | protocol=udp 20 | bind=0.0.0.0:5060 21 | local_net={{.Network "privateIPv4"}} 22 | external_media_address={{.Network "publicIPv4"}} 23 | external_signaling_address={{.Network "publicIPv4"}} 24 | 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | 14 | - name: Set up Buildx 15 | id: buildx 16 | uses: docker/setup-buildx-action@v1 17 | 18 | - name: Set up Go 19 | uses: actions/setup-go@v3 20 | with: 21 | go-version: 1.18 22 | 23 | - name: Docker Hub Login 24 | uses: docker/login-action@v1 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | 29 | - name: GHCR Login 30 | uses: docker/login-action@v1 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GITHUB_TOKEN }} 35 | 36 | - name: GoReleaser 37 | uses: goreleaser/goreleaser-action@v2.8.0 38 | with: 39 | args: release --rm-dist 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | -------------------------------------------------------------------------------- /.github/workflows/master.yaml: -------------------------------------------------------------------------------- 1 | name: Master branch push 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | 9 | image: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: PrepareReg Names 14 | run: | 15 | echo IMAGE_REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV 16 | echo IMAGE_TAG=$(echo ${{ github.ref }} | tr '[:upper:]' '[:lower:]' | awk '{split($0,a,"/"); print a[3]}') >> $GITHUB_ENV 17 | 18 | - name: Set up Buildx 19 | id: buildx 20 | uses: docker/setup-buildx-action@v1 21 | 22 | - name: Set up Go 23 | uses: actions/setup-go@v3 24 | with: 25 | go-version: 1.18 26 | 27 | - name: GHCR Login 28 | uses: docker/login-action@v1 29 | with: 30 | registry: ghcr.io 31 | username: ${{ github.repository_owner }} 32 | password: ${{ secrets.GITHUB_TOKEN }} 33 | 34 | - name: GHCR Push 35 | uses: docker/build-push-action@v2 36 | with: 37 | push: true 38 | tags: | 39 | ghcr.io/${{ env.IMAGE_REPOSITORY }}:${{ github.sha }} 40 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/CyCoreSystems/asterisk-config 2 | 3 | require ( 4 | github.com/CyCoreSystems/kubetemplate v0.6.0-rc1 5 | github.com/CyCoreSystems/netdiscover v1.2.4 6 | github.com/nats-io/nuid v1.0.1 7 | github.com/rotisserie/eris v0.4.1 8 | k8s.io/client-go v0.23.1 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/go-logr/logr v1.2.0 // indirect 14 | github.com/gogo/protobuf v1.3.2 // indirect 15 | github.com/golang/protobuf v1.5.2 // indirect 16 | github.com/google/go-cmp v0.5.5 // indirect 17 | github.com/google/gofuzz v1.1.0 // indirect 18 | github.com/googleapis/gnostic v0.5.5 // indirect 19 | github.com/json-iterator/go v1.1.12 // indirect 20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 21 | github.com/modern-go/reflect2 v1.0.2 // indirect 22 | golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect 23 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect 24 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e // indirect 25 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect 26 | golang.org/x/text v0.3.7 // indirect 27 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 28 | google.golang.org/appengine v1.6.7 // indirect 29 | google.golang.org/protobuf v1.27.1 // indirect 30 | gopkg.in/inf.v0 v0.9.1 // indirect 31 | gopkg.in/yaml.v2 v2.4.0 // indirect 32 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 33 | k8s.io/api v0.23.1 // indirect 34 | k8s.io/apimachinery v0.23.1 // indirect 35 | k8s.io/klog/v2 v2.30.0 // indirect 36 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect 37 | k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect 38 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect 39 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 40 | sigs.k8s.io/yaml v1.2.0 // indirect 41 | ) 42 | 43 | go 1.17 44 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at sys@cycoresys.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /defaults/modules.conf: -------------------------------------------------------------------------------- 1 | [modules] 2 | autoload = no 3 | 4 | ; This is a minimal module load. We are loading only the modules required for 5 | ; the Asterisk features used in the Super Awesome Company configuration. 6 | 7 | ; Applications 8 | 9 | load = app_bridgewait.so 10 | load = app_dial.so 11 | load = app_playback.so 12 | load = app_stack.so 13 | load = app_verbose.so 14 | load = app_voicemail.so 15 | load = app_directory.so 16 | load = app_confbridge.so 17 | load = app_stasis.so 18 | 19 | ; Bridging 20 | 21 | load = bridge_builtin_features.so 22 | load = bridge_builtin_interval_features.so 23 | load = bridge_holding.so 24 | load = bridge_native_rtp.so 25 | load = bridge_simple.so 26 | load = bridge_softmix.so 27 | 28 | ; Call Detail Records 29 | 30 | load = cdr_custom.so 31 | 32 | ; Channel Drivers 33 | 34 | load = chan_bridge_media.so 35 | load = chan_pjsip.so 36 | 37 | ; Codecs 38 | 39 | load = codec_gsm.so 40 | load = codec_resample.so 41 | load = codec_ulaw.so 42 | load = codec_g722.so 43 | 44 | ; Formats 45 | 46 | load = format_gsm.so 47 | load = format_pcm.so 48 | load = format_wav_gsm.so 49 | load = format_wav.so 50 | 51 | ; Functions 52 | 53 | load = func_callerid.so 54 | load = func_cdr.so 55 | load = func_pjsip_endpoint.so 56 | load = func_sorcery.so 57 | load = func_devstate.so 58 | load = func_strings.so 59 | 60 | ; Core/PBX 61 | 62 | load = pbx_config.so 63 | 64 | ; Resources 65 | 66 | load = res_musiconhold.so 67 | load = res_pjproject.so 68 | load = res_pjsip_acl.so 69 | load = res_pjsip_authenticator_digest.so 70 | load = res_pjsip_caller_id.so 71 | load = res_pjsip_dialog_info_body_generator.so 72 | load = res_pjsip_diversion.so 73 | load = res_pjsip_dtmf_info.so 74 | load = res_pjsip_endpoint_identifier_anonymous.so 75 | load = res_pjsip_endpoint_identifier_ip.so 76 | load = res_pjsip_endpoint_identifier_user.so 77 | load = res_pjsip_exten_state.so 78 | load = res_pjsip_header_funcs.so 79 | load = res_pjsip_logger.so 80 | load = res_pjsip_messaging.so 81 | load = res_pjsip_mwi_body_generator.so 82 | load = res_pjsip_mwi.so 83 | load = res_pjsip_nat.so 84 | load = res_pjsip_notify.so 85 | load = res_pjsip_one_touch_record_info.so 86 | load = res_pjsip_outbound_authenticator_digest.so 87 | load = res_pjsip_outbound_publish.so 88 | load = res_pjsip_outbound_registration.so 89 | load = res_pjsip_path.so 90 | load = res_pjsip_pidf_body_generator.so 91 | load = res_pjsip_pidf_digium_body_supplement.so 92 | load = res_pjsip_pidf_eyebeam_body_supplement.so 93 | load = res_pjsip_publish_asterisk.so 94 | load = res_pjsip_pubsub.so 95 | load = res_pjsip_refer.so 96 | load = res_pjsip_registrar_expire.so 97 | load = res_pjsip_registrar.so 98 | load = res_pjsip_rfc3326.so 99 | load = res_pjsip_sdp_rtp.so 100 | load = res_pjsip_send_to_voicemail.so 101 | load = res_pjsip_session.so 102 | load = res_pjsip.so 103 | load = res_pjsip_t38.so 104 | load = res_pjsip_transport_websocket.so 105 | load = res_pjsip_xpidf_body_generator.so 106 | load = res_rtp_asterisk.so 107 | load = res_sorcery_astdb.so 108 | load = res_sorcery_config.so 109 | load = res_sorcery_memory.so 110 | load = res_sorcery_realtime.so 111 | load = res_stasis_answer.so 112 | load = res_stasis_device_state.so 113 | load = res_stasis_playback.so 114 | load = res_stasis_recording.so 115 | load = res_stasis_snoop.so 116 | load = res_stasis.so 117 | load = res_ari_applications.so 118 | load = res_ari_asterisk.so 119 | load = res_ari_bridges.so 120 | load = res_ari_channels.so 121 | load = res_ari_device_states.so 122 | load = res_ari_endpoints.so 123 | load = res_ari_events.so 124 | load = res_ari_model.so 125 | load = res_ari_playbacks.so 126 | load = res_ari_recordings.so 127 | load = res_ari_sounds.so 128 | load = res_ari.so 129 | load = res_timing_timerfd.so 130 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: Asterisk Config 2 | builds: 3 | - binary: asterisk-config 4 | env: 5 | - CGO_ENABLED=0 6 | goos: 7 | - linux 8 | - darwin 9 | - windows 10 | goarch: 11 | - amd64 12 | - arm64 13 | 14 | archives: 15 | - id: asterisk-config 16 | format: tar.gz 17 | name_template: "{{ .Binary }}.{{ .Os }}.{{ .Arch }}" 18 | files: 19 | - 'defaults/*' 20 | checksum: 21 | name_template: 'checksums.txt' 22 | snapshot: 23 | name_template: "{{ .Tag }}-next" 24 | changelog: 25 | sort: asc 26 | filters: 27 | exclude: 28 | - '^docs:' 29 | - '^doc:' 30 | - '^test:' 31 | 32 | dockers: 33 | - image_templates: 34 | - 'cycoresystems/asterisk-config:{{ .Tag }}-amd64' 35 | - 'cycoresystems/asterisk-config:v{{ .Major }}-amd64' 36 | - 'cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-amd64' 37 | - 'cycoresystems/asterisk-config:latest-amd64' 38 | - 'ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}-amd64' 39 | - 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}-amd64' 40 | - 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-amd64' 41 | - 'ghcr.io/cycoresystems/asterisk-config:latest-amd64' 42 | use: buildx 43 | goos: linux 44 | goarch: amd64 45 | dockerfile: Dockerfile.goreleaser 46 | extra_files: 47 | - 'defaults/' 48 | build_flag_templates: 49 | - "--platform=linux/amd64" 50 | - image_templates: 51 | - 'cycoresystems/asterisk-config:{{ .Tag }}-arm64v8' 52 | - 'cycoresystems/asterisk-config:v{{ .Major }}-arm64v8' 53 | - 'cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-arm64v8' 54 | - 'cycoresystems/asterisk-config:latest-arm64v8' 55 | - 'ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}-arm64v8' 56 | - 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}-arm64v8' 57 | - 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-arm64v8' 58 | - 'ghcr.io/cycoresystems/asterisk-config:latest-arm64v8' 59 | use: buildx 60 | goos: linux 61 | goarch: arm64 62 | dockerfile: Dockerfile.goreleaser 63 | extra_files: 64 | - 'defaults/' 65 | build_flag_templates: 66 | - "--platform=linux/arm64/v8" 67 | docker_manifests: 68 | - name_template: 'cycoresystems/asterisk-config:{{ .Tag }}' 69 | image_templates: 70 | - cycoresystems/asterisk-config:{{ .Tag }}-amd64 71 | - cycoresystems/asterisk-config:{{ .Tag }}-arm64v8 72 | - name_template: 'ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}' 73 | image_templates: 74 | - ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}-amd64 75 | - ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}-arm64v8 76 | - name_template: 'cycoresystems/asterisk-config:v{{ .Major }}' 77 | image_templates: 78 | - cycoresystems/asterisk-config:v{{ .Major }}-amd64 79 | - cycoresystems/asterisk-config:v{{ .Major }}-arm64v8 80 | - name_template: 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}' 81 | image_templates: 82 | - ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}-amd64 83 | - ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}-arm64v8 84 | - name_template: 'cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}' 85 | image_templates: 86 | - cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-amd64 87 | - cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-arm64v8 88 | - name_template: 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}' 89 | image_templates: 90 | - ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-amd64 91 | - ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-arm64v8 92 | - name_template: 'cycoresystems/asterisk-config:latest' 93 | image_templates: 94 | - cycoresystems/asterisk-config:latest-amd64 95 | - cycoresystems/asterisk-config:latest-arm64v8 96 | - name_template: 'ghcr.io/cycoresystems/asterisk-config:latest' 97 | image_templates: 98 | - ghcr.io/cycoresystems/asterisk-config:latest-amd64 99 | - ghcr.io/cycoresystems/asterisk-config:latest-arm64v8 100 | -------------------------------------------------------------------------------- /Documentation/pjsip-ext-ext.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Documentation/pjsip-int-ext.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Documentation/pjsip-int-int.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/zip" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "fmt" 9 | "io" 10 | "io/ioutil" 11 | "log" 12 | "net/http" 13 | "os" 14 | "path" 15 | "path/filepath" 16 | "strings" 17 | "sync" 18 | "time" 19 | 20 | "github.com/CyCoreSystems/kubetemplate" 21 | "github.com/CyCoreSystems/netdiscover/discover" 22 | "github.com/rotisserie/eris" 23 | "k8s.io/client-go/kubernetes" 24 | "k8s.io/client-go/rest" 25 | ) 26 | 27 | const ariUsername = "k8s-asterisk-config" 28 | const secretFilename = ".k8s-generated-secret" 29 | const renderFlagFilename = ".asterisk-config" 30 | 31 | var maxShortDeaths = 10 32 | var minRuntime = time.Minute 33 | var defaultMinReloadInterval = 5 * time.Second 34 | 35 | // Service maintains an Asterisk configuration set 36 | type Service struct { 37 | 38 | // Discoverer is the engine which should be used for network discovery 39 | Discoverer discover.Discoverer 40 | 41 | // Secret is the password which should be used for internal administrative authentication 42 | Secret string 43 | 44 | // CustomRoot is the directory which contains the tree of custom configuration templates 45 | CustomRoot string 46 | 47 | // DefaultsRoot is the directory which contains the default configuration templates 48 | DefaultsRoot string 49 | 50 | // ExportRoot is the destination directory to which the rendered configuration set will be exported. 51 | ExportRoot string 52 | 53 | // Modules is the list of Asterisk modules which should be reloaded after each render is complete. 54 | Modules string 55 | 56 | // engine is the template rendering and monitoring engine 57 | engine kubetemplate.Engine 58 | } 59 | 60 | // nolint: gocyclo 61 | func main() { 62 | var err error 63 | 64 | cloud := "" 65 | if os.Getenv("CLOUD") != "" { 66 | cloud = os.Getenv("CLOUD") 67 | } 68 | disc := getDiscoverer(cloud) 69 | 70 | source := "/source/asterisk-config.zip" 71 | if os.Getenv("SOURCE") != "" { 72 | source = os.Getenv("SOURCE") 73 | } 74 | 75 | defaultsRoot := "/defaults" 76 | if os.Getenv("DEFAULTS_DIR") != "" { 77 | defaultsRoot = os.Getenv("DEFAULTS_DIR") 78 | } 79 | 80 | customRoot := "/custom" 81 | if os.Getenv("CUSTOM_DIR") != "" { 82 | customRoot = os.Getenv("CUSTOM_DIR") 83 | } 84 | if err := os.MkdirAll(customRoot, os.ModePerm); err != nil { 85 | log.Println("failed to ensure custom directory", customRoot, ":", err.Error()) 86 | os.Exit(1) 87 | } 88 | 89 | exportRoot := "/etc/asterisk" 90 | if os.Getenv("EXPORT_DIR") != "" { 91 | exportRoot = os.Getenv("EXPORT_DIR") 92 | } 93 | if err = os.MkdirAll(exportRoot, os.ModePerm); err != nil { 94 | log.Println("failed to ensure destination directory", exportRoot, ":", err.Error()) 95 | os.Exit(1) 96 | } 97 | 98 | modules := "res_pjsip.so" 99 | if os.Getenv("RELOAD_MODULES") != "" { 100 | modules = os.Getenv("RELOAD_MODULES") 101 | } 102 | 103 | secret := os.Getenv("ARI_AUTOSECRET") 104 | if secret == "" { 105 | secret, err = getOrCreateSecret(exportRoot) 106 | if err != nil { 107 | log.Println("failed to get secret:", err) 108 | os.Exit(1) 109 | } 110 | os.Setenv("ARI_AUTOSECRET", secret) 111 | } 112 | 113 | // Try to extract the source 114 | if err := extractSource(source, customRoot); err != nil { 115 | log.Printf("failed to load source from %s: %s\n", source, err.Error()) 116 | } 117 | 118 | var shortDeaths int 119 | var t time.Time 120 | for shortDeaths < maxShortDeaths { 121 | 122 | svc := &Service{ 123 | Discoverer: disc, 124 | Secret: secret, 125 | CustomRoot: customRoot, 126 | DefaultsRoot: defaultsRoot, 127 | ExportRoot: exportRoot, 128 | Modules: modules, 129 | } 130 | 131 | t = time.Now() 132 | log.Println("running service") 133 | err := svc.Run() 134 | log.Println("service exited:", err) 135 | if time.Since(t) < minRuntime { 136 | shortDeaths++ 137 | } else { 138 | shortDeaths = 0 139 | } 140 | } 141 | 142 | log.Println("asterisk-config exiting") 143 | os.Exit(1) 144 | } 145 | 146 | // Run executes the Service 147 | func (s *Service) Run() error { 148 | ctx, cancel := context.WithCancel(context.Background()) 149 | defer cancel() 150 | 151 | r := newReloader(ctx, ariUsername, s.Secret, s.Modules) 152 | 153 | kconfig, err := rest.InClusterConfig() 154 | if err != nil { 155 | return fmt.Errorf("failed to create in-cluster Kubernetes config: %w", err) 156 | } 157 | 158 | kc, err := kubernetes.NewForConfig(kconfig) 159 | if err != nil { 160 | return eris.Wrap(err, "failed to create Kubernetes client") 161 | } 162 | 163 | s.engine, err = kubetemplate.NewEngine(kc, s.Discoverer, 10*time.Minute) 164 | if err != nil { 165 | return eris.Wrap(err, "failed to create templating engine") 166 | } 167 | 168 | defer s.engine.Close() 169 | 170 | // Learn the templates first 171 | if err := s.learnTemplates(); err != nil { 172 | return eris.Wrap(err, "failed to learn defaults") 173 | } 174 | 175 | // Execute first template render 176 | if err := s.renderTemplates(); err != nil { 177 | return eris.Wrap(err, "failed to render configuration") 178 | } 179 | 180 | // Write out render flag file to signal completion 181 | if err := ioutil.WriteFile(path.Join(s.ExportRoot, renderFlagFilename), []byte("complete"), 0666); err != nil { 182 | return eris.Wrap(err, "failed to write render flag file") 183 | } 184 | 185 | r.Reload() 186 | 187 | for ctx.Err() == nil { 188 | s.engine.Wait(ctx) 189 | 190 | log.Println("change detected") 191 | 192 | if err := s.renderTemplates(); err != nil { 193 | return eris.Wrap(err, "failed to render configuration") 194 | } 195 | 196 | r.Reload() 197 | } 198 | 199 | return ctx.Err() 200 | } 201 | 202 | func (s *Service) learnTemplates() error { 203 | if err := render(s.engine, true, s.DefaultsRoot, s.ExportRoot); err != nil { 204 | return eris.Wrap(err, "failed to learn defaults") 205 | } 206 | if err := render(s.engine, true, s.CustomRoot, s.ExportRoot); err != nil { 207 | return eris.Wrap(err, "failed to learn templates") 208 | } 209 | 210 | return nil 211 | } 212 | 213 | func (s *Service) renderTemplates() error { 214 | if err := render(s.engine, false, s.DefaultsRoot, s.ExportRoot); err != nil { 215 | return eris.Wrap(err, "failed to render defaults") 216 | } 217 | if err := render(s.engine, false, s.CustomRoot, s.ExportRoot); err != nil { 218 | return eris.Wrap(err, "failed to render templates") 219 | } 220 | 221 | return nil 222 | } 223 | 224 | func getDiscoverer(cloud string) discover.Discoverer { 225 | switch cloud { 226 | case "aws": 227 | return discover.NewAWSDiscoverer() 228 | case "azure": 229 | return discover.NewAzureDiscoverer() 230 | case "digitalocean": 231 | return discover.NewDigitalOceanDiscoverer() 232 | case "do": 233 | return discover.NewDigitalOceanDiscoverer() 234 | case "gcp": 235 | return discover.NewGCPDiscoverer() 236 | case "": 237 | return discover.NewDiscoverer() 238 | default: 239 | log.Printf("WARNING: unhandled cloud %s\n", cloud) 240 | return discover.NewDiscoverer() 241 | } 242 | } 243 | 244 | func getOrCreateSecret(exportRoot string) (string, error) { 245 | secret := genSecret() 246 | secretPath := path.Join(exportRoot, secretFilename) 247 | 248 | // Determine if a secret has already been generated 249 | if data, err := ioutil.ReadFile(secretPath); err == nil { 250 | if len(data) > 0 { 251 | return string(data), nil 252 | } 253 | } 254 | 255 | if err := ioutil.WriteFile(secretPath, []byte(secret), 0600); err != nil { 256 | return "", eris.Wrap(err, "failed to write secret to file") 257 | } 258 | return secret, nil 259 | } 260 | 261 | func render(e kubetemplate.Engine, learn bool, customRoot string, exportRoot string) error { 262 | var fileCount int 263 | 264 | err := filepath.Walk(customRoot, func(fn string, info os.FileInfo, err error) error { 265 | if err != nil { 266 | return eris.Wrapf(err, "failed to access file %s", fn) 267 | } 268 | 269 | isTemplate := path.Ext(fn) == ".tmpl" 270 | 271 | outFile := path.Join(exportRoot, strings.TrimPrefix(fn, customRoot)) 272 | if isTemplate { 273 | outFile = strings.TrimSuffix(outFile, ".tmpl") 274 | } 275 | 276 | if info.IsDir() { 277 | return os.MkdirAll(outFile, os.ModePerm) 278 | } 279 | if err = os.MkdirAll(path.Dir(outFile), os.ModePerm); err != nil { 280 | return eris.Wrapf(err, "failed to create destination directory %s", path.Dir(outFile)) 281 | } 282 | fileCount++ 283 | 284 | out, err := os.Create(outFile) 285 | if err != nil { 286 | return eris.Wrapf(err, "failed to open file for writing: %s", outFile) 287 | } 288 | defer out.Close() // nolint: errcheck 289 | 290 | in, err := os.Open(fn) // nolint: gosec 291 | if err != nil { 292 | return eris.Wrapf(err, "failed to open template for reading: %s", fn) 293 | } 294 | defer in.Close() // nolint: errcheck 295 | 296 | if isTemplate { 297 | if learn { 298 | return e.Learn(in, os.Getenv("POD_NAMESPACE")) 299 | } 300 | return e.Render(out, in, os.Getenv("POD_NAMESPACE")) 301 | } 302 | 303 | _, err = io.Copy(out, in) 304 | return err 305 | }) 306 | if err != nil { 307 | return err 308 | } 309 | 310 | if fileCount < 1 { 311 | return errors.New("no files processed") 312 | } 313 | 314 | return nil 315 | } 316 | 317 | func waitAsterisk(username, secret string) error { 318 | r, err := http.NewRequest("GET", "http://127.0.0.1:8088/ari/asterisk/variable?variable=ASTERISK_CONFIG_SYSTEM_READY", nil) 319 | if err != nil { 320 | return eris.Wrap(err, "failed to construct ping request") 321 | } 322 | r.Header.Set("Content-Type", "application/json") 323 | r.SetBasicAuth(username, secret) 324 | 325 | type response struct { 326 | Value string `json:"value"` 327 | } 328 | resp := new(response) 329 | 330 | for { 331 | time.Sleep(time.Second / 2) 332 | 333 | ret, err := http.DefaultClient.Do(r) 334 | if err != nil { 335 | continue 336 | } 337 | 338 | if err = json.NewDecoder(ret.Body).Decode(resp); err != nil { 339 | // failed to decode into resp format 340 | log.Println("failed to decode Asterisk response:", err) 341 | continue 342 | } 343 | if resp.Value != "1" { 344 | // not yet ready 345 | continue 346 | } 347 | 348 | // System ready 349 | log.Println("Asterisk ready") 350 | return nil 351 | } 352 | } 353 | 354 | func extractSource(source, customRoot string) (err error) { 355 | if strings.HasPrefix(source, "http") { 356 | source, err = downloadSource(source) 357 | if err != nil { 358 | return eris.Wrap(err, "failed to download source") 359 | } 360 | } 361 | 362 | r, err := zip.OpenReader(source) 363 | if err != nil { 364 | return eris.Wrap(err, "failed to open source archive") 365 | } 366 | defer r.Close() // nolint: errcheck 367 | 368 | for _, f := range r.File { 369 | 370 | in, err := f.Open() 371 | if err != nil { 372 | return eris.Wrapf(err, "failed to read file %s", f.Name) 373 | } 374 | defer in.Close() // nolint: errcheck 375 | 376 | dest := path.Join(customRoot, f.Name) 377 | if f.FileInfo().IsDir() { 378 | if err = os.MkdirAll(dest, os.ModePerm); err != nil { 379 | return eris.Wrapf(err, "failed to create destination directory %s", f.Name) 380 | } 381 | continue 382 | } 383 | 384 | if err = os.MkdirAll(path.Dir(dest), os.ModePerm); err != nil { 385 | return eris.Wrapf(err, "failed to create destination directory %s", path.Dir(dest)) 386 | } 387 | 388 | out, err := os.Create(dest) 389 | if err != nil { 390 | return eris.Wrapf(err, "failed to create file %s", dest) 391 | } 392 | 393 | _, err = io.Copy(out, in) 394 | out.Close() // nolint 395 | if err != nil { 396 | return eris.Wrapf(err, "error writing file %s", dest) 397 | } 398 | 399 | } 400 | 401 | return nil 402 | } 403 | 404 | func downloadSource(uri string) (string, error) { 405 | req, err := http.NewRequest("GET", uri, nil) 406 | if err != nil { 407 | return "", eris.Wrapf(err, "failed to construct web request to %s", uri) 408 | } 409 | 410 | if os.Getenv("URL_USERNAME") != "" { 411 | req.SetBasicAuth(os.Getenv("URL_USERNAME"), os.Getenv("URL_PASSWORD")) 412 | } 413 | if os.Getenv("URL_AUTHORIZATION") != "" { 414 | req.Header.Add("Authorization", os.Getenv("URL_AUTHORIZATION")) 415 | } 416 | 417 | resp, err := http.DefaultClient.Do(req) 418 | if err != nil { 419 | return "", err 420 | } 421 | defer resp.Body.Close() // nolint: errcheck 422 | 423 | if resp.StatusCode < 200 || resp.StatusCode > 299 { 424 | return "", fmt.Errorf("request failed: %s", resp.Status) 425 | } 426 | if resp.ContentLength < 1 { 427 | return "", errors.New("empty response") 428 | } 429 | 430 | tf, err := ioutil.TempFile("", "config-download") 431 | if err != nil { 432 | return "", eris.Wrap(err, "failed to create temporary file for download") 433 | } 434 | defer tf.Close() // nolint: errcheck 435 | 436 | _, err = io.Copy(tf, resp.Body) 437 | 438 | return tf.Name(), err 439 | } 440 | 441 | type reloader struct { 442 | minReloadInterval time.Duration 443 | 444 | username string 445 | secret string 446 | 447 | modules []string 448 | 449 | needReload bool 450 | 451 | mu sync.Mutex 452 | } 453 | 454 | func newReloader(ctx context.Context, username, secret, modules string) *reloader { 455 | r := &reloader{ 456 | minReloadInterval: defaultMinReloadInterval, 457 | username: username, 458 | secret: secret, 459 | } 460 | 461 | for _, m := range strings.Split(modules, ",") { 462 | r.modules = append(r.modules, strings.TrimSpace(m)) 463 | } 464 | 465 | go r.run(ctx) 466 | 467 | return r 468 | } 469 | 470 | func (r *reloader) run(ctx context.Context) { 471 | // Wait for Asterisk to come up before proceeding, so as to not interrupt 472 | // normal Asterisk loading with a reload 473 | log.Println("Waiting for Asterisk to be ready...") 474 | if err := waitAsterisk(r.username, r.secret); err != nil { 475 | log.Fatalln("failed to wait for Asterisk to come up:", err) 476 | } 477 | 478 | for { 479 | select { 480 | case <-ctx.Done(): 481 | return 482 | case <-time.After(r.minReloadInterval): 483 | } 484 | 485 | if err := r.maybeRunReload(); err != nil { 486 | log.Println("failed to reload modules", err) 487 | } 488 | } 489 | } 490 | 491 | func (r *reloader) maybeRunReload() error { 492 | r.mu.Lock() 493 | defer r.mu.Unlock() 494 | 495 | if r.needReload { 496 | if err := r.reload(); err != nil { 497 | return err 498 | } 499 | 500 | r.needReload = false 501 | } 502 | 503 | return nil 504 | } 505 | 506 | func (r *reloader) Reload() { 507 | r.mu.Lock() 508 | r.needReload = true 509 | r.mu.Unlock() 510 | } 511 | 512 | func (r *reloader) reload() error { 513 | log.Println("reloading Asterisk modules") 514 | for _, m := range r.modules { 515 | if err := r.reloadModule(m); err != nil { 516 | return err 517 | } 518 | } 519 | log.Println("Asterisk modules reloaded") 520 | 521 | return nil 522 | } 523 | 524 | func (r *reloader) reloadModule(name string) error { 525 | url := fmt.Sprintf("http://127.0.0.1:8088/ari/asterisk/modules/%s", name) 526 | 527 | req, err := http.NewRequest("PUT", url, nil) 528 | if err != nil { 529 | return eris.Wrapf(err, "failed to construct module reload request for module %s", name) 530 | } 531 | req.Header.Set("Content-Type", "application/json") 532 | req.SetBasicAuth(r.username, r.secret) 533 | 534 | ret, err := http.DefaultClient.Do(req) 535 | if err != nil { 536 | return eris.Wrapf(err, "failed to contact ARI to reload module %s", name) 537 | } 538 | ret.Body.Close() // nolint 539 | 540 | switch ret.StatusCode { 541 | case http.StatusNoContent: 542 | return nil 543 | case http.StatusNotFound: 544 | return fmt.Errorf("module %s not already loaded", name) 545 | case http.StatusUnauthorized: 546 | return fmt.Errorf("module %s failed to reload due bad authentication", name) 547 | case 409: 548 | return fmt.Errorf("module %s could not be reloaded", name) 549 | default: 550 | return fmt.Errorf("module %s reload failed: %s", name, ret.Status) 551 | } 552 | } 553 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Asterisk Config 2 | 3 | Asterisk Config is a kubernetes sidecar container which constructs the 4 | configuration for Asterisk. It is comprised of a custom configuration set and a 5 | standardized dynamic environment set to build the Asterisk configuration for the 6 | Pod in question. 7 | 8 | The primary dynamic component of Asterisk Config is the IP address (internal and 9 | external) for use by the SIP and PJSIP modules. 10 | 11 | ## Automatic reloading 12 | 13 | Any time dynamic data is updated, Asterisk is told to reload. By default, we 14 | only reload `res_pjsip.so`, since the dynamic data usually just involves PJSIP 15 | endpoint IPs. However, you can set the `RELOAD_MODULES` environment variable to 16 | a comma-separated list of modules which should be reloaded when the dynamic data 17 | is updated. 18 | 19 | The reloads are performed by executing the ARI "/asterisk/modules" "PUT" 20 | (reload) once for each of the specified modules. This ARI connection is 21 | automatically created with a randomly-generated password by Asterisk Config. 22 | 23 | ## Layering 24 | 25 | There are two layers of files which are used: 26 | 27 | - Default configuration 28 | - Custom configuration 29 | 30 | ### Default configuration 31 | 32 | Included within this package is the standard Asterisk basic configuration set 33 | with minimal alterations to: 34 | 35 | - include custom configurations 36 | - include configuration directories 37 | - disable all file-based logging 38 | 39 | Any file in the default configuration my be replaced by including it in your 40 | custom configuration bundle, but see the Custom configuration section below for 41 | better methods. 42 | 43 | The default configuration also creates configurations for ARI, so that it may 44 | call a reload when necessary, and PJSIP, to configure the IP information for 45 | transports. 46 | 47 | #### PJSIP default transports 48 | 49 | The following default PJSIP transports will be specified: 50 | 51 | - `k8s-internal-ipv4-internal-media` (internal SIP/signaling advertisement, 52 | internal RTP/media advertisement, port 5080/UDP) 53 | - `k8s-internal-ipv4-external-media` (internal SIP/signaling advertisement, 54 | external RTP/media advertisement, port 5070/UDP) 55 | - `k8s-external-ipv4-external-media` (external SIP/signaling advertisement, 56 | external RTP/media advertisement, port 5060/UDP) 57 | 58 | In most cloud-based kubernetes setups, the Pod will be assigned an internal IP 59 | address, and it will have a NATed external IP address. The choice of transports 60 | depends on two things: 61 | 62 | - Where is the _signaling_ endpoint? 63 | - Where is the _media_ endpoint? 64 | 65 | It is common, for instance, to use kamailio as a SIP proxy to handle a scalable 66 | set of Asterisk servers. In this case, you would want to use _internal_ 67 | signaling IPs. The RTP, however, will depend on whether you want your media to 68 | flow _directly_ to your Asterisk Pods (`-external-media`) or by way of 69 | `rtpengine` or `rtpproxy` (`-internal-media`). 70 | 71 | For each of your PJSIP `Endpoints`, just specify the transport you wish to 72 | use. 73 | 74 | - ![Internal SIP, Internal RTP](./Documentation/pjsip-int-int.svg) 75 | - ![Internal SIP, External RTP](./Documentation/pjsip-int-ext.svg) 76 | - ![External SIP, External RTP](./Documentation/pjsip-ext-ext.svg) 77 | 78 | ### Custom configuration 79 | 80 | While your custom configurations are allowed to overwrite any Asterisk 81 | configuration file, there are generally two schemes by which customized configurations may be 82 | applied: 83 | 84 | - `.d/XXXX.conf` 85 | - `_custom.conf` 86 | 87 | The most flexible approach is to create any number of discrete files in the 88 | module configuration subdirectories. For instance, you might add a PJSIP 89 | endpoint configuration in: 90 | 91 | `pjsip.d/ext-101.conf` 92 | 93 | Any file with the `.conf` extension in one of these directories will 94 | automatically be loaded. 95 | 96 | Modules which are configured to load configurations using this scheme are: 97 | 98 | - AMI (`manager.d/`) 99 | - ARI (`ari.d/`) 100 | - Extensions (`extensions.d/`) 101 | - PJSIP (`pjsip.d/`) 102 | - Voicemail (`voicemail.d/`) 103 | 104 | If there is any default configuration for any of these modules, that 105 | configuration will exist in `_custom.conf`. The corresponding 106 | `.conf` only contains include statements. 107 | 108 | Take special note that ARI and PJSIP modules are used internally by Asterisk 109 | Config, so changing their root `ari.conf` and `pjsip.conf` is not recommended 110 | unless you really know what you are doing. 111 | 112 | ## Usage 113 | 114 | It is presumed that you have a kubernetes installation on a standard cloud 115 | platform (such as AWS, GCP, Azure, DigitalOcean, etc) or are running a baremetal 116 | kubernetes cluster which you can control to supply the public and private IP 117 | addresses for the Asterisk Pod. 118 | 119 | It is strongly recommended to set the `CLOUD` environment variable to match your 120 | environment. The valid options are: 121 | 122 | - `aws` Amazon Web Services 123 | - `azure` Microsoft Azure 124 | - `digitalocean` or `do` Digital Ocean 125 | - `gcp` Google Cloud Platform 126 | - `` default discovery 127 | 128 | Default discovery is useful for baremetal configurations or situations where you 129 | do not wish to use the cloud provider's self discovery API. 130 | 131 | ***NOTE***: Importantly, in cases where you need Asterisk to use the kubernetes 132 | Pod IP address instead of the Node IP address, set the `CLOUD` variable to be 133 | the empty string. Default discovery also works for public IP addresses by using 134 | the `jsonip.io` service. 135 | 136 | Asterisk Config offers varying levels of configuration complexity, allowing you 137 | to easily just get your Asterisk system off the ground or to build a 138 | fully-templated configuration set. 139 | 140 | It is a common problem that Asterisk may start before the config has been 141 | written. In order to eliminate that eventuality, you should check for the 142 | existence of the `.asterisk-config` file before allowing Asterisk to start. 143 | 144 | ### Basic Usage 145 | 146 | The simplest use is: to create the set of custom Asterisk configurations 147 | 148 | 1. create the set of custom Asterisk configurations for your scenario 149 | 2. generate a `.zip` file of that configuration tree 150 | 3. load that `.zip` file to a ConfigMap, Secret, or Web URL 151 | 152 | For example: 153 | 154 | We will define a simple dialplan with a single PJSIP endpoint to a carrier. 155 | When a call comes in from the carrier, it will be answered and any audio 156 | received will be played back to the caller. 157 | 158 | First, create a directory to contain the configuration files. Files stored in 159 | this directory will be copied into `/etc/asterisk/` on the live Asterisk Pod. 160 | In this example, we will use the local directory named 161 | `/home/user/asterisk/config`. 162 | 163 | Inside your directory, we create two files: `pjsip.d/my_carrier.conf` and 164 | `extensions.d/dialin.conf`. 165 | 166 | `pjsip.d/my_carrier.conf`: 167 | 168 | ```ini 169 | [pstn] 170 | type=endpoint 171 | transport=k8s-external-ipv4-external-media 172 | context=dialin 173 | disallow=all 174 | allow=ulaw 175 | aors=pstn 176 | rtp_symmetric=yes 177 | 178 | [pstn] 179 | type=aor 180 | contact=sip:my.carrier.com:5060 181 | 182 | [pstn] 183 | type=identify 184 | endpoint=pstn 185 | match=12.34.56.78 186 | match=87.65.43.21 187 | 188 | [acl] 189 | type=acl 190 | deny=0.0.0.0/0.0.0.0 191 | permit=12.34.56.78/255.255.255.255 192 | permit=87.65.43.21/255.255.255.255 193 | ``` 194 | 195 | `extensions.d/dialin.conf`: 196 | 197 | ```ini 198 | [dialin] 199 | exten = echo,1,Verbose(1, "Running Echo") 200 | same = n,Answer() 201 | same = n,Echo() 202 | same = n,Hangup() 203 | 204 | exten = 15555555555,1,Verbose(1, "Received call to +1 555 555.5555") 205 | same = n,Goto(echo,1) 206 | ``` 207 | 208 | Now zip up these configuration files to a new `asterisk-config.zip`: 209 | 210 | ```sh 211 | zip -r asterisk-config.zip * 212 | ``` 213 | 214 | Then store the `asterisk-config.zip` file to kubernetes as a Secret named 215 | "asterisk-config": 216 | 217 | ```sh 218 | kubectl create secret generic asterisk-config --from-file=asterisk-config.zip 219 | ``` 220 | 221 | **NOTE**: By default, Asterisk-Config looks for the Secret named 222 | "asterisk-config" to load the custom configuration. See the section below for 223 | sourcing the custom configuration from a different location. 224 | 225 | Now we create a normal Pod spec for kubernetes including the Asterisk 226 | Configuration sidecar container: 227 | 228 | ```yaml 229 | apiVersion: extensions/v1beta1 230 | kind: Deployment 231 | metadata: 232 | name: asterisk 233 | labels: 234 | component: asterisk 235 | spec: 236 | replicas: 1 237 | template: 238 | metadata: 239 | labels: 240 | component: asterisk 241 | spec: 242 | hostNetwork: true 243 | containers: 244 | - name: config 245 | image: ghcr.io/cycoresystems/asterisk-config 246 | env: 247 | - name: POD_NAMESPACE 248 | valueFrom: 249 | fieldRef: 250 | fieldPath: metadata.namespace 251 | volumeMounts: 252 | - name: config 253 | mountPath: /etc/asterisk 254 | - name: source 255 | mountPath: /source 256 | - name: asterisk 257 | image: cycoresystems/asterisk 258 | volumeMounts: 259 | - name: config 260 | mountPath: /etc/asterisk 261 | volumes: 262 | - name: config 263 | - name: source 264 | secret: 265 | secretName: "asterisk-config" 266 | ``` 267 | 268 | 269 | ## Custom Configuration source 270 | 271 | By default, Asterisk Config looks for the file `/source/asterisk-config.zip` as 272 | the source of configuration. However, this can be customized by setting the 273 | `SOURCE` environment variable. 274 | 275 | You may also obtain the source from an HTTP URL by specifying that URL as the 276 | `SOURCE`. Additional environment variables may be provided for HTTP authentication: 277 | 278 | - `URL_USERNAME` (for basic authentication) 279 | - `URL_PASSWORD` (for basic authentication), 280 | - `URL_AUTHORIZATION` (explicit `"Authorization" header`) 281 | 282 | If no `SOURCE` file can be found or is specified, Asterisk Config will attempt to 283 | load the (expanded) configuration tree in the `/custom/` directory. In this 284 | way, you may plug in your own source-obtaining method and have it populate the 285 | custom configuration files in this directory. 286 | 287 | To make sure the Asterisk container is not successfully started before the 288 | configuration can be loaded, Asterisk Config will die if no valid custom 289 | configuration can be obtained. Asterisk will already die if it cannot find its 290 | configuration. Kubernetes will automatically restart each of these if they die. 291 | 292 | ## Templates 293 | 294 | Asterisk Config will process any file within the source bundle which ends in the 295 | `.tmpl` extension. These files will be processed as Go `text/template` 296 | files and the output stored as the same filename without the `.tmpl` extension. 297 | 298 | Values for the templates may come from a number of sources: 299 | 300 | - ConfigMap 301 | - Environment Variables 302 | - Service 303 | - Endpoints (of a Service) 304 | - EndpointIPs (of a Service) 305 | - Network 306 | 307 | ### ConfigMap 308 | 309 | To obtain ConfigMap entries, Asterisk Config will use the Kubernetes API to 310 | attempt to pull in the ConfigMap and key requested. 311 | 312 | **Format**: `{{.ConfigMap "" "" ""}}` 313 | 314 | The provided namespace _may_ be `""` if both the ConfigMap is in the same 315 | namespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly 316 | set. 317 | 318 | The ConfigMap will be monitored by Asterisk Config, and if it is updated, the 319 | configuration files will be regenerated, and a reload will be performed. 320 | 321 | Note that this will likely require an RBAC entry to allow the `ServiceAccount` 322 | under which Asterisk Config is running to access the referenced ConfigMap. 323 | 324 | 325 | ### Environment Variables 326 | 327 | **Format**: `{{.Env ""}}` 328 | 329 | It is useful to note that IP addresses of services within the same namespace 330 | will automatically be populated as environment variables by kubernetes. These 331 | will be of the form `_SERVICE_HOST`. For instance, the IP of a 332 | service named "kamailio" will be stored in the environment variable 333 | `KAMAILIO_SERVICE_HOST`. This is a normal, default feature of all kubernetes 334 | containers. See the [documentation](https://kubernetes.io/docs/concepts/services-networking/service/) for more information. 335 | 336 | ### Service 337 | 338 | Data from a kubernetes Service may be obtained using the Kubernetes API. 339 | 340 | **Format**: `{{.Service "" "]"}}` 341 | 342 | The provided namespace _may_ be `""` if both the Service is in the same 343 | namespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly 344 | set. 345 | 346 | The value returned here is the Kubernetes 347 | [Service](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#service-v1-core). 348 | Keep in mind that Go uses PascalCase for the fields, so "clusterIP" becomes 349 | "ClusterIP". 350 | 351 | For example, to get the ClusterIP of a service named "kamailio" in the "voip" 352 | namespace: 353 | 354 | `{{ with .Service "kamailio" "voip"}}{{.Spec.ClusterIP}}{{end}}` 355 | 356 | Note that the IP address of a service within the same namespace can be obtained 357 | more simply by environment variable, as described above. 358 | 359 | 360 | ### Endpoints 361 | 362 | Data from the kubernetes Endpoints of a Service may be obtained using the 363 | Kubernetes API. 364 | 365 | **Format**: `{{.Service "" ""}}` 366 | 367 | The provided namespace _may_ be `""` if both the Service is in the same 368 | namespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly 369 | set. 370 | 371 | The value returned is the Kubernetes [Endpoints](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#endpoints-v1-core). 372 | 373 | The Endpoints will be monitored by Asterisk Config, and if it is updated, the 374 | configuration files will be regenerated, and a reload will be performed. 375 | 376 | This is usually used to obtain the dynamic set of proxy servers, but since the 377 | most common reason to do this is to obtain the set of IPs for endpoints of a 378 | service, we provide a second helper function just for that. 379 | 380 | ### Endpoint IPs 381 | 382 | One of the most common pieces of dynamic data to retrieve is the set of IPs for 383 | the endpoints of a service. Therefore, to simplify the relatively tedious 384 | iteration of these directly from the Endpoints spec, we provide the EndpointIPs 385 | macro, which returns the list of IPs of all Endpoints of the given service 386 | name. 387 | 388 | **Format**: `{{.EndpointIPs "" ""}}` 389 | 390 | The provided namespace _may_ be `""` if both the Service is in the same 391 | namespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly 392 | set. 393 | 394 | Using this is then easy. For example, to create a PJSIP endpoint from the set 395 | of proxy servers running as the "kamailio" service: 396 | 397 | `pjsip.d/proxies.conf`: 398 | 399 | ```ini 400 | [proxies] 401 | type=endpoint 402 | transport=k8s-internal-ipv4-external-media 403 | context=from-proxies 404 | disallow=all 405 | allow=ulaw 406 | aors=proxies 407 | rtp_symmetric=yes 408 | 409 | [proxies] 410 | type=aor 411 | {{range .EndpointIPs "kamailio"}} 412 | contact=sip:{{.}} 413 | {{end}} 414 | 415 | [proxies] 416 | type=identify 417 | endpoint=proxies 418 | {{range .EndpointIPs "kamailio"}} 419 | match={{.}} 420 | {{end}} 421 | 422 | [proxies] 423 | type=acl 424 | deny=0.0.0.0/0.0.0.0 425 | {{range .EndpointIPs "kamailio"}} 426 | permit={{.}} 427 | {{end}} 428 | ``` 429 | 430 | The Endpoints IPs will be monitored by Asterisk Config, and if they are updated, the 431 | configuration files will be regenerated, and a reload will be performed. 432 | 433 | 434 | ### Network data 435 | 436 | The IP addresses for the running Pod are made available, as well. 437 | 438 | **Format**: `{{.Network ""}}` 439 | 440 | The available data kinds correspond to the data available from 441 | [NetDiscover](https://github.com/CyCoreSystems/netdiscover): 442 | 443 | - "hostname" 444 | - "privatev4" 445 | - "publicv4" 446 | - "publicv6" 447 | 448 | Note that PJSIP transports are already automatically set up, as described above. 449 | 450 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 17 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 18 | cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= 19 | cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= 20 | cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= 21 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 22 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 23 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 24 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 25 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 26 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 27 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 28 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 29 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 30 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 31 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 32 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 33 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 34 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 35 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 36 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 37 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 38 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 39 | github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= 40 | github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= 41 | github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= 42 | github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= 43 | github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= 44 | github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= 45 | github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= 46 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 47 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 48 | github.com/CyCoreSystems/kubetemplate v0.6.0-rc1 h1:AUkKHwYW4bIeLVxxyava0y9FTOtZ3/sbofHxATMwXBU= 49 | github.com/CyCoreSystems/kubetemplate v0.6.0-rc1/go.mod h1:6N6GpbDmvgwmS3j/fBeSD8pCC05y++JOG4sIEI2cLIU= 50 | github.com/CyCoreSystems/netdiscover v1.2.4 h1:/9e1KlFkn5LPUMXEwDbkVfXqMJrgCWbiiXkt7GEItFs= 51 | github.com/CyCoreSystems/netdiscover v1.2.4/go.mod h1:RN7msKC9tTuYeqyMPJSEOzVUruw6xYgisO4XJ25hjFw= 52 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 53 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 54 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 55 | github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= 56 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 57 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 58 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 59 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 60 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 61 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 62 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 63 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 64 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 65 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 66 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 67 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 68 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 69 | github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 70 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 71 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 72 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 73 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 74 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 75 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 76 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 77 | github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 78 | github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= 79 | github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= 80 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 81 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 82 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 83 | github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= 84 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 85 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 86 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 87 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 88 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 89 | github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= 90 | github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= 91 | github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 92 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 93 | github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 94 | github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= 95 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 96 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 97 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 98 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 99 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 100 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 101 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 102 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 103 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 104 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 105 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 106 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 107 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 108 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 109 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 110 | github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= 111 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 112 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 113 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 114 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 115 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 116 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 117 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 118 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 119 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 120 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 121 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 122 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 123 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 124 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 125 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 126 | github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 127 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 128 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 129 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 130 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 131 | github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= 132 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 133 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 134 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 135 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 136 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 137 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 138 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 139 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 140 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 141 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 142 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 143 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 144 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 145 | github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= 146 | github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 147 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 148 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 149 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 150 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 151 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 152 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 153 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 154 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 155 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 156 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 157 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 158 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 159 | github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 160 | github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 161 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 162 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= 163 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 164 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 165 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 166 | github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= 167 | github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= 168 | github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= 169 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 170 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 171 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 172 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 173 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 174 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 175 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 176 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 177 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 178 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 179 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 180 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 181 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 182 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 183 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 184 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 185 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 186 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 187 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 188 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 189 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 190 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 191 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 192 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 193 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 194 | github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= 195 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 196 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 197 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 198 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 199 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 200 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 201 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 202 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 203 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 204 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 205 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 206 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 207 | github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= 208 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 209 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 210 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 211 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 212 | github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= 213 | github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= 214 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 215 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 216 | github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= 217 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 218 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 219 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 220 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 221 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 222 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 223 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 224 | github.com/rotisserie/eris v0.4.1 h1:0IHaklBg2X5z10qpXS8F6eR3bUM2Xsbr1bH8W/eLUlo= 225 | github.com/rotisserie/eris v0.4.1/go.mod h1:lODN/gtqebxPHRbCcWeCYOE350FC2M3V/oAPT2wKxAU= 226 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 227 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 228 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 229 | github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= 230 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 231 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 232 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 233 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 234 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 235 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 236 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 237 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 238 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 239 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 240 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 241 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 242 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 243 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 244 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 245 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 246 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 247 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 248 | go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 249 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 250 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 251 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 252 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 253 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 254 | golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 255 | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 256 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 257 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 258 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 259 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 260 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 261 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 262 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 263 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 264 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 265 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 266 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 267 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 268 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 269 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 270 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 271 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 272 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 273 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 274 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 275 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 276 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 277 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 278 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 279 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 280 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 281 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 282 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 283 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 284 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 285 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 286 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 287 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 288 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 289 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 290 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 291 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 292 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 293 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 294 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 295 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 296 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 297 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 298 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 299 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 300 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 301 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 302 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 303 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 304 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 305 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 306 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 307 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 308 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 309 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 310 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 311 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 312 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 313 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 314 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 315 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 316 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 317 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 318 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 319 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 320 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 321 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 322 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 323 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 324 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 325 | golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 326 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 327 | golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= 328 | golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 329 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 330 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 331 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 332 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 333 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 334 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 335 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 336 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 337 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 338 | golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 339 | golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 340 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= 341 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 342 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 343 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 344 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 345 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 346 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 347 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 348 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 349 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 350 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 351 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 352 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 353 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 354 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 355 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 356 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 357 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 358 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 359 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 360 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 361 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 362 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 363 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 364 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 365 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 366 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 367 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 368 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 369 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 370 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 371 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 372 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 373 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 374 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 375 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 376 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 377 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 378 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 379 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 380 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 381 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 382 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 383 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 384 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 385 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 386 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 387 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 388 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 389 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 390 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 391 | golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 392 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 393 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 394 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 395 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 396 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 397 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c= 398 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 399 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 400 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= 401 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 402 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 403 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 404 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 405 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 406 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 407 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 408 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 409 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 410 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 411 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 412 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 413 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 414 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 415 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= 416 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 417 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 418 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 419 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 420 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 421 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 422 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 423 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 424 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 425 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 426 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 427 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 428 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 429 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 430 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 431 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 432 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 433 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 434 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 435 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 436 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 437 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 438 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 439 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 440 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 441 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 442 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 443 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 444 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 445 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 446 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 447 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 448 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 449 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 450 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 451 | golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 452 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 453 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 454 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 455 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 456 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 457 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 458 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 459 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 460 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 461 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 462 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 463 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 464 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 465 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 466 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 467 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 468 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 469 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 470 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 471 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 472 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 473 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 474 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 475 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 476 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 477 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 478 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 479 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 480 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 481 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 482 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 483 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 484 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 485 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 486 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 487 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 488 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 489 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 490 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 491 | google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= 492 | google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= 493 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 494 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 495 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 496 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 497 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 498 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 499 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 500 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 501 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 502 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 503 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 504 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 505 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 506 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 507 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 508 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 509 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 510 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 511 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 512 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 513 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 514 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 515 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 516 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 517 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 518 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 519 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 520 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 521 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 522 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 523 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 524 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 525 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 526 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 527 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 528 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 529 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 530 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 531 | google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 532 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 533 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 534 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 535 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 536 | google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 537 | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 538 | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 539 | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 540 | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 541 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 542 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 543 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 544 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 545 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 546 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 547 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 548 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 549 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 550 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 551 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 552 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 553 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 554 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 555 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 556 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 557 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 558 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 559 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 560 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 561 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 562 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 563 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 564 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 565 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 566 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 567 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 568 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 569 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 570 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 571 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 572 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 573 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 574 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 575 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 576 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= 577 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 578 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 579 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 580 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 581 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 582 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 583 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 584 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 585 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 586 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 587 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 588 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 589 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 590 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 591 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 592 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 593 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 594 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 595 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 596 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 597 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 598 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 599 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 600 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 601 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 602 | k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8= 603 | k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo= 604 | k8s.io/apimachinery v0.23.1 h1:sfBjlDFwj2onG0Ijx5C+SrAoeUscPrmghm7wHP+uXlo= 605 | k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno= 606 | k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ= 607 | k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0= 608 | k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= 609 | k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= 610 | k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= 611 | k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= 612 | k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= 613 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= 614 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= 615 | k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= 616 | k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= 617 | k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= 618 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 619 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 620 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 621 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= 622 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= 623 | sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= 624 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= 625 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= 626 | sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= 627 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= 628 | --------------------------------------------------------------------------------