mirror of
https://github.com/openfaas/faas.git
synced 2025-06-21 14:23:25 +00:00
Compare commits
65 Commits
openfaaslt
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
af936a14d8 | |||
910b8dae1b | |||
00613347f8 | |||
e0144b0573 | |||
4315101191 | |||
b4b7e2d450 | |||
0972fa6093 | |||
e44448c5dc | |||
bf63bbf88f | |||
a128df471f | |||
c26ec5221e | |||
8e1c34e222 | |||
21a8f0cec1 | |||
8d38b4befe | |||
1fc7bbce4e | |||
231e3ed426 | |||
fbc0ebdf4a | |||
4f9c61b5d2 | |||
a7d486eee6 | |||
b1ef4b49b7 | |||
f9245ebbb3 | |||
f3599f4699 | |||
3bafff7e09 | |||
e3171b49b0 | |||
e1c62f4875 | |||
b31419c8de | |||
004bbddadb | |||
88bedf78bd | |||
9d0436e511 | |||
c07bebbbc9 | |||
208b1b2235 | |||
0255a9480b | |||
f7f71f1497 | |||
03b6d6c01b | |||
efffd83990 | |||
06433e11c0 | |||
806585b434 | |||
32b828b25e | |||
bb163760ff | |||
1a00a55c77 | |||
bc2eeff467 | |||
887c804254 | |||
9da2ec244f | |||
8e711b3a0c | |||
4604271076 | |||
9fccc67b9c | |||
dc2a7a0c6e | |||
ce5ea178ec | |||
20b62e3cc9 | |||
2e8ec683eb | |||
774c7bb133 | |||
40bb3581b7 | |||
1ee7db994c | |||
2cdc7f3083 | |||
b87b96ae45 | |||
2e14a34243 | |||
88eea5f62e | |||
01841f605c | |||
6ed0ab71fb | |||
8f8a93d43f | |||
08279fb79b | |||
df3d59c918 | |||
d1022c410a | |||
5b77ad4af0 | |||
cc2f38938e |
42
.DEREK.yml
42
.DEREK.yml
@ -2,7 +2,7 @@ curators:
|
||||
- alexellis
|
||||
- LucasRoesler
|
||||
- viveksyngh
|
||||
- Waterdrips
|
||||
- nitishkumar71
|
||||
- rgee0
|
||||
- welteki
|
||||
|
||||
@ -13,43 +13,3 @@ features:
|
||||
- release_notes
|
||||
|
||||
contributing_url: https://github.com/openfaas/faas/blob/master/CONTRIBUTING.md
|
||||
|
||||
required_in_issues:
|
||||
- "## Why do you need this?"
|
||||
- "## Expected Behaviour"
|
||||
- "## Current Behaviour"
|
||||
- "## Steps to Reproduce (for bugs)"
|
||||
- "## Your Environment"
|
||||
|
||||
custom_messages:
|
||||
messages:
|
||||
- name: template
|
||||
value: |
|
||||
Your issue has been marked as *invalid* because you've deleted or removed questions from our issue template.
|
||||
|
||||
If you wish to participate in this community, then you need to follow guidelines set by the maintainers.
|
||||
|
||||
You will find the template in the .github folder, edit your issue and use the whole issue template, so that we can help you.
|
||||
|
||||
- name: propose
|
||||
value: |
|
||||
This project follows a contributing guide which states that all
|
||||
changes must be proposed with an Issue before being worked on.
|
||||
|
||||
Please raise an Issue and update your Pull Request to include
|
||||
the ID or link as part of the description.
|
||||
|
||||
Thank you for your contribution.
|
||||
|
||||
- name: test
|
||||
value: |
|
||||
This project follows a contributing guide which requires that
|
||||
all changes are tested before being merged. You should include
|
||||
worked examples that a maintainer can run to prove that the
|
||||
changes are good.
|
||||
|
||||
Screenshots and command line output are also accepted, but
|
||||
must show the positive, and negative cases, not just that
|
||||
what was added worked as you expected.
|
||||
|
||||
Thank you for your contribution.
|
||||
|
5
.github/ISSUE_TEMPLATE.md
vendored
5
.github/ISSUE_TEMPLATE.md
vendored
@ -7,6 +7,9 @@
|
||||
<!-- How is this affecting you? What task are you trying to accomplish? -->
|
||||
## Why do you need this?
|
||||
|
||||
## Who is this for?
|
||||
|
||||
What company is this for? Are you listed in the [ADOPTERS.md](https://github.com/openfaas/faas/blob/master/ADOPTERS.md) file?
|
||||
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
## Expected Behaviour
|
||||
@ -20,7 +23,7 @@
|
||||
|
||||
|
||||
## Are you a GitHub Sponsor (Yes/No?)
|
||||
<!--- Given this request for help, how are you supporting the project? -->
|
||||
<!-- Issues created by customers or monthly sponsors get priority -->
|
||||
|
||||
Check at: https://github.com/sponsors/openfaas
|
||||
- [ ] Yes
|
||||
|
66
.github/workflows/build.yml
vendored
66
.github/workflows/build.yml
vendored
@ -9,71 +9,37 @@ on:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
|
||||
build-gateway:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.17.x]
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Get TAG
|
||||
id: get_tag
|
||||
run: echo ::set-output name=TAG::latest-dev
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Get git commit
|
||||
id: get_git_commit
|
||||
run: echo "GIT_COMMIT=$(git rev-parse HEAD)" >> $GITHUB_ENV
|
||||
- name: Get version
|
||||
id: get_version
|
||||
run: echo "VERSION=$(git describe --tags --dirty)" >> $GITHUB_ENV
|
||||
- name: Get Repo Owner
|
||||
id: get_repo_owner
|
||||
run: echo ::set-output name=repo_owner::$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')
|
||||
run: echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" > $GITHUB_ENV
|
||||
|
||||
- name: Build ${{ matrix.svc }}
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: ./gateway
|
||||
file: ./gateway/Dockerfile
|
||||
outputs: "type=image,push=false"
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
build-args: |
|
||||
VERSION=${{ steps.get_tag.outputs.TAG }}
|
||||
VERSION=${{ env.TAG }}
|
||||
GIT_COMMIT=${{ github.sha }}
|
||||
tags: |
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/gateway:${{ steps.get_tag.outputs.TAG }}
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/gateway:${{ github.sha }}
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/gateway:latest
|
||||
|
||||
build-auth-plugins:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.17.x]
|
||||
svc: [
|
||||
basic-auth
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Get TAG
|
||||
id: get_tag
|
||||
run: echo ::set-output name=TAG::latest-dev
|
||||
- name: Get Repo Owner
|
||||
id: get_repo_owner
|
||||
run: echo ::set-output name=repo_owner::$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')
|
||||
- name: Build ${{ matrix.svc }}
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: ./auth/${{ matrix.svc }}
|
||||
file: ./auth/${{ matrix.svc }}/Dockerfile
|
||||
outputs: "type=image,push=false"
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
tags: |
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/${{ matrix.svc }}:${{ steps.get_tag.outputs.TAG }}
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/${{ matrix.svc }}:${{ github.sha }}
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/${{ matrix.svc }}:latest
|
||||
ghcr.io/${{ env.REPO_OWNER }}/gateway:${{ github.sha }}
|
||||
ghcr.io/${{ env.REPO_OWNER }}/gateway:latest
|
||||
|
85
.github/workflows/publish.yml
vendored
85
.github/workflows/publish.yml
vendored
@ -6,82 +6,57 @@ on:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
|
||||
publish-gateway:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.17.x]
|
||||
permissions:
|
||||
actions: read
|
||||
checks: write
|
||||
issues: read
|
||||
packages: write
|
||||
pull-requests: read
|
||||
repository-projects: read
|
||||
statuses: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
registry: ghcr.io
|
||||
|
||||
- name: Get TAG
|
||||
id: get_tag
|
||||
run: echo ::set-output name=TAG::${GITHUB_REF#refs/tags/}
|
||||
run: echo TAG=${GITHUB_REF#refs/tags/} >> $GITHUB_ENV
|
||||
|
||||
- name: Get git commit
|
||||
id: get_git_commit
|
||||
run: echo "GIT_COMMIT=$(git rev-parse HEAD)" >> $GITHUB_ENV
|
||||
- name: Get version
|
||||
id: get_version
|
||||
run: echo "VERSION=$(git describe --tags --dirty)" >> $GITHUB_ENV
|
||||
- name: Get Repo Owner
|
||||
id: get_repo_owner
|
||||
run: echo ::set-output name=repo_owner::$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')
|
||||
run: echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" > $GITHUB_ENV
|
||||
|
||||
- name: Publish ${{ matrix.svc }}
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: ./gateway
|
||||
file: ./gateway/Dockerfile
|
||||
outputs: "type=registry,push=true"
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
build-args: |
|
||||
VERSION=${{ steps.get_tag.outputs.TAG }}
|
||||
VERSION=${{ env.TAG }}
|
||||
GIT_COMMIT=${{ github.sha }}
|
||||
tags: |
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/gateway:${{ steps.get_tag.outputs.TAG }}
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/gateway:${{ github.sha }}
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/gateway:latest
|
||||
publish-auth-plugins:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.17.x]
|
||||
svc: [
|
||||
basic-auth
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Get TAG
|
||||
id: get_tag
|
||||
run: echo ::set-output name=TAG::${GITHUB_REF#refs/tags/}
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
registry: ghcr.io
|
||||
- name: Get Repo Owner
|
||||
id: get_repo_owner
|
||||
run: echo ::set-output name=repo_owner::$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')
|
||||
- name: Publish ${{ matrix.svc }}
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: ./auth/${{ matrix.svc }}
|
||||
file: ./auth/${{ matrix.svc }}/Dockerfile
|
||||
outputs: "type=registry,push=true"
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
tags: |
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/${{ matrix.svc }}:${{ steps.get_tag.outputs.TAG }}
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/${{ matrix.svc }}:${{ github.sha }}
|
||||
ghcr.io/${{ steps.get_repo_owner.outputs.repo_owner }}/${{ matrix.svc }}:latest
|
||||
ghcr.io/${{ env.REPO_OWNER }}/gateway:${{ github.sha }}
|
||||
ghcr.io/${{ env.REPO_OWNER }}/gateway:${{ env.TAG }}
|
||||
ghcr.io/${{ env.REPO_OWNER }}/gateway:latest
|
||||
|
93
ADOPTERS.md
93
ADOPTERS.md
@ -1,16 +1,29 @@
|
||||
# Adopters
|
||||
|
||||
This list shows adopters of OpenFaaS. If you're using OpenFaaS in some way, then please get in touch.
|
||||
This list shows adopters of OpenFaaS. If you're using OpenFaaS in some way, then please add your team and use-case to this file
|
||||
|
||||
## Further resources
|
||||
## How else can you support this project?
|
||||
|
||||
Become a GitHub Sponsor - either as an individual practitioner using or introducing OpenFaaS, or as a company, or both.
|
||||
### Individual or company sponsor
|
||||
|
||||
You can sponsor OpenFaaS on GitHub, most users do this using their personal accounts.
|
||||
|
||||
You'll show up as a sponsor on issues and PRs, which is going to make it more likely you'll get a timely response and help from the community.
|
||||
|
||||
* [Sponsor OpenFaaS on GitHub](https://github.com/openfaas/sponsors)
|
||||
|
||||
Support & OpenFaaS PRO
|
||||
### Help yourself, with the manual for OpenFaaS
|
||||
|
||||
* Buy [OpenFaaS PRO or Enterprise Subscription](https://openfaas.com/support) from OpenFaaS Ltd
|
||||
Help yourself learn and grow, whilst supporting us.
|
||||
|
||||
* [Serverless For Everyone Else](https://openfaas.gumroad.com/l/serverless-for-everyone-else) is the official manual for OpenFaaS, brimming with examples written in Node.js
|
||||
* [Everyday Go](https://openfaas.gumroad.com/l/everyday-golang) is the official reference material from the OpenFaaS founder Alex Ellis for learning Go, and writing functions in Go.
|
||||
|
||||
### Running OpenFaaS in production?
|
||||
|
||||
See how Community Edition (CE) which you are using now, compares to OpenFaaS Pro, which is designed for commercial use:
|
||||
|
||||
[Overview and comparison of OpenFaaS Pro](https://docs.openfaas.com/openfaas-pro/introduction/)
|
||||
|
||||
Tell us more:
|
||||
|
||||
@ -21,10 +34,26 @@ Tell us more:
|
||||
|
||||
* [3fs](https://3fs.si) - 3fs is using OpenFaaS for automating repetitive development tasks like automatic rebasing, vendoring of dependencies on merge requests and many other things that make our developers lives easier
|
||||
|
||||
* [BT](https://www.bt.com) - BT are using OpenFaaS to enable collaboration between data-scientists and developers. The teams are going from 3-years to build and deliver a PoC, to 3 months. See: [KubeCon video](https://www.youtube.com/watch?v=y77HlN2Fa-w)
|
||||
* [911 Security](https://www.911security.com/) - "We migrated our Python functions from AWS Lambda using automation, and now run them in airgapped environments for customers using OpenFaaS and arkade" - Scott Creager
|
||||
|
||||
* [Axa France](https://www.axa.fr) - Axa uses OpenFaaS for inference and predictions at scale using ML models - Pierre-Henri Gache
|
||||
|
||||
* [Baidu](https://baidu.com) - A team within Baidu provides ML models to customers which are hosted on OpenFaaS - He Sun.
|
||||
|
||||
* [BCubed Engineering](https://bcubed-corp.com) - "We use OpenFaaS to provide a serverless platform for our customers to run their code on."
|
||||
|
||||
* [Black.ai](https://black.ai) - video encoding, transcoding - object detection for CCTV using AI.
|
||||
|
||||
* [Corva.ai](https://corva.ai) - "Corva is an information-sharing, collaboration-driving, and productivity-powering solution for your Drilling, Completions, Geoscience, and Sustainability teams."
|
||||
|
||||
* [3fs](https://3fs.si) - 3fs is using OpenFaaS for automating repetitive development tasks like automatic rebasing, vendoring of dependencies on merge requests and many other things that make our developers lives easier
|
||||
|
||||
* [Baidu](https://baidu.com) - A team within Baidu provides ML models to customers which are hosted on OpenFaaS - He Sun.
|
||||
|
||||
* [Breu](https://breu.io) - Breu is using OpenFaaS to build an end user monitoring solution for hybrid cloud.
|
||||
|
||||
* [BT](https://www.bt.com) - BT are using OpenFaaS to enable collaboration between data-scientists and developers. The teams are going from 3-years to build and deliver a PoC, to 3 months. See: [KubeCon video](https://www.youtube.com/watch?v=y77HlN2Fa-w)
|
||||
|
||||
* [BulletProof](https://www.bulletproof.co.uk/) - Bulletproof are using OpenFaaS to build an on demand and scalable Vulnerability Scanning (VA) engine. Using OpenFaaS allows us to use compute resource efficiently yet maintain the ability to grow to meet customer scanning demands. We also like the ability to use pure docker containers to compose multiple scanning tools with different technologies into a single, coherent interface. This has reduced the time need to add new tools to the platform.
|
||||
|
||||
* [Citrix](https://www.citrix.com/en-gb/) - Citrix built out a closed-source multi-tenant functions platform and UI using OpenFaaS. It is used for testing hardware devices and for automated QA testing.
|
||||
@ -43,54 +72,94 @@ Tell us more:
|
||||
|
||||
* [Dragonchain](https://dragonchain.com/) - "At Dragonchain, we focus on creating a hybrid blockchain-as-a-service product, with integrations of OpenFaaS as our 'smart contract' platform, to be able to automatically run customer code based on interactions that occur on the blockchain. This allows us to be extremely flexible, as customers only have to create a docker container and give it to us in order to create a 'smart contract' which can have deep integrations with our blockchain itself.". Blog: [Dragonchain & OpenFaaS](https://dragonchain.com/blog/blockchain-as-a-service-at-scale-for-enterprise)
|
||||
|
||||
* [Edgedelta](https://www.edgedelta.com/) - "OpenFaaS powers parts of the "edge observability platform"
|
||||
* [Edge Delta](https://www.edgedelta.com/) - "OpenFaaS powers parts of the "edge observability platform"
|
||||
|
||||
* [First Baptist Church Carrollton](https://www.fbcc.us) - "We use faasd as the backend for a Slack bot connected to our internal Slack workspace. The bot was initially created to facilitate remote question and answer sessions at our church by allowing viewers of our live stream to text or email questions in, have a staff member ask their question in the room, and then allow the staff member to send a response back to the sender. The texting is facilitated by Twilio while the email is done by interacting with a Gmail account via IMAP and SMTP."
|
||||
|
||||
* [Fonix Telematics](https://fonixtelematics.com/) - "We are using OpenFaaS to build our new generation of APIs."
|
||||
|
||||
* [FTI Consulting](https://www.fticonsulting.com/) - "We've built a cloud-based analytical framework using Netflix Conductor for the workflow engine and OpenFaaS for our serverless function implementation, where each function can be called from a workflow. We've currently deployed several dozen OpenFaaS functions to our on-premise Kubernetes clusters" - Jason Cullison
|
||||
|
||||
* [GalaxyCard](https://www.galaxycard.in/) - "GalaxyCard is a happy user of OpenFaaS"
|
||||
|
||||
* [GMO Internet](https://www.gmo.jp/en/)
|
||||
|
||||
* [HelloSafe](https://hellosafe.ca/en/) - "HelloSafe is one of the leading website of financial products comparison in Canada. We're using OpenFaas on our production applications."
|
||||
|
||||
* [HM Planning Inspectorate](http://www.planninginspectorate.gov.uk) - HM Planning Inspectorate is the UK Government body responsible for dealing with planning appeals, national infrastructure planning applications, examinations of local plans and other specialist casework in England and Wales. OpenFaaS eased the communication between the new planning appeals website and the monolithic back-office application and allowed easy retries in the event of network failure.
|
||||
|
||||
* [HPE](https://www.hpe.com/) - HPE Ezmeral is a purpose-built, hybrid cloud platform for data science and analytics workloads.
|
||||
|
||||
* [Iconscout](https://iconscout.com) - e-commerce site for stock photography and icons. OpenFaaS is used to resize images and to bundle assets for customers.
|
||||
|
||||
* [Ingrooves](https://ingrooves.com) - Ingrooves is a global music distribution, tech & marketing company, and OpenFaaS is a key component in its finance system for report generation, event publishing, and data ingestion.
|
||||
|
||||
* [Infotechpartners](www.infotechpartners.be)
|
||||
|
||||
* [Intel.com](https://intel.com) - OpenFaaS is used within a commercial service and within the Open Source group for AI model serving.
|
||||
|
||||
* [Intraffic](https://www.intraffic.nl/) - "Using OpenFaaS for integration and callable AI/ML models for asset management."
|
||||
|
||||
* [Klar MX](https://klar.mx) - "Cuenta con Klar" - Klar provides access to credit cards in Mexico for those who have issues with credit history.
|
||||
|
||||
* [Kubiya.ai](https://kubiya.ai) - ChatGPT-like DevOps Virtual Assistant that runs OpenFaaS functions for custom infrastructure automation and management.
|
||||
|
||||
* [LivePerson](https://www.liveperson.com/) - LivePerson extended their chat platform by allowing customers to write functions to execute in client chat flows. See [KubeCon video](https://www.youtube.com/watch?v=bt06Z28uzPA)
|
||||
|
||||
* [Live Time Value (LTV) Co.](https://www.ltvco.com) - "Data is at the heart of what we do" - the data-science team at LTV use OpenFaaS to provide a scalable and cost-effective way to run their models in production.
|
||||
|
||||
* [metaspan](https://metaspan.com) - "End-to-end blockchain solutions". metaspan ported all api endpoints from monolith express.js/sails.js to openfaas micro-functions.
|
||||
|
||||
* [MoneyLion](https://www.moneylion.com/)
|
||||
|
||||
* [Naamio](https://naamio.cloud/) - "Naamio are providing an event-based serverless API to developers to enable rapid development of decentralized applications on the cloud. By providing progressive enhancement within the developer tools, OpenFaaS has enabled Naamio to go from clustered Docker container deployments with REST APIs using Kubernetes, to load balanced deployable functions over an open event queue interface. It was key to enabling a standard multilingual development kit across cloud providers."
|
||||
|
||||
* [Neoskop](https://www.neoskop.de) - Neoskop is using OpenFAAS in production to provide our developers with a self-service platform for backend functionality and thereby our customers agile and rapid feature development.
|
||||
|
||||
* [Nexylan](nexylan.com/) - "We are a French professional hoster that use OpenFaaS in dev and production inside our private extranet. We use OpenFaaS to split our historic monolith project and then simplify development/maintainability and speed up development times."
|
||||
|
||||
* [NGC](https://www.ngcsoftware.com/)
|
||||
|
||||
* [Northwestern Mutual](https://www.northwesternmutual.com/) - "OpenFaaS is a great platform and Alex and team are a great resource. They will work very diligently with your team to help you get the most out of OpenFaaS, and he will always be able to provide valuable insight into issues that a team might face while developing software for the cloud." Kieran Gordon
|
||||
|
||||
* [Optiv](https://optiv.com) - Cyber Security Solutions
|
||||
|
||||
* [Outsystems](https://outsystems.com) - "In my team, we're using OpenFaaS to help the orchestration of our CD pipelines. From a high-level perspective, we have a NATS cluster and the OpenFaaS functions subscribing to NATS topics and reacting to them. Our functions are doing some work related to the pipeline, like saving data to the database, sending Slack messages, or just returning something from the database." (Marco Alves)
|
||||
|
||||
* [P. A. Media Group](https://pamediagroup.com/) - "We use OpenFaaS to orchestrate Terraform and Jenkins jobs for our internal infrastructure provisioning" - Rob Stonham
|
||||
|
||||
* [Patchworks Integration Limited](https://www.wearepatchworks.com) - Ecommerce integrations made easy - functions provide custom enrichment for data and integrations with third-party APIs. Customers can provide their own PHP code to execute in a sandboxed environment.
|
||||
|
||||
* [PathfinderZA](https://www.pathfinderza.com) - PathfinderZA is an IOT security firm selling underground sensors that transmits warnings to users if a person or vehicle goes past it. We're using OpenFaas, with Dockerised functions written in Java (Quarkus) and Rust (Actix/Rocket-RS).
|
||||
|
||||
* [Pentium Network](https://www.pentium.network/)
|
||||
|
||||
* [PiperCI](https://piperci.dreamer-labs.net) - PiperCI is a task management framework that provides users with a standard library of CI/CD-centric tasks and the [OpenFaas](https://www.openfaas.com/) and [Kubernetes](https://kubernetes.io/) based infrastructure required to run them. PiperCI can be used in conjunction with existing CI/CD orchestrators like GitlabCI, Jenkins, TravisCI, or others to create a more scalable, robust, and functional CI/CD system.
|
||||
|
||||
* [Politics Rewired](https://www.politicsrewired.com/) - Politics Rewired uses OpenFaaS to enable organisation of political campaigns and sending of SMS message at scale using functions.
|
||||
|
||||
* [Press Association](https://www.pressassociation.com/) - Press Association is using OpenFaaS in development and production as part of our deployment pipeline.
|
||||
|
||||
* [Pypestream](https://www.pypestream.com) - "We have just migrated 50 of our customers from Kubeless, which is now deprecated to OpenFaaS" - Antoine Hamon
|
||||
|
||||
* [Ratehub](https://www.ratehub.ca) - Ratehub is Canada's leading personal finance comparison site. We're breaking apart our monolithic PHP and Java codebases into Node, PHP and Java OpenFaaS functions; there's not much that we don't plan on moving to FaaS!
|
||||
|
||||
* [Rapid Circle](https://www.rapidcircle.com) is using OpenFaaS within a Azure Kubernetes cluster to host a large amount of micro-services aiming at automating core activities of their Microsoft 365 Cloud Managed Services offering. Robustness, speed, scalable and simplicity have been major reasons to favor OpenFaaS over Azure Functions.
|
||||
|
||||
* [smashHit](https://smashhit.eu) - smashHit is a project funded by the European Union's Horizon 2020 research and innovation programme under grant agreement No. 871477. The objective of smashHit is to assure trusted and secure sharing of data streams from both personal and industrial platforms, needed to build sectorial and cross-sectorial services, by establishing a Framework for processing of data owner consent and legal rules (GDPR) and effective contracting, as well as joint security and privacy-preserving mechanisms. We are utilising OpenFaaS to support the need for scalable processing through the use of functions.
|
||||
|
||||
* [Sprucee](https://spruce.casa) - We use [faasd](https://github.com/openfaas/faasd) as part of our base Encryption as a Service platform which were manually managed docker containers. As NATS based platform we were able to scale to every size we want, but deployment takes many labor time as we need to deal with OS level and customer limitations. Now we can use "faas install/up" to accomplish 80% of deployment effort.
|
||||
|
||||
* [SURF](https://www.surf.nl) - [The Green Village](https://www.thegreenvillage.org/) is a living lab at Delft University of Technology. It is an experimental, real-life setting with the goal to accelerate innovation for a sustainable future. [SURF](https://www.surf.nl/), a cooperative association of Dutch educational and research institutions providing digital infrastructure and ICT services, has developed a [digital platform](https://youtu.be/_WYVzoBuWKk) for The Green Village that uses OpenFaaS to classify and sort incoming sensor data at scale.
|
||||
|
||||
* [SURFsara IoT Platform for Sensemakers](https://github.com/sensemakersamsterdam/sensemakers-iot-platform) - The SURFsara IoT Platform for Sensemakers is a platform for storing, monitoring, visualising and analyzing sensor data. It is a collaboration platform designed to host multiple projects carried by the Sensemakers community. In addition, there is a project dedicated to experimentation, available for everyone to use. All data within the platform is shared. OpenFaaS serverless functions give access to the platform through an HTTP entry point, take care of the metadata extraction and enable custom event-driven actions.
|
||||
|
||||
* [Surge](https://www.workwithsurge.com) - Lending Platform and Salesforce integrations
|
||||
|
||||
* [skyslope.com](https://skyslope.com) - "We process millions of documents per day and moved from AWS Lambda to Kubernetes. We estimate that OpenFaaS has saved us 60,000 USD each year over the past three years that we've been running it in our business" - Derrick Martinez
|
||||
|
||||
* [T-Mobile](https://www.t-mobile.com/) - T-Mobile is a global mobile network that provides mobile data, voice and text services to consumers and businesses.
|
||||
|
||||
* [Transmute Industries](https://www.transmute.industries/) - "At Transmute we use OpenFaaS to develop identity and access integrations leveraging decentralized identities that integrate with legacy IAM systems. OpenFaaS helps Transmute and our customers avoid vendor lock in, encourages modularity, and helps us rapidly develop and release integrations for customers."
|
||||
|
||||
* [Traversals](https://traversals.com/) - At Traversals, we use OpenFaaS for processing of incoming data. We take benefit from various programming languages available in OpenFaaS.
|
||||
@ -99,21 +168,23 @@ Tell us more:
|
||||
|
||||
* [Very Good Security](https://www.verygoodsecurity.com) - VGS uses OpenFaaS to build a solid foundation for the development, deployment, and execution of custom logic on customer payloads as part of their secure compute platform.
|
||||
|
||||
* [Vision Banco SAECA](https://www.visionbanco.com) - self-service home banking portal and asynchronous report/PDF generation. See: [KubeCon Video](https://www.youtube.com/watch?v=mPjI34qj5vU&t=1417s)
|
||||
|
||||
* [Virality](https://www.virality.de/)
|
||||
|
||||
* [Vision Banco SAECA](https://www.visionbanco.com) - self-service home banking portal and asynchronous report/PDF generation. See: [KubeCon Video](https://www.youtube.com/watch?v=mPjI34qj5vU&t=1417s)
|
||||
|
||||
* [VMware](https://vmware.com)
|
||||
* Used in "veba" VMware Event Broker Appliance to extend vSphere by adding event functionality. OpenFaaS functions and the vcenter-connector are used as an appliance.
|
||||
* CAS / vRA8 - The Cloud Automation Services product has an option to deploy "FaaS on-premises", this actually deploys OpenFaaS white-boxed / white-labelled. [CAS Write-up from Swisscom](https://ict.swisscom.ch/2019/08/cloud-automation-services-on-prem-faas-provider-for-vsphere/)
|
||||
* OpenFaaS is also repackaged as "Automation Extensibility" in the ["vRO" product](https://vnuggets.com/2019/08/16/cloud-assembly-extensibility-with-abx-faas-part1/). [See an example](https://vnuggets.com/2019/08/19/cloud-assembly-extensibility-with-abx-faas-part3/)
|
||||
|
||||
* [VNourdin](https://www.vnourdin.dev) - I am a French web developer working with the Jamstack, using 11ty and faasd. I started with faasd as I wanted to make it work on my small VPS, but as I do more and more projects relying on OpenFaaS, I'll probably switch to a K8s cluster to gain scalability.
|
||||
|
||||
* [Waylay](https://www.waylay.io) - We use OpenFaaS to deploy small snippets of code that can be combined in a low-code manner by our clients to do data orchestration and automation. Users of the platform also are able to deploy their own plugins (written in multiple languages), which also get deployed on OpenFaas.
|
||||
|
||||
* [Wireline.io](https://wireline.io) - portable functions that can run on any hardware, indexed through blockchain.
|
||||
|
||||
* [Yokogawa Electric](https://en.wikipedia.org/wiki/Yokogawa_Electric)
|
||||
|
||||
* [Ytel](https://www.ytel.com) - Ytel are a Google Cloud customer and deployed OpenFaaS vs. the vendor alternative due to its wide range of templates, Dockerfile support and easier access to services within the VPC. The Dockerfile template allowed for easy migration of existing code. The latency of transactions for customers during purchase process was reduced by offloading synchronous code to NATS which is built into OpenFaaS. OpenFaaS also allowed "hot path" code to be refactored from large services into multiple functions, to take advantage of horizontal scaling.
|
||||
|
||||
* [smashHit](https://smashhit.eu) - smashHit is a project funded by the European Union's Horizon 2020 research and innovation programme under grant agreement No. 871477. The objective of smashHit is to assure trusted and secure sharing of data streams from both personal and industrial platforms, needed to build sectorial and cross-sectorial services, by establishing a Framework for processing of data owner consent and legal rules (GDPR) and effective contracting, as well as joint security and privacy-preserving mechanisms. We are utilising OpenFaaS to support the need for scalable processing through the use of functions.
|
||||
|
||||
See the top of the file for how to participate.
|
||||
|
@ -385,13 +385,7 @@ The [community.md](https://github.com/openfaas/faas/blob/master/community.md) fi
|
||||
|
||||
### Roadmap
|
||||
|
||||
* See the [2019 Project Update](https://www.openfaas.com/blog/project-update/)
|
||||
|
||||
* Browse open issues in [openfaas/faas](https://github.com/openfaas/faas/issues)
|
||||
|
||||
* Join the [2020 Roadmap on Trello](https://trello.com/invite/b/5OpMyrBP/ade103a10ae1e38eb5d3eee7955260a9/2020-openfaas-roadmap)
|
||||
|
||||
For commercial users, please feel free to ask about support, backlog prioritisation and feature development. Email sales@openfaas.com.
|
||||
See also: [OpenFaaS Pro](https://docs.openfaas.com/openfaas-pro/introduction/)
|
||||
|
||||
## License
|
||||
|
||||
|
106
DEV.md
106
DEV.md
@ -1,106 +0,0 @@
|
||||
## Develop your own function
|
||||
|
||||
### Working on the API Gateway or Watchdog
|
||||
|
||||
To work on either of the FaaS Golang components checkout the "./build.sh" scripts and acompanying Dockerfiles.
|
||||
|
||||
* [Roadmap and Contributing](https://github.com/openfaas/faas/blob/master/ROADMAP.md)
|
||||
|
||||
### Creating a function
|
||||
|
||||
Functions run as Docker containers with the Watchdog component embedded to handle communication with the API Gateway.
|
||||
|
||||
You can find the [reference documentation for the Watchdog here](https://github.com/openfaas/faas/tree/master/watchdog).
|
||||
|
||||
**Markdown Parser**
|
||||
|
||||
This is the basis of a function which generates HTML from MarkDown:
|
||||
|
||||
```
|
||||
FROM golang:1.9.7
|
||||
RUN mkdir -p /go/src/app
|
||||
COPY handler.go /go/src/app
|
||||
WORKDIR /go/src/app
|
||||
RUN go get github.com/microcosm-cc/bluemonday && \
|
||||
go get github.com/russross/blackfriday
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
|
||||
|
||||
ADD https://github.com/openfaas/faas/releases/download/0.9.14/fwatchdog /usr/bin
|
||||
RUN chmod +x /usr/bin/fwatchdog
|
||||
|
||||
ENV fprocess="/go/src/app/app"
|
||||
|
||||
CMD ["/usr/bin/fwatchdog"]
|
||||
```
|
||||
|
||||
The base Docker container is not important, you just need to add the watchdog component and then set the fprocess to execute your binary at runtime.
|
||||
|
||||
Update the Docker stack with this:
|
||||
|
||||
```
|
||||
markdown:
|
||||
image: alexellis2/faas-markdownrender:latest
|
||||
labels:
|
||||
function: "true"
|
||||
networks:
|
||||
- functions
|
||||
```
|
||||
|
||||
**Word counter with busybox**
|
||||
|
||||
```
|
||||
FROM alpine:latest
|
||||
|
||||
ADD https://github.com/openfaas/faas/releases/download/0.9.14/fwatchdog /usr/bin
|
||||
RUN chmod +x /usr/bin/fwatchdog
|
||||
|
||||
ENV fprocess="wc"
|
||||
CMD ["fwatchdog"]
|
||||
```
|
||||
|
||||
Update your Docker stack with this definition:
|
||||
|
||||
```
|
||||
wordcount:
|
||||
image: alexellis2/faas-alpinefunction:latest
|
||||
labels:
|
||||
function: "true"
|
||||
networks:
|
||||
- functions
|
||||
environment:
|
||||
fprocess: "wc"
|
||||
```
|
||||
|
||||
**Tip:**
|
||||
|
||||
You can optimize Docker to cache getting the watchdog by using curl, instead of ADD.
|
||||
To do so, replace the related lines with:
|
||||
|
||||
```
|
||||
RUN apt-get update && apt-get install -y curl \
|
||||
&& curl -sL https://github.com/openfaas/faas/releases/download/0.9.14/fwatchdog > /usr/bin/fwatchdog \
|
||||
&& chmod +x /usr/bin/fwatchdog \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
```
|
||||
|
||||
or with the following for Alpine based images:
|
||||
|
||||
```
|
||||
RUN apk --no-cache add curl \
|
||||
&& curl -sL https://github.com/openfaas/faas/releases/download/0.9.14/fwatchdog > /usr/bin/fwatchdog \
|
||||
&& chmod +x /usr/bin/fwatchdog
|
||||
```
|
||||
|
||||
### Testing your function
|
||||
|
||||
You can test your function through a webbrowser against the UI portal on port 8080.
|
||||
|
||||
http://localhost:8080/
|
||||
|
||||
You can also invoke a function by name with curl:
|
||||
|
||||
```
|
||||
curl --data-binary @README.md http://localhost:8080/function/func_wordcount
|
||||
```
|
||||
|
20
README.md
20
README.md
@ -20,7 +20,7 @@ OpenFaaS® makes it easy for developers to deploy event-driven functions and
|
||||
* Portable: runs on existing hardware or public/private cloud by leveraging [Kubernetes](https://github.com/openfaas/faas-netes)
|
||||
* [CLI](http://github.com/openfaas/faas-cli) available with YAML format for templating and defining functions
|
||||
* Auto-scales as demand increases [including to zero](https://docs.openfaas.com/architecture/autoscaling/)
|
||||
* [Commercially supported distribution by the team behind OpenFaaS](https://openfaas.com/support/)
|
||||
* [Commercially supported Pro distribution by the team behind OpenFaaS](https://openfaas.com/pricing/)
|
||||
|
||||
**Want to dig deeper into OpenFaaS?**
|
||||
|
||||
@ -79,19 +79,21 @@ Official templates exist for many popular languages and are easily extensible wi
|
||||
package function
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/openfaas-incubator/go-function-sdk"
|
||||
handler "github.com/openfaas/templates-sdk/go-http"
|
||||
)
|
||||
|
||||
// Handle a function invocation
|
||||
func Handle(req handler.Request) (handler.Response, error) {
|
||||
var err error
|
||||
|
||||
message := fmt.Sprintf("Body: %s", string(req.Body))
|
||||
|
||||
return handler.Response{
|
||||
Body: []byte("Try us out today!"),
|
||||
Header: map[string][]string{
|
||||
"X-Served-By": []string{"openfaas.com"},
|
||||
},
|
||||
Body: []byte(message),
|
||||
StatusCode: http.StatusOK,
|
||||
}, err
|
||||
}
|
||||
```
|
||||
@ -151,9 +153,9 @@ Have you written a blog about OpenFaaS? Do you have a speaking event? Send a Pul
|
||||
|
||||
* [Read blogs/articles and find events about OpenFaaS](https://github.com/openfaas/faas/blob/master/community.md)
|
||||
|
||||
### Roadmap and contributing
|
||||
### Contributing
|
||||
|
||||
OpenFaaS is written in Golang and is MIT licensed - contributions are welcomed whether that means providing feedback, testing existing and new feature or hacking on the source.
|
||||
OpenFaaS Community Edition is written in Golang and is MIT licensed. Various types of contributions are welcomed whether that means providing feedback, testing existing and new feature or hacking on the source code.
|
||||
|
||||
#### How do I become a contributor?
|
||||
|
||||
|
34
ROADMAP.md
34
ROADMAP.md
@ -1,34 +0,0 @@
|
||||
# Roadmap
|
||||
|
||||
## GitHub projects / source code
|
||||
|
||||
You can find a detailed breakdown of the [openfaas](https://github.com/openfaas/) and [openfaas-incubator](https://github.com/openfaas-incubator/) organisations and projects [in the docs](https://docs.openfaas.com/contributing/get-started/).
|
||||
|
||||
## Feature overview
|
||||
|
||||
For an overview see [the docs](https://docs.openfaas.com/) or see a [feature comparison between OpenFaaS and OpenFaaS Cloud](https://docs.openfaas.com/openfaas-cloud/intro/).
|
||||
|
||||
### OpenFaaS
|
||||
|
||||
OpenFaaS is a platform for building Serverless Functions and/or deploying existing microservices. Any programming language or binary is supported with a range of [templates](https://github.com/openfaas/templates) available to help you get started.
|
||||
|
||||
The core services which make up OpenFaaS need to run on a Linux master, but Windows worker nodes can be added to your cluster to run Windows binaries and functions.
|
||||
|
||||
Platforms: the x86_64 platform has first class support, with 32-bit arm and 64-bit arm provided on a best-effort basis.
|
||||
|
||||
Orchestrators: there is official support for Kubernetes & faasd (containerd) with the community providing support for AWS Fargate, Hashicorp Nomad and others.
|
||||
|
||||
### OpenFaaS Cloud
|
||||
|
||||
OpenFaaS Cloud is a multi-user distribution of OpenFaaS with a built-in CI/CD pipeline, OAuth delegation, a dashboard and a git-based workflow with public/private GitHub and self-hosted GitLab.
|
||||
|
||||
## What is coming next?
|
||||
|
||||
Proposals and feature requests are tracked [on the 2020 Roadmap on Trello](https://trello.com/invite/b/5OpMyrBP/ade103a10ae1e38eb5d3eee7955260a9/2020-openfaas-roadmap) and through the GitHub issue tracker of each project in the two organisations.
|
||||
|
||||
* [openfaas](https://github.com/openfaas/)
|
||||
* [openfaas-incubator](https://github.com/openfaas-incubator/)
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING.md](https://github.com/openfaas/faas/blob/master/CONTRIBUTING.md).
|
@ -1 +1,2 @@
|
||||
theme: jekyll-theme-cayman
|
||||
theme: jekyll-theme-cayman
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
auth plugins
|
||||
============
|
||||
|
||||
Auth plugins must implement request checking on a HTTP port and path such as `:8080/validate`.
|
||||
|
||||
* Valid requests: return 2xx
|
||||
* Invalid requests: return non 2xx
|
||||
|
||||
It is up to the developer to pick whether a request body is required for validation. For strategies such as [Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication), headers are sufficient.
|
||||
|
||||
Plugins available:
|
||||
|
||||
* [basic-auth](./basic-auth/)
|
1
auth/basic-auth/.gitignore
vendored
1
auth/basic-auth/.gitignore
vendored
@ -1 +0,0 @@
|
||||
basic-auth
|
@ -1,45 +0,0 @@
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} ghcr.io/openfaas/license-check:0.4.0 as license-check
|
||||
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.17 as build
|
||||
|
||||
ENV GO111MODULE=off
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
ARG BUILDPLATFORM
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
COPY --from=license-check /license-check /usr/bin/
|
||||
|
||||
WORKDIR /go/src/handler
|
||||
COPY . .
|
||||
|
||||
# Run a gofmt and exclude all vendored code.
|
||||
|
||||
RUN license-check -path ./ --verbose=false "OpenFaaS Authors" "OpenFaaS Author(s)"
|
||||
|
||||
RUN test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*"))"
|
||||
|
||||
RUN CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go test -v ./...
|
||||
|
||||
RUN CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
|
||||
--ldflags "-s -w" -a -installsuffix cgo -o handler .
|
||||
|
||||
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.16.0 as ship
|
||||
# Add non-root user
|
||||
RUN addgroup -S app && adduser -S -g app app \
|
||||
&& mkdir -p /home/app \
|
||||
&& chown app /home/app
|
||||
|
||||
WORKDIR /home/app
|
||||
|
||||
COPY --from=build /go/src/handler/handler .
|
||||
|
||||
RUN chown -R app /home/app
|
||||
|
||||
USER app
|
||||
|
||||
WORKDIR /home/app
|
||||
|
||||
CMD ["./handler"]
|
@ -1,13 +0,0 @@
|
||||
basic-auth
|
||||
============
|
||||
|
||||
This component implements [Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) as an OpenFaaS authentication plug-in.
|
||||
|
||||
To run this plugin you will need to create and bind a secret named `basic-auth-user` and `basic-auth-password`
|
||||
|
||||
| Option | Usage |
|
||||
|---------------------------------|--------------|
|
||||
| `port` | Set the HTTP port |
|
||||
| `secret_mount_path` | It is recommended that this is set to `/var/openfaas/secrets` |
|
||||
| `user_filename` | File to read from disk for username, default empty |
|
||||
| `pass_filename` | File to read from disk for username, default empty |
|
@ -1,8 +0,0 @@
|
||||
module github.com/openfaas/faas/auth/basic-auth
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/openfaas/faas-provider v0.18.9
|
||||
github.com/pkg/errors v0.8.1
|
||||
)
|
@ -1,27 +0,0 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/openfaas/faas-provider v0.18.9 h1:nHPlq9PYLGLuyhuXfASlBPOvXiZC/fJqHOr6m+0Fn1s=
|
||||
github.com/openfaas/faas-provider v0.18.9/go.mod h1:S217qfIaMrv+XKJxgbhBzJzCfyFvoIF+BvYdDo6XIDQ=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
go.uber.org/goleak v1.1.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
@ -1,81 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/openfaas/faas-provider/auth"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
port := 8080
|
||||
|
||||
if val, ok := os.LookupEnv("port"); ok {
|
||||
intOut, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, fmt.Sprintf("value of `port`: %s, not a valid port", val)))
|
||||
}
|
||||
port = intOut
|
||||
}
|
||||
|
||||
s := &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", port),
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20, // Max header of 1MB
|
||||
}
|
||||
|
||||
credentialsReader := auth.ReadBasicAuthFromDisk{
|
||||
SecretMountPath: os.Getenv("secret_mount_path"),
|
||||
UserFilename: os.Getenv("user_filename"),
|
||||
PasswordFilename: os.Getenv("pass_filename"),
|
||||
}
|
||||
|
||||
credentials, err := credentialsReader.Read()
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "unable to read basic auth credentials, check `secret_mount_path`"))
|
||||
}
|
||||
|
||||
authHandler := auth.DecorateWithBasicAuth(func(w http.ResponseWriter, r *http.Request) {
|
||||
}, credentials)
|
||||
http.HandleFunc("/validate", makeLogger(authHandler))
|
||||
|
||||
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
log.Printf("Listening on: %d\n", port)
|
||||
log.Fatal(s.ListenAndServe())
|
||||
}
|
||||
|
||||
func makeLogger(next http.Handler) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
next.ServeHTTP(rr, r)
|
||||
log.Printf("Validated request %d.\n", rr.Code)
|
||||
|
||||
resHeader := rr.Header()
|
||||
copyHeaders(w.Header(), &resHeader)
|
||||
|
||||
w.WriteHeader(rr.Code)
|
||||
if rr.Body != nil {
|
||||
w.Write(rr.Body.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func copyHeaders(destination http.Header, source *http.Header) {
|
||||
for k, v := range *source {
|
||||
vClone := make([]string, len(v))
|
||||
copy(vClone, v)
|
||||
(destination)[k] = vClone
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_makeLogger_CopiesResponseHeaders(t *testing.T) {
|
||||
handler := http.HandlerFunc(makeLogger(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Unit-Test", "true")
|
||||
})))
|
||||
|
||||
s := httptest.NewServer(handler)
|
||||
defer s.Close()
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
got := rr.Header().Get("X-Unit-Test")
|
||||
want := "true"
|
||||
if want != got {
|
||||
t.Errorf("Header X-Unit-Test, want: %s, got %s", want, got)
|
||||
}
|
||||
|
||||
}
|
21
auth/basic-auth/vendor/github.com/openfaas/faas-provider/LICENSE
generated
vendored
21
auth/basic-auth/vendor/github.com/openfaas/faas-provider/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Alex Ellis
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
30
auth/basic-auth/vendor/github.com/openfaas/faas-provider/auth/basic_auth.go
generated
vendored
30
auth/basic-auth/vendor/github.com/openfaas/faas-provider/auth/basic_auth.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
// Copyright (c) OpenFaaS Author(s). All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// DecorateWithBasicAuth enforces basic auth as a middleware with given credentials
|
||||
func DecorateWithBasicAuth(next http.HandlerFunc, credentials *BasicAuthCredentials) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
user, password, ok := r.BasicAuth()
|
||||
|
||||
const noMatch = 0
|
||||
if !ok ||
|
||||
user != credentials.User ||
|
||||
subtle.ConstantTimeCompare([]byte(credentials.Password), []byte(password)) == noMatch {
|
||||
|
||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte("invalid credentials"))
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
66
auth/basic-auth/vendor/github.com/openfaas/faas-provider/auth/credentials.go
generated
vendored
66
auth/basic-auth/vendor/github.com/openfaas/faas-provider/auth/credentials.go
generated
vendored
@ -1,66 +0,0 @@
|
||||
// Copyright (c) OpenFaaS Author(s). All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BasicAuthCredentials for credentials
|
||||
type BasicAuthCredentials struct {
|
||||
User string
|
||||
Password string
|
||||
}
|
||||
|
||||
type ReadBasicAuth interface {
|
||||
Read() (*BasicAuthCredentials, error)
|
||||
}
|
||||
|
||||
type ReadBasicAuthFromDisk struct {
|
||||
SecretMountPath string
|
||||
|
||||
UserFilename string
|
||||
|
||||
PasswordFilename string
|
||||
}
|
||||
|
||||
func (r *ReadBasicAuthFromDisk) Read() (*BasicAuthCredentials, error) {
|
||||
var credentials *BasicAuthCredentials
|
||||
|
||||
if len(r.SecretMountPath) == 0 {
|
||||
return nil, fmt.Errorf("invalid SecretMountPath specified for reading secrets")
|
||||
}
|
||||
|
||||
userKey := "basic-auth-user"
|
||||
if len(r.UserFilename) > 0 {
|
||||
userKey = r.UserFilename
|
||||
}
|
||||
|
||||
passwordKey := "basic-auth-password"
|
||||
if len(r.PasswordFilename) > 0 {
|
||||
passwordKey = r.PasswordFilename
|
||||
}
|
||||
|
||||
userPath := path.Join(r.SecretMountPath, userKey)
|
||||
user, userErr := ioutil.ReadFile(userPath)
|
||||
if userErr != nil {
|
||||
return nil, fmt.Errorf("unable to load %s", userPath)
|
||||
}
|
||||
|
||||
userPassword := path.Join(r.SecretMountPath, passwordKey)
|
||||
password, passErr := ioutil.ReadFile(userPassword)
|
||||
if passErr != nil {
|
||||
return nil, fmt.Errorf("Unable to load %s", userPassword)
|
||||
}
|
||||
|
||||
credentials = &BasicAuthCredentials{
|
||||
User: strings.TrimSpace(string(user)),
|
||||
Password: strings.TrimSpace(string(password)),
|
||||
}
|
||||
|
||||
return credentials, nil
|
||||
}
|
24
auth/basic-auth/vendor/github.com/pkg/errors/.gitignore
generated
vendored
24
auth/basic-auth/vendor/github.com/pkg/errors/.gitignore
generated
vendored
@ -1,24 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
15
auth/basic-auth/vendor/github.com/pkg/errors/.travis.yml
generated
vendored
15
auth/basic-auth/vendor/github.com/pkg/errors/.travis.yml
generated
vendored
@ -1,15 +0,0 @@
|
||||
language: go
|
||||
go_import_path: github.com/pkg/errors
|
||||
go:
|
||||
- 1.4.x
|
||||
- 1.5.x
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
23
auth/basic-auth/vendor/github.com/pkg/errors/LICENSE
generated
vendored
23
auth/basic-auth/vendor/github.com/pkg/errors/LICENSE
generated
vendored
@ -1,23 +0,0 @@
|
||||
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
52
auth/basic-auth/vendor/github.com/pkg/errors/README.md
generated
vendored
52
auth/basic-auth/vendor/github.com/pkg/errors/README.md
generated
vendored
@ -1,52 +0,0 @@
|
||||
# errors [](https://travis-ci.org/pkg/errors) [](https://ci.appveyor.com/project/davecheney/errors/branch/master) [](http://godoc.org/github.com/pkg/errors) [](https://goreportcard.com/report/github.com/pkg/errors) [](https://sourcegraph.com/github.com/pkg/errors?badge)
|
||||
|
||||
Package errors provides simple error handling primitives.
|
||||
|
||||
`go get github.com/pkg/errors`
|
||||
|
||||
The traditional error handling idiom in Go is roughly akin to
|
||||
```go
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
|
||||
|
||||
## Adding context to an error
|
||||
|
||||
The errors.Wrap function returns a new error that adds context to the original error. For example
|
||||
```go
|
||||
_, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read failed")
|
||||
}
|
||||
```
|
||||
## Retrieving the cause of an error
|
||||
|
||||
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
|
||||
```go
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
```
|
||||
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
|
||||
```go
|
||||
switch err := errors.Cause(err).(type) {
|
||||
case *MyError:
|
||||
// handle specifically
|
||||
default:
|
||||
// unknown error
|
||||
}
|
||||
```
|
||||
|
||||
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
|
||||
|
||||
Before proposing a change, please discuss your change by raising an issue.
|
||||
|
||||
## License
|
||||
|
||||
BSD-2-Clause
|
32
auth/basic-auth/vendor/github.com/pkg/errors/appveyor.yml
generated
vendored
32
auth/basic-auth/vendor/github.com/pkg/errors/appveyor.yml
generated
vendored
@ -1,32 +0,0 @@
|
||||
version: build-{build}.{branch}
|
||||
|
||||
clone_folder: C:\gopath\src\github.com\pkg\errors
|
||||
shallow_clone: true # for startup speed
|
||||
|
||||
environment:
|
||||
GOPATH: C:\gopath
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
# http://www.appveyor.com/docs/installed-software
|
||||
install:
|
||||
# some helpful output for debugging builds
|
||||
- go version
|
||||
- go env
|
||||
# pre-installed MinGW at C:\MinGW is 32bit only
|
||||
# but MSYS2 at C:\msys64 has mingw64
|
||||
- set PATH=C:\msys64\mingw64\bin;%PATH%
|
||||
- gcc --version
|
||||
- g++ --version
|
||||
|
||||
build_script:
|
||||
- go install -v ./...
|
||||
|
||||
test_script:
|
||||
- set PATH=C:\gopath\bin;%PATH%
|
||||
- go test -v ./...
|
||||
|
||||
#artifacts:
|
||||
# - path: '%GOPATH%\bin\*.exe'
|
||||
deploy: off
|
282
auth/basic-auth/vendor/github.com/pkg/errors/errors.go
generated
vendored
282
auth/basic-auth/vendor/github.com/pkg/errors/errors.go
generated
vendored
@ -1,282 +0,0 @@
|
||||
// Package errors provides simple error handling primitives.
|
||||
//
|
||||
// The traditional error handling idiom in Go is roughly akin to
|
||||
//
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// which when applied recursively up the call stack results in error reports
|
||||
// without context or debugging information. The errors package allows
|
||||
// programmers to add context to the failure path in their code in a way
|
||||
// that does not destroy the original value of the error.
|
||||
//
|
||||
// Adding context to an error
|
||||
//
|
||||
// The errors.Wrap function returns a new error that adds context to the
|
||||
// original error by recording a stack trace at the point Wrap is called,
|
||||
// together with the supplied message. For example
|
||||
//
|
||||
// _, err := ioutil.ReadAll(r)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "read failed")
|
||||
// }
|
||||
//
|
||||
// If additional control is required, the errors.WithStack and
|
||||
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||
// operations: annotating an error with a stack trace and with a message,
|
||||
// respectively.
|
||||
//
|
||||
// Retrieving the cause of an error
|
||||
//
|
||||
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||
// preceding error. Depending on the nature of the error it may be necessary
|
||||
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||
// for inspection. Any error value which implements this interface
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||
// the topmost error that does not implement causer, which is assumed to be
|
||||
// the original cause. For example:
|
||||
//
|
||||
// switch err := errors.Cause(err).(type) {
|
||||
// case *MyError:
|
||||
// // handle specifically
|
||||
// default:
|
||||
// // unknown error
|
||||
// }
|
||||
//
|
||||
// Although the causer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// Formatted printing of errors
|
||||
//
|
||||
// All error values returned from this package implement fmt.Formatter and can
|
||||
// be formatted by the fmt package. The following verbs are supported:
|
||||
//
|
||||
// %s print the error. If the error has a Cause it will be
|
||||
// printed recursively.
|
||||
// %v see %s
|
||||
// %+v extended format. Each Frame of the error's StackTrace will
|
||||
// be printed in detail.
|
||||
//
|
||||
// Retrieving the stack trace of an error or wrapper
|
||||
//
|
||||
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||
// invoked. This information can be retrieved with the following interface:
|
||||
//
|
||||
// type stackTracer interface {
|
||||
// StackTrace() errors.StackTrace
|
||||
// }
|
||||
//
|
||||
// The returned errors.StackTrace type is defined as
|
||||
//
|
||||
// type StackTrace []Frame
|
||||
//
|
||||
// The Frame type represents a call site in the stack trace. Frame supports
|
||||
// the fmt.Formatter interface that can be used for printing information about
|
||||
// the stack trace of this error. For example:
|
||||
//
|
||||
// if err, ok := err.(stackTracer); ok {
|
||||
// for _, f := range err.StackTrace() {
|
||||
// fmt.Printf("%+s:%d", f)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Although the stackTracer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// See the documentation for Frame.Format for more details.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// New returns an error with the supplied message.
|
||||
// New also records the stack trace at the point it was called.
|
||||
func New(message string) error {
|
||||
return &fundamental{
|
||||
msg: message,
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string
|
||||
// as a value that satisfies error.
|
||||
// Errorf also records the stack trace at the point it was called.
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
return &fundamental{
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// fundamental is an error that has a message and a stack, but no caller.
|
||||
type fundamental struct {
|
||||
msg string
|
||||
*stack
|
||||
}
|
||||
|
||||
func (f *fundamental) Error() string { return f.msg }
|
||||
|
||||
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
io.WriteString(s, f.msg)
|
||||
f.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, f.msg)
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", f.msg)
|
||||
}
|
||||
}
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
// If err is nil, WithStack returns nil.
|
||||
func WithStack(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
type withStack struct {
|
||||
error
|
||||
*stack
|
||||
}
|
||||
|
||||
func (w *withStack) Cause() error { return w.error }
|
||||
|
||||
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v", w.Cause())
|
||||
w.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, w.Error())
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap returns an error annotating err with a stack trace
|
||||
// at the point Wrap is called, and the supplied message.
|
||||
// If err is nil, Wrap returns nil.
|
||||
func Wrap(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace
|
||||
// at the point Wrapf is called, and the format specifier.
|
||||
// If err is nil, Wrapf returns nil.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
func WithMessage(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
type withMessage struct {
|
||||
cause error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
|
||||
func (w *withMessage) Cause() error { return w.cause }
|
||||
|
||||
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||
io.WriteString(s, w.msg)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's', 'q':
|
||||
io.WriteString(s, w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Cause returns the underlying cause of the error, if possible.
|
||||
// An error value has a cause if it implements the following
|
||||
// interface:
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// If the error does not implement Cause, the original error will
|
||||
// be returned. If the error is nil, nil will be returned without further
|
||||
// investigation.
|
||||
func Cause(err error) error {
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
for err != nil {
|
||||
cause, ok := err.(causer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = cause.Cause()
|
||||
}
|
||||
return err
|
||||
}
|
147
auth/basic-auth/vendor/github.com/pkg/errors/stack.go
generated
vendored
147
auth/basic-auth/vendor/github.com/pkg/errors/stack.go
generated
vendored
@ -1,147 +0,0 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Frame represents a program counter inside a stack frame.
|
||||
type Frame uintptr
|
||||
|
||||
// pc returns the program counter for this frame;
|
||||
// multiple frames may have the same PC value.
|
||||
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||
|
||||
// file returns the full path to the file that contains the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) file() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
file, _ := fn.FileLine(f.pc())
|
||||
return file
|
||||
}
|
||||
|
||||
// line returns the line number of source code of the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) line() int {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return 0
|
||||
}
|
||||
_, line := fn.FileLine(f.pc())
|
||||
return line
|
||||
}
|
||||
|
||||
// Format formats the frame according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s source file
|
||||
// %d source line
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+s function name and path of source file relative to the compile time
|
||||
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||
// %+v equivalent to %+s:%d
|
||||
func (f Frame) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
pc := f.pc()
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
io.WriteString(s, "unknown")
|
||||
} else {
|
||||
file, _ := fn.FileLine(pc)
|
||||
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
|
||||
}
|
||||
default:
|
||||
io.WriteString(s, path.Base(f.file()))
|
||||
}
|
||||
case 'd':
|
||||
fmt.Fprintf(s, "%d", f.line())
|
||||
case 'n':
|
||||
name := runtime.FuncForPC(f.pc()).Name()
|
||||
io.WriteString(s, funcname(name))
|
||||
case 'v':
|
||||
f.Format(s, 's')
|
||||
io.WriteString(s, ":")
|
||||
f.Format(s, 'd')
|
||||
}
|
||||
}
|
||||
|
||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||
type StackTrace []Frame
|
||||
|
||||
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s lists source files for each Frame in the stack
|
||||
// %v lists the source file and line number for each Frame in the stack
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
for _, f := range st {
|
||||
fmt.Fprintf(s, "\n%+v", f)
|
||||
}
|
||||
case s.Flag('#'):
|
||||
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||
default:
|
||||
fmt.Fprintf(s, "%v", []Frame(st))
|
||||
}
|
||||
case 's':
|
||||
fmt.Fprintf(s, "%s", []Frame(st))
|
||||
}
|
||||
}
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
func (s *stack) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case st.Flag('+'):
|
||||
for _, pc := range *s {
|
||||
f := Frame(pc)
|
||||
fmt.Fprintf(st, "\n%+v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stack) StackTrace() StackTrace {
|
||||
f := make([]Frame, len(*s))
|
||||
for i := 0; i < len(f); i++ {
|
||||
f[i] = Frame((*s)[i])
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func callers() *stack {
|
||||
const depth = 32
|
||||
var pcs [depth]uintptr
|
||||
n := runtime.Callers(3, pcs[:])
|
||||
var st stack = pcs[0:n]
|
||||
return &st
|
||||
}
|
||||
|
||||
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||
func funcname(name string) string {
|
||||
i := strings.LastIndex(name, "/")
|
||||
name = name[i+1:]
|
||||
i = strings.Index(name, ".")
|
||||
return name[i+1:]
|
||||
}
|
6
auth/basic-auth/vendor/modules.txt
vendored
6
auth/basic-auth/vendor/modules.txt
vendored
@ -1,6 +0,0 @@
|
||||
# github.com/openfaas/faas-provider v0.18.9
|
||||
## explicit; go 1.16
|
||||
github.com/openfaas/faas-provider/auth
|
||||
# github.com/pkg/errors v0.8.1
|
||||
## explicit
|
||||
github.com/pkg/errors
|
50
community.md
50
community.md
@ -52,7 +52,6 @@ It would be great to hear from you especially if you have any of the above and w
|
||||
| Title | Show | Date |
|
||||
|---------------------------------------------------------------------|--------------|----------|
|
||||
| [The Cube Interview - Monetising Open Source at KubeCon Valencia](https://www.youtube.com/watch?v=iyMIF4olLWI) | the Cube | 19-May-2022 |
|
||||
|
||||
| ["Balancing OSS Sacrifice with Success"](https://github.com/readme/alex-ellis) | GitHub ReadME program | 04-Sep-2020 |
|
||||
| [Episode #116 Independent Open Source, with Alex Ellis](https://kubernetespodcast.com/episode/116-independent-open-source/) | Kubernetes Podcast by Google | 12-Aug-2020 |
|
||||
| [The explosive growth of CNCF, what is Kubernetes and independent open source](https://blog.newrelic.com/engineering/observy-mcobservface-episode-no-2-alex-ellis/) | Observy McObservface | 29-07-2020 |
|
||||
@ -85,18 +84,55 @@ It would be great to hear from you especially if you have any of the above and w
|
||||
| [Digital Transformation of Vision Banco Paraguay with Serverless Functions @ KubeCon](https://kccna18.sched.com/event/GraO/digital-transformation-of-vision-banco-paraguay-with-serverless-functions-alex-ellis-vmware-patricio-diaz-vision-banco-saeca) | Alex Ellis & Patricio Diaz | 13-Dec-2018 |
|
||||
| [Introducing "faas" - Cool Hacks Keynote at Dockercon 2017](https://blog.docker.com/2017/04/dockercon-2017-mobys-cool-hack-sessions/) | Alex Ellis | 04-April-2017 |
|
||||
|
||||
### 2022
|
||||
### 2023
|
||||
|
||||
#### Blog posts and write-ups 2022
|
||||
#### Blog posts, write-ups and videos 2023
|
||||
|
||||
[Back to top](#openfaas-community)
|
||||
|
||||
| Blog/repo name and description | Author | Site | Date |
|
||||
| Blog/video/repo name and description | Author | Site | Date |
|
||||
|-------------------------------------------------------------------------|--------------|----------|-------------|
|
||||
| [Building OpenFaaS Serverless function to detect weather using OpenWeatherMap and Python](https://www.faizanbashir.me/building-openfaas-serverless-function-to-detect-weather-using-openweathermap-and-python) | Faizan Bashir | faizanbashir.me | 02-Apr-2023 |
|
||||
| [Fine-tuning the cold-start in OpenFaaS ](https://www.openfaas.com/blog/fine-tuning-the-cold-start/) | Alex Ellis | openfaas.com | 28-Mar-2023 |
|
||||
| [How do changes to the Docker Hub affect OpenFaaS?](https://www.openfaas.com/blog/how-does-docker-hub-affect-openfaas/) | Alex Ellis | openfaas.com | 20-Mar-2023 |
|
||||
| [Cluster auto-scaling with DigitalOcean Kubernetes and OpenFaaS](https://www.openfaas.com/blog/cluster-autoscaling-with-digitalocean/) | Alex Ellis | openfaas.com | 16-Mar-2023 |
|
||||
| [Import leads from Google Forms into your CRM with functions](https://www.openfaas.com/blog/import-leads-from-google-forms-to-crm/) | Alex Ellis | openfaas.com | 02-Mar-2023 |
|
||||
| [Using OpenFaaS on AKS](https://learn.microsoft.com/en-us/azure/aks/openfaas) | Various | learn.microsoft.com | 27-Feb-2023 |
|
||||
| [How to integrate OpenFaaS functions with managed AWS services](https://www.openfaas.com/blog/integrate-openfaas-with-managed-aws-services/) | Han Verstraete | openfaas.com | 19-Jan-2023 |
|
||||
|
||||
### 2022
|
||||
|
||||
#### Blog posts, write-ups and videos 2022
|
||||
|
||||
[Back to top](#openfaas-community)
|
||||
|
||||
| Blog/video/repo name and description | Author | Site | Date |
|
||||
|-------------------------------------------------------------------------|--------------|----------|-------------|
|
||||
| [Trigger OpenFaaS functions from PostgreSQL with AWS Aurora](https://www.openfaas.com/blog/trigger-functions-from-postgres/) | Han Verstraete | openfaas.com | 16-Dec-2022 |
|
||||
| [Introducing our new Python template for production](https://www.openfaas.com/blog/openfaas-pro-python-template/) | Han Verstraete | openfaas.com | 06-Dec-2022 |
|
||||
| [Deploy Serverless Function on k3s/Kubernetes with OpenFaaS (x86/Arm, Linux VM, Go)](https://www.youtube.com/watch?v=-8MrDWg6K6s) | David Hwang | youtube.com | 09-Nov-2022 |
|
||||
| [Rethinking Auto-scaling for OpenFaaS](https://www.openfaas.com/blog/autoscaling-functions/) | Han Verstraete | openfaas.com | 05-Nov-2022 |
|
||||
| [Custom health and readiness checks for your OpenFaaS Functions](https://www.openfaas.com/blog/health-and-readiness-for-functions/) | Alex Ellis | openfaas.com | 26-Oct-2022 |
|
||||
| [Generate PDFs at scale on Kubernetes using OpenFaaS and Puppeteer](https://www.openfaas.com/blog/pdf-generation-at-scale-on-kubernetes/) | Han Verstraete | openfaas.com | 06-Oct-2022 |
|
||||
| [Eliminate vendor locking of Serverless workloads with OpenFaaS](https://awstip.com/eliminate-vendor-lock-in-of-serverless-workloads-with-openfaas-474807383ce1) | Meher Chaitanya | medium.com | 06-Oct-2022 |
|
||||
| [Use the Serverless Function Method to Build a Machine Learning Microservice System](https://blog.infuseai.io/use-serverless-function-method-to-build-a-ml-microservice-system-a108f3f2c1c) | SimonLiu | blog.infuseai.io | 30-Aug-2022 |
|
||||
| [Go Functions as a Service With Kubernetes and OpenFaaS](https://dominikbraun.io/blog/go-functions-as-a-service-with-kubernetes-and-openfaas/) | Dominik Braun | dominikbraun.io | 24-Aug-2022 |
|
||||
| [Exploring the Fan out and Fan in pattern with OpenFaaS](https://www.openfaas.com/blog/fan-out-and-back-in-using-functions/) | Han Verstraete | openfaas.com | 22-Aug-2022 |
|
||||
| [Finding Raspberry Pis with Raspberry Pis](https://www.openfaas.com/blog/searching-for-raspberrypi/) | Alex Ellis | openfaas.com | 08-Aug-2022 |
|
||||
| [The Next Generation of Queuing: JetStream for OpenFaaS](https://www.openfaas.com/blog/jetstream-for-openfaas/) | Han Verstraete | openfaas.com | 21-Jul-2022 |
|
||||
| [How to update your OpenFaaS functions automatically with the Argo CD Image Updater](https://www.openfaas.com/blog/argocd-image-updater-for-functions/) | Han Verstraete | openfaas.com | 04-Jul-2022 |
|
||||
| [How to build functions from source code with the Function Builder API](https://www.openfaas.com/blog/how-to-build-via-api/) | Han Verstraete | openfaas.com | 23-Jun-2022 |
|
||||
| [OpenFaaS First Function](https://rpi4cluster.com/k3s/k3s-openfaas-function/) | Vlado Portos | rpi4cluster.com | 22-Jun-2022 |
|
||||
| [OpenFaaS](https://rpi4cluster.com/k3s/k3s-openfaas/) | Vlado Portos | rpi4cluster.com | 22-Jun-2022 |
|
||||
| [How to package OpenFaaS functions with Helm](https://www.openfaas.com/blog/howto-package-functions-with-helm/) | Han Verstraete | openfaas.com | 09-Jun-2022 |
|
||||
| [The Event-Driven Edge with OpenFaaS](https://www.openfaas.com/blog/eventdriven-edge/) | Han Verstraete | openfaas.com | 01-Jun-2022 |
|
||||
| [Running faasd on Azure Arm-based Virtual Machines](https://blog.ediri.io/running-faasd-on-azure-arm-based-virtual-machines) | Engin Diri | blog.ediri.io | 27-May-2022 |
|
||||
| [WebAssembly functions in OpenFaaS using Sat (Part1)](https://www.wasm.builders/suborbital/webassembly-functions-in-openfaas-using-sat-part-1-2omk) | Connor Hicks | wasm.builders | 04-May-2022 |
|
||||
| [Building a RESTful API with functions](https://simonemms.com/blog/2022/04/24/building-a-restful-api-with-serverless-functions/) | Simon Emms | simonemms.com | 24-April-2022 |
|
||||
| [Building a RESTful API with functions](https://simonemms.com/blog/2022/04/24/building-a-restful-api-with-serverless-functions/) | Simon Emms | simonemms.com | 24-Apr-2022 |
|
||||
| [How to process your data the resilient way with back pressure](https://www.openfaas.com/blog/limits-and-backpressure/) | Alex Ellis | openfaas.com | 12-May-2022 |
|
||||
| [A Deep Dive into Golang for OpenFaaS Functions](https://www.openfaas.com/blog/golang-deep-dive/) | Alex Ellis | openfaas.com | 13-April-2022 |
|
||||
| [Open-Faas on Centos 7](https://medium.com/geekculture/open-faas-on-centos-7-c4dc629f28fe) | Heshani Samarasekara | medium.com | 07-May-2022 |
|
||||
| [A Deep Dive into Golang for OpenFaaS Functions](https://www.openfaas.com/blog/golang-deep-dive/) | Alex Ellis | openfaas.com | 13-Apr-2022 |
|
||||
| [Serverless Architecture with OpenFaaS and Java](https://www.xenonstack.com/blog/serverless-open-faas-java) | Navdeep Singh Gill | xenonstack.com | 13-Mar-2022 |
|
||||
| [My Journey Contributing To OpenFaaS So Far](https://www.openfaas.com/blog/my-journey-contributing-to-openfaas/) | Nitishkumar Singh | openfaas.com | 02-Mar-2022 |
|
||||
| [Your pocket-sized cloud with a Raspberry Pi](https://blog.alexellis.io/your-pocket-sized-cloud/) | Alex Ellis | openfaas.com | 23-Mar-2022 |
|
||||
| [Hosting a React App with OpenFaaS](https://www.openfaas.com/blog/react-app/) | Alex Ellis | openfaas.com | 01-Mar-2022 |
|
||||
@ -125,6 +161,7 @@ Mainly virtual due to pandemic.
|
||||
|-------------------------------------------------------------------------|--------------|----------|-------------|
|
||||
| [Configure your OpenFaaS functions for staging and production](https://www.openfaas.com/blog/custom-environments/) | Alex Ellis | openfaas.com | 09-Dec-2021 |
|
||||
| [OpenFaaS - Run Containerized Functions On Your Own Terms](https://iximiuz.com/en/posts/openfaas-case-study/) | Ivan Velichko | iximiuz.com | 02-Dec-2021 |
|
||||
| [Making a Docker Dev Environment for OpenFaaS](https://www.felipecruz.es/making-a-docker-dev-environment-for-openfaas/) | Felipe Cruz | felipecruz.es | 30-Nov-2021 |
|
||||
| [Build at the Edge with OpenFaaS and GitHub Actions](https://www.openfaas.com/blog/edge-actions/) | Alex Ellis | openfaas.com | 29-Nov-2021 |
|
||||
| [Improving long-running jobs for OpenFaaS users](https://www.openfaas.com/blog/long-running-jobs/) | Alex Ellis | openfaas.com | 05-Nov-2021 |
|
||||
| [Derek says goodbye to Docker Swarm](https://www.openfaas.com/blog/migrating-derek-from-docker-swarm/) | Alex Ellis | openfaas.com | 05-Oct-2021 |
|
||||
@ -146,6 +183,7 @@ Mainly virtual due to pandemic.
|
||||
| [How to integrate with GitHub the right way with GitHub Apps](https://www.openfaas.com/blog/integrate-with-github-apps-and-faasd/) | Batuhan Apaydın | openfaas.com | 26-Jan-2021 |
|
||||
| [Serverless with OpenFaaS and .NET](https://goncalo-a-oliveira.medium.com/serverless-with-openfaas-and-net-6a66b5c30a5f) | Batuhan Apaydın | medium.com | 20-Jan-2021 |
|
||||
| [How I discovered faas and what it changed for me](https://releasecandidate.dev/posts/2021/discovery-faasd-and-openfaas/) | Peter Thaleikis | releasecandidate.dev | 05-Jan-2021 |
|
||||
| [Installing OpenFaaS On k3s (Single Node)](https://midnightprogrammer.net/post/installing-openfaas-on-k3s-single-node/) | Pashant Khandelwal | midnightprogrammer.net | 04-Jan-2021 |
|
||||
|
||||
#### Events in 2021
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
## contrib
|
||||
|
||||
This folder contains miscellaneous scripts and packages for CI, development and custom Docker images.
|
||||
|
||||
* Hack on the UI Portal with [HACK.md](./HACK.md)
|
||||
* Deploy a [Grafana dashboard](./grafana.json)
|
||||
* Build and publish all project images for ARMHF with [publish-armhf.sh](./publish-armhf.sh)
|
||||
* Run experimental end-to-end tests with Docker in Docker with [dind.sh](./dind.sh)
|
||||
|
||||
Custom Docker images for ARMHF/ARM64 are available for AlertManager and Prometheus in this folder.
|
@ -1,84 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# "openfaas/nats-queue-worker"
|
||||
# ^ Already multi-arch
|
||||
|
||||
declare -a repos=("openfaas/faas")
|
||||
|
||||
HERE=`pwd`
|
||||
ARCH=$(uname -m)
|
||||
|
||||
#if [ ! -z "$CACHED" ]; then
|
||||
rm -rf staging || :
|
||||
mkdir -p staging/openfaas
|
||||
mkdir -p staging/openfaas-incubator
|
||||
|
||||
#fi
|
||||
|
||||
get_image_names() {
|
||||
if [ "openfaas-incubator/faas-idler" = $1 ]; then
|
||||
images=("openfaas/faas-idler")
|
||||
elif [ "openfaas/faas" = $1 ]; then
|
||||
images=("openfaas/gateway" "openfaas/basic-auth-plugin")
|
||||
elif [ "openfaas/nats-queue-worker" = $1 ]; then
|
||||
images=("openfaas/queue-worker")
|
||||
elif [ "openfaas-incubator/openfaas-operator" = $1 ]; then
|
||||
images=("openfaas/openfaas-operator")
|
||||
else
|
||||
images=($1)
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$ARCH" = "armv7l" ] ; then
|
||||
ARM_VERSION="armhf"
|
||||
elif [ "$ARCH" = "aarch64" ] ; then
|
||||
ARM_VERSION="arm64"
|
||||
fi
|
||||
|
||||
echo "Target architecture: ${ARM_VERSION}"
|
||||
|
||||
for r in "${repos[@]}"
|
||||
do
|
||||
cd $HERE
|
||||
|
||||
echo -e "\nBuilding: $r\n"
|
||||
git clone https://github.com/$r ./staging/$r
|
||||
cd ./staging/$r
|
||||
pwd
|
||||
export TAG=$(git describe --abbrev=0 --tags)
|
||||
echo "Latest release: $TAG"
|
||||
|
||||
get_image_names $r
|
||||
|
||||
for IMAGE in "${images[@]}"
|
||||
do
|
||||
TAG_PRESENT=$(curl -s "https://hub.docker.com/v2/repositories/${IMAGE}/tags/${TAG}-${ARM_VERSION}/" | grep -Po '"message": *"[^"]*"' | grep -io 'not found')
|
||||
if [ "$TAG_PRESENT" = "not found" ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$TAG_PRESENT" = "not found" ]; then
|
||||
make ci-${ARM_VERSION}-build ci-${ARM_VERSION}-push
|
||||
else
|
||||
for IMAGE in "${images[@]}"
|
||||
do
|
||||
echo "Image is already present: ${IMAGE}:${TAG}-${ARM_VERSION}"
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Docker images"
|
||||
|
||||
for r in "${repos[@]}"
|
||||
do
|
||||
cd $HERE
|
||||
cd ./staging/$r
|
||||
export TAG=$(git describe --abbrev=0 --tags)
|
||||
echo "$r"
|
||||
get_image_names $r
|
||||
for IMAGE in "${images[@]}"
|
||||
do
|
||||
echo " ${IMAGE}:${TAG}-${ARM_VERSION}"
|
||||
done
|
||||
done
|
@ -1,6 +1,6 @@
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} ghcr.io/openfaas/license-check:0.4.0 as license-check
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} ghcr.io/openfaas/license-check:0.4.1 as license-check
|
||||
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.17 as build
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.19 as build
|
||||
|
||||
ENV GO111MODULE=on
|
||||
ENV CGO_ENABLED=0
|
||||
@ -44,7 +44,7 @@ RUN CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build --
|
||||
-X github.com/openfaas/faas/gateway/types.Arch=${TARGETARCH}" \
|
||||
-a -installsuffix cgo -o gateway .
|
||||
|
||||
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.16.0 as ship
|
||||
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.17 as ship
|
||||
|
||||
LABEL org.label-schema.license="MIT" \
|
||||
org.label-schema.vcs-url="https://github.com/openfaas/faas" \
|
||||
|
28
gateway/Makefile
Normal file
28
gateway/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
|
||||
PLATFORM := "linux/amd64,linux/arm/v7,linux/arm64"
|
||||
|
||||
TAG?=latest
|
||||
SERVER?=docker.io
|
||||
OWNER?=alexellis2
|
||||
NAME=gateway
|
||||
|
||||
.PHONY: local-docker
|
||||
build-local:
|
||||
@echo $(SERVER)/$(OWNER)/$(NAME):$(TAG) \
|
||||
&& docker buildx create --use --name=multiarch --node multiarch \
|
||||
&& docker buildx build \
|
||||
--progress=plain \
|
||||
--platform linux/amd64 \
|
||||
--output "type=docker,push=false" \
|
||||
--tag $(SERVER)/$(OWNER)/$(NAME):$(TAG) .
|
||||
|
||||
.PHONY: push-docker
|
||||
push-docker:
|
||||
@echo $(SERVER)/$(OWNER)/$(NAME):$(TAG) \
|
||||
&& docker buildx create --use --name=multiarch --node multiarch \
|
||||
&& docker buildx build \
|
||||
--progress=plain \
|
||||
--platform $(PLATFORM) \
|
||||
--output "type=image,push=true" \
|
||||
--tag $(SERVER)/$(OWNER)/$(NAME):$(TAG) .
|
@ -1,14 +1,34 @@
|
||||
module github.com/openfaas/faas/gateway
|
||||
|
||||
go 1.16
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/docker/distribution v2.8.1+incompatible
|
||||
github.com/docker/distribution v2.8.2+incompatible
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/hashicorp/golang-lru v0.5.1 // indirect
|
||||
github.com/openfaas/faas-provider v0.18.7
|
||||
github.com/openfaas/nats-queue-worker v0.0.0-20210726161954-ada9a31504c9
|
||||
github.com/prometheus/client_golang v1.11.1
|
||||
github.com/openfaas/faas-provider v0.19.1
|
||||
github.com/openfaas/nats-queue-worker v0.0.0-20230117214128-3615ccb286cc
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
go.uber.org/goleak v1.1.10
|
||||
go.uber.org/goleak v1.1.12
|
||||
golang.org/x/sync v0.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/nats-io/nats-server/v2 v2.9.11 // indirect
|
||||
github.com/nats-io/nats-streaming-server v0.25.3 // indirect
|
||||
github.com/nats-io/nats.go v1.22.1 // indirect
|
||||
github.com/nats-io/nkeys v0.3.0 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/nats-io/stan.go v0.10.4 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/stretchr/testify v1.7.1 // indirect
|
||||
golang.org/x/crypto v0.5.0 // indirect
|
||||
golang.org/x/sys v0.4.1-0.20230105183443-b8be2fde2a9e // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
)
|
||||
|
449
gateway/go.sum
449
gateway/go.sum
@ -1,4 +1,38 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@ -11,54 +45,104 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.16.1 h1:IVQwpTGNRRIHafnTs2dQLIk4ENtneRIEEJWOVDqz99o=
|
||||
github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v1.1.0 h1:QsGcniKx5/LuX2eYoeL+Np3UKYPNaN7YKpTh29h8rbw=
|
||||
github.com/hashicorp/go-hclog v1.1.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
@ -69,25 +153,29 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/raft v1.3.1 h1:zDT8ke8y2aP4wf9zPTB2uSIeavJ3Hx/ceY4jxI2JxuY=
|
||||
github.com/hashicorp/raft v1.3.1/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM=
|
||||
github.com/hashicorp/raft v1.3.11 h1:p3v6gf6l3S797NnK5av3HcczOC1T5CLoaRvg0g9ys4A=
|
||||
github.com/hashicorp/raft v1.3.11/go.mod h1:J8naEwc6XaaCfts7+28whSeRvCqTd6e20BlCU3LtEO4=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.11.12 h1:famVnQVu7QwryBN4jNseQdUKES71ZAOnB6UQQJPZvqk=
|
||||
github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
|
||||
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
@ -95,65 +183,70 @@ github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW1
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=
|
||||
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v1.2.2 h1:w3GMTO969dFg+UOKTmmyuu7IGdusK+7Ytlt//OYH/uU=
|
||||
github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q=
|
||||
github.com/nats-io/jwt/v2 v2.0.2 h1:ejVCLO8gu6/4bOKIHQpmB5UhhUJfAQw55yvLWpfmKjI=
|
||||
github.com/nats-io/jwt/v2 v2.0.2/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY=
|
||||
github.com/nats-io/nats-server/v2 v2.2.6/go.mod h1:sEnFaxqe09cDmfMgACxZbziXnhQFhwk+aKkZjBBRYrI=
|
||||
github.com/nats-io/nats-server/v2 v2.3.2 h1:SGJLWrjBHsl0DsdY8PeTR3YKEfiUEYVVq2STw9d8MSY=
|
||||
github.com/nats-io/nats-server/v2 v2.3.2/go.mod h1:dUf7Cm5z5LbciFVwWx54owyCKm8x4/hL6p7rrljhLFY=
|
||||
github.com/nats-io/nats-streaming-server v0.22.0 h1:2egnq86o9roTqUfELlqykf7ZZkNvRsXjVf4EbaLysHo=
|
||||
github.com/nats-io/nats-streaming-server v0.22.0/go.mod h1:Jyu3eUQaUAjwd5TiBuLagKdQRofPrHoIXt1kL0U/e5o=
|
||||
github.com/nats-io/nats.go v1.11.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
|
||||
github.com/nats-io/nats.go v1.11.1-0.20210623165838-4b75fc59ae30 h1:9GqilBhZaR3xYis0JgMlJjNw933WIobdjKhilXm+Vls=
|
||||
github.com/nats-io/nats.go v1.11.1-0.20210623165838-4b75fc59ae30/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
|
||||
github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
|
||||
github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI=
|
||||
github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
|
||||
github.com/nats-io/nats-server/v2 v2.9.11 h1:4y5SwWvWI59V5mcqtuoqKq6L9NDUydOP3Ekwuwl8cZI=
|
||||
github.com/nats-io/nats-server/v2 v2.9.11/go.mod h1:b0oVuxSlkvS3ZjMkncFeACGyZohbO4XhSqW1Lt7iRRY=
|
||||
github.com/nats-io/nats-streaming-server v0.25.3 h1:A9dmf4fMIxFPBGqgwePljWsBePMEjl3ugsIwK6F2wow=
|
||||
github.com/nats-io/nats-streaming-server v0.25.3/go.mod h1:0Cyht7y75el3if3Qdq31OPc/TNjVwzglMPz04Hn77kk=
|
||||
github.com/nats-io/nats.go v1.19.0/go.mod h1:tLqubohF7t4z3du1QDPYJIQQyhb4wl6DhjxEajSI7UA=
|
||||
github.com/nats-io/nats.go v1.22.1 h1:XzfqDspY0RNufzdrB8c4hFR+R3dahkxlpWe5+IWJzbE=
|
||||
github.com/nats-io/nats.go v1.22.1/go.mod h1:tLqubohF7t4z3du1QDPYJIQQyhb4wl6DhjxEajSI7UA=
|
||||
github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
|
||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nats-io/stan.go v0.9.0 h1:TB73Y31au++0sU0VmnBy2pYkSrwH0zUFNRB9YePHqC4=
|
||||
github.com/nats-io/stan.go v0.9.0/go.mod h1:0jEuBXKauB1HHJswHM/lx05K48TJ1Yxj6VIfM4k+aB4=
|
||||
github.com/openfaas/faas-provider v0.18.6/go.mod h1:fq1JL0mX4rNvVVvRLaLRJ3H6o667sHuyP5p/7SZEe98=
|
||||
github.com/openfaas/faas-provider v0.18.7 h1:Oq3N7KrlAkAZ23N5gzZfdA9F62vpUFk3ZkQpQuHeRBU=
|
||||
github.com/openfaas/faas-provider v0.18.7/go.mod h1:S217qfIaMrv+XKJxgbhBzJzCfyFvoIF+BvYdDo6XIDQ=
|
||||
github.com/openfaas/nats-queue-worker v0.0.0-20210726161954-ada9a31504c9 h1:dpG1UcgTesGfLetgT3ns1cAhP8XMDZqxnxTW1MlnwSc=
|
||||
github.com/openfaas/nats-queue-worker v0.0.0-20210726161954-ada9a31504c9/go.mod h1:ajlN2z+D8JPBq3kWNv4WLT6mtKPqlgeE3dYEx39d1tk=
|
||||
github.com/nats-io/stan.go v0.10.4 h1:19GS/eD1SeQJaVkeM9EkvEYattnvnWrZ3wkSWSw4uXw=
|
||||
github.com/nats-io/stan.go v0.10.4/go.mod h1:3XJXH8GagrGqajoO/9+HgPyKV5MWsv7S5ccdda+pc6k=
|
||||
github.com/openfaas/faas-provider v0.19.1 h1:xH8lTWabfDZwzIvC0u1AO48ghD3BNw6Vo231DLqTeI0=
|
||||
github.com/openfaas/faas-provider v0.19.1/go.mod h1:Farrp+9Med8LeK3aoYpqplMP8f5ebTILbCSLg2LPLZk=
|
||||
github.com/openfaas/nats-queue-worker v0.0.0-20230117214128-3615ccb286cc h1:qMcVTwdbRAqZtQrYS9rvUxnbQY6nmqf7CIsjp7A+cOo=
|
||||
github.com/openfaas/nats-queue-worker v0.0.0-20230117214128-3615ccb286cc/go.mod h1:s86POyW6C8S4CALFRhO8ax5sR2uaQUJQ0HaQGvbTpTc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
|
||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
@ -162,104 +255,342 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.uber.org/goleak v1.1.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.1-0.20230105183443-b8be2fde2a9e h1:Lw2b7QX5zDuEsD5ZkJNRUGEGkLuho3UAKsO25Ucv140=
|
||||
golang.org/x/sys v0.4.1-0.20230105183443-b8be2fde2a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
|
||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"math"
|
||||
"net/http"
|
||||
|
||||
"github.com/openfaas/faas/gateway/pkg/middleware"
|
||||
"github.com/openfaas/faas/gateway/requests"
|
||||
"github.com/openfaas/faas/gateway/scaling"
|
||||
)
|
||||
@ -19,23 +20,24 @@ import (
|
||||
func MakeAlertHandler(service scaling.ServiceQuery, defaultNamespace string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.Println("Alert received.")
|
||||
if r.Body == nil {
|
||||
http.Error(w, "A body is required for this endpoint", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
body, readErr := ioutil.ReadAll(r.Body)
|
||||
defer r.Body.Close()
|
||||
|
||||
log.Println(string(body))
|
||||
|
||||
if readErr != nil {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("Unable to read alert."))
|
||||
|
||||
log.Println(readErr)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
var req requests.PrometheusAlert
|
||||
err := json.Unmarshal(body, &req)
|
||||
if err != nil {
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("Unable to parse alert, bad format."))
|
||||
log.Println(err)
|
||||
@ -73,7 +75,7 @@ func handleAlerts(req *requests.PrometheusAlert, service scaling.ServiceQuery, d
|
||||
func scaleService(alert requests.PrometheusInnerAlert, service scaling.ServiceQuery, defaultNamespace string) error {
|
||||
var err error
|
||||
|
||||
serviceName, namespace := getNamespace(defaultNamespace, alert.Labels.FunctionName)
|
||||
serviceName, namespace := middleware.GetNamespace(defaultNamespace, alert.Labels.FunctionName)
|
||||
|
||||
if len(serviceName) > 0 {
|
||||
queryResponse, getErr := service.GetReplicas(serviceName, namespace)
|
||||
@ -100,6 +102,7 @@ func scaleService(alert requests.PrometheusInnerAlert, service scaling.ServiceQu
|
||||
func CalculateReplicas(status string, currentReplicas uint64, maxReplicas uint64, minReplicas uint64, scalingFactor uint64) uint64 {
|
||||
var newReplicas uint64
|
||||
|
||||
maxReplicas = uint64(math.Min(float64(maxReplicas), float64(scaling.DefaultMaxReplicas)))
|
||||
step := uint64(math.Ceil(float64(maxReplicas) / 100 * float64(scalingFactor)))
|
||||
|
||||
if status == "firing" && step > 0 {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) Alex Ellis 2017. All rights reserved.
|
||||
// Copyright (c) Alex Ellis 1017. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
package handlers
|
||||
@ -12,9 +12,9 @@ import (
|
||||
func TestDisabledScale(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
scalingFactor := uint64(0)
|
||||
newReplicas := CalculateReplicas("firing", scaling.DefaultMinReplicas, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != minReplicas {
|
||||
t.Logf("Expected not to scale, but replicas were: %d", newReplicas)
|
||||
got := CalculateReplicas("firing", scaling.DefaultMinReplicas, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if got != minReplicas {
|
||||
t.Logf("Expected not to scale, but replicas were: %d", got)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
@ -22,20 +22,23 @@ func TestDisabledScale(t *testing.T) {
|
||||
func TestParameterEdge(t *testing.T) {
|
||||
minReplicas := uint64(0)
|
||||
scalingFactor := uint64(0)
|
||||
newReplicas := CalculateReplicas("firing", scaling.DefaultMinReplicas, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != 0 {
|
||||
got := CalculateReplicas("firing", scaling.DefaultMinReplicas, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if got != 0 {
|
||||
t.Log("Expected not to scale")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalingWithSameUpperLowerLimit(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
scalingFactor := uint64(20)
|
||||
// status string, currentReplicas uint64, maxReplicas uint64, minReplicas uint64, scalingFactor uint64)
|
||||
newReplicas := CalculateReplicas("firing", minReplicas, minReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != 1 {
|
||||
t.Logf("Replicas - want: %d, got: %d", minReplicas, newReplicas)
|
||||
func TestScaling_SameUpperLowerLimit(t *testing.T) {
|
||||
minReplicas := uint64(5)
|
||||
maxReplicas := uint64(5)
|
||||
scalingFactor := uint64(10)
|
||||
|
||||
got := CalculateReplicas("firing", minReplicas, minReplicas, maxReplicas, scalingFactor)
|
||||
|
||||
want := minReplicas
|
||||
if want != got {
|
||||
t.Logf("Replicas - want: %d, got: %d", want, got)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
@ -43,58 +46,62 @@ func TestScalingWithSameUpperLowerLimit(t *testing.T) {
|
||||
func TestMaxScale(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
scalingFactor := uint64(100)
|
||||
newReplicas := CalculateReplicas("firing", scaling.DefaultMinReplicas, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != 20 {
|
||||
t.Log("Expected ceiling of 20 replicas")
|
||||
t.Fail()
|
||||
got := CalculateReplicas("firing", scaling.DefaultMinReplicas, scaling.DefaultMaxReplicas*2, minReplicas, scalingFactor)
|
||||
if got != scaling.DefaultMaxReplicas {
|
||||
t.Fatalf("want ceiling: %d, but got: %d", scaling.DefaultMaxReplicas, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitialScale(t *testing.T) {
|
||||
func TestInitialScale_From1_Factor10(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
scalingFactor := uint64(20)
|
||||
newReplicas := CalculateReplicas("firing", scaling.DefaultMinReplicas, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != 5 {
|
||||
t.Log("Expected the increment to equal 5")
|
||||
t.Fail()
|
||||
scalingFactor := uint64(10)
|
||||
got := CalculateReplicas("firing", scaling.DefaultMinReplicas, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
want := uint64(2)
|
||||
|
||||
if got != want {
|
||||
t.Fatalf("want: %d, but got: %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScale(t *testing.T) {
|
||||
func TestScale_midrange_factor25(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
scalingFactor := uint64(20)
|
||||
newReplicas := CalculateReplicas("firing", 4, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != 8 {
|
||||
t.Log("Expected newReplicas to equal 8")
|
||||
t.Fail()
|
||||
scalingFactor := uint64(25)
|
||||
current := uint64(4)
|
||||
maxReplicas := uint64(scaling.DefaultMaxReplicas)
|
||||
|
||||
got := CalculateReplicas("firing", current, maxReplicas, minReplicas, scalingFactor)
|
||||
want := uint64(5)
|
||||
if want != got {
|
||||
t.Fatalf("want: %d, but got: %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaleCeiling(t *testing.T) {
|
||||
func TestScale_Ceiling_IsDefaultMaxReplicas(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
scalingFactor := uint64(20)
|
||||
newReplicas := CalculateReplicas("firing", 20, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != 20 {
|
||||
t.Log("Expected ceiling of 20 replicas")
|
||||
t.Fail()
|
||||
scalingFactor := uint64(10)
|
||||
current := uint64(scaling.DefaultMaxReplicas)
|
||||
|
||||
got := CalculateReplicas("firing", current, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if got != scaling.DefaultMaxReplicas {
|
||||
t.Fatalf("want: %d, but got: %d", scaling.DefaultMaxReplicas, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaleCeilingEdge(t *testing.T) {
|
||||
func TestScaleCeilingReplicasOver(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
scalingFactor := uint64(20)
|
||||
newReplicas := CalculateReplicas("firing", 19, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != 20 {
|
||||
t.Log("Expected ceiling of 20 replicas")
|
||||
t.Fail()
|
||||
scalingFactor := uint64(10)
|
||||
got := CalculateReplicas("firing", 19, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
|
||||
if got != scaling.DefaultMaxReplicas {
|
||||
t.Fatalf("want: %d, but got: %d", scaling.DefaultMaxReplicas, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackingOff(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
scalingFactor := uint64(20)
|
||||
newReplicas := CalculateReplicas("resolved", 8, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if newReplicas != 1 {
|
||||
scalingFactor := uint64(10)
|
||||
got := CalculateReplicas("resolved", 8, scaling.DefaultMaxReplicas, minReplicas, scalingFactor)
|
||||
if got != 1 {
|
||||
t.Log("Expected backing off to 1 replica")
|
||||
t.Fail()
|
||||
}
|
||||
@ -104,9 +111,9 @@ func TestScaledUpFrom1(t *testing.T) {
|
||||
currentReplicas := uint64(1)
|
||||
maxReplicas := uint64(5)
|
||||
scalingFactor := uint64(30)
|
||||
newReplicas := CalculateReplicas("firing", currentReplicas, maxReplicas, scaling.DefaultMinReplicas, scalingFactor)
|
||||
if newReplicas <= currentReplicas {
|
||||
t.Log("Expected newReplicas > currentReplica")
|
||||
got := CalculateReplicas("firing", currentReplicas, maxReplicas, scaling.DefaultMinReplicas, scalingFactor)
|
||||
if got <= currentReplicas {
|
||||
t.Log("Expected got > currentReplica")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
@ -115,9 +122,9 @@ func TestScaledUpWithSmallParam(t *testing.T) {
|
||||
currentReplicas := uint64(1)
|
||||
maxReplicas := uint64(4)
|
||||
scalingFactor := uint64(1)
|
||||
newReplicas := CalculateReplicas("firing", currentReplicas, maxReplicas, scaling.DefaultMinReplicas, scalingFactor)
|
||||
if newReplicas <= currentReplicas {
|
||||
t.Log("Expected newReplicas > currentReplica")
|
||||
got := CalculateReplicas("firing", currentReplicas, maxReplicas, scaling.DefaultMinReplicas, scalingFactor)
|
||||
if got <= currentReplicas {
|
||||
t.Log("Expected got > currentReplica")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
// Copyright (c) OpenFaaS Author(s). All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSingleHostBaseURLResolver(t *testing.T) {
|
||||
|
||||
urlVal, _ := url.Parse("http://upstream:8080/")
|
||||
r := SingleHostBaseURLResolver{BaseURL: urlVal.String()}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/function/hello", nil)
|
||||
|
||||
resolved := r.Resolve(req)
|
||||
want := "http://upstream:8080"
|
||||
if resolved != want {
|
||||
t.Logf("r.Resolve failed, want: %s got: %s", want, resolved)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
const watchdogPort = 8080
|
||||
|
||||
func TestFunctionAsHostBaseURLResolver_WithNamespaceOverride(t *testing.T) {
|
||||
|
||||
suffix := "openfaas-fn.local.cluster.svc."
|
||||
namespace := "openfaas-fn"
|
||||
newNS := "production-fn"
|
||||
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix, FunctionNamespace: namespace}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/function/hello."+newNS, nil)
|
||||
|
||||
resolved := r.Resolve(req)
|
||||
|
||||
newSuffix := strings.Replace(suffix, namespace, newNS, -1)
|
||||
|
||||
want := fmt.Sprintf("http://hello.%s:%d", newSuffix, watchdogPort)
|
||||
log.Println(want)
|
||||
if resolved != want {
|
||||
t.Logf("r.Resolve failed, want: %s got: %s", want, resolved)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunctionAsHostBaseURLResolver_WithSuffix(t *testing.T) {
|
||||
suffix := "openfaas-fn.local.cluster.svc."
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/function/hello", nil)
|
||||
|
||||
resolved := r.Resolve(req)
|
||||
want := fmt.Sprintf("http://hello.%s:%d", suffix, watchdogPort)
|
||||
log.Println(want)
|
||||
if resolved != want {
|
||||
t.Logf("r.Resolve failed, want: %s got: %s", want, resolved)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunctionAsHostBaseURLResolver_WithoutSuffix(t *testing.T) {
|
||||
suffix := ""
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/function/hello", nil)
|
||||
|
||||
resolved := r.Resolve(req)
|
||||
want := fmt.Sprintf("http://hello%s:%d", suffix, watchdogPort)
|
||||
|
||||
if resolved != want {
|
||||
t.Logf("r.Resolve failed, want: %s got: %s", want, resolved)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MakeExternalAuthHandler make an authentication proxy handler
|
||||
func MakeExternalAuthHandler(next http.HandlerFunc, upstreamTimeout time.Duration, upstreamURL string, passBody bool) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
req, _ := http.NewRequest(http.MethodGet, upstreamURL, nil)
|
||||
|
||||
copyHeaders(req.Header, &r.Header)
|
||||
|
||||
deadlineContext, cancel := context.WithTimeout(
|
||||
context.Background(),
|
||||
upstreamTimeout)
|
||||
|
||||
defer cancel()
|
||||
|
||||
res, err := http.DefaultClient.Do(req.WithContext(deadlineContext))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
log.Printf("ExternalAuthHandler: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
if res.StatusCode == http.StatusOK {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
copyHeaders(w.Header(), &res.Header)
|
||||
w.WriteHeader(res.StatusCode)
|
||||
|
||||
if res.Body != nil {
|
||||
io.Copy(w, res.Body)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,239 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_External_Auth_Wrapper_FailsInvalidAuth(t *testing.T) {
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
next := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
passBody := false
|
||||
handler := MakeExternalAuthHandler(next, time.Second*5, s.URL, passBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
rr := httptest.NewRecorder()
|
||||
handler(rr, req)
|
||||
|
||||
if rr.Code == http.StatusOK {
|
||||
t.Errorf("Status incorrect, did not want: %d, but got %d", http.StatusOK, rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_External_Auth_Wrapper_FailsInvalidAuth_WritesBody(t *testing.T) {
|
||||
|
||||
wantBody := []byte(`invalid credentials`)
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write(wantBody)
|
||||
}))
|
||||
|
||||
defer s.Close()
|
||||
|
||||
next := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
passBody := false
|
||||
handler := MakeExternalAuthHandler(next, time.Second*5, s.URL, passBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
rr := httptest.NewRecorder()
|
||||
handler(rr, req)
|
||||
|
||||
if rr.Code == http.StatusOK {
|
||||
t.Errorf("Status incorrect, did not want: %d, but got %d", http.StatusOK, rr.Code)
|
||||
}
|
||||
|
||||
if bytes.Compare(rr.Body.Bytes(), wantBody) != 0 {
|
||||
t.Errorf("Body incorrect, want: %s, but got %s", []byte(wantBody), rr.Body)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_External_Auth_Wrapper_PassesValidAuth(t *testing.T) {
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
next := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
passBody := false
|
||||
handler := MakeExternalAuthHandler(next, time.Second*5, s.URL, passBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
rr := httptest.NewRecorder()
|
||||
handler(rr, req)
|
||||
want := http.StatusNotImplemented
|
||||
if rr.Code != want {
|
||||
t.Errorf("Status incorrect, want: %d, but got %d", want, rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_External_Auth_Wrapper_WithoutRequiredHeaderFailsAuth(t *testing.T) {
|
||||
wantToken := "secret-key"
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("X-Token") == wantToken {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
next := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
passBody := false
|
||||
handler := MakeExternalAuthHandler(next, time.Second*5, s.URL, passBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
|
||||
// use an invalid token
|
||||
req.Header.Set("X-Token", "invalid-key")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler(rr, req)
|
||||
want := http.StatusUnauthorized
|
||||
if rr.Code != want {
|
||||
t.Errorf("Status incorrect, want: %d, but got %d", want, rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_External_Auth_Wrapper_WithoutRequiredHeaderFailsAuth_ProxiesServerHeaders(t *testing.T) {
|
||||
wantToken := "secret-key"
|
||||
wantRealm := `Basic realm="Restricted"`
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("X-Token") == wantToken {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Www-Authenticate", wantRealm)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
next := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
passBody := false
|
||||
handler := MakeExternalAuthHandler(next, time.Second*5, s.URL, passBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
|
||||
// use an invalid token
|
||||
req.Header.Set("X-Token", "invalid-key")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler(rr, req)
|
||||
want := http.StatusUnauthorized
|
||||
if rr.Code != want {
|
||||
t.Errorf("Status incorrect, want: %d, but got %d", want, rr.Code)
|
||||
}
|
||||
|
||||
got := rr.Header().Get("Www-Authenticate")
|
||||
if got != wantRealm {
|
||||
t.Errorf("Www-Authenticate header, want: %s, but got %s, %q", wantRealm, got, rr.Header())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_External_Auth_Wrapper_WithRequiredHeaderPassesValidAuth(t *testing.T) {
|
||||
wantToken := "secret-key"
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("X-Token") == wantToken {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
next := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
passBody := false
|
||||
handler := MakeExternalAuthHandler(next, time.Second*5, s.URL, passBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
req.Header.Set("X-Token", wantToken)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler(rr, req)
|
||||
want := http.StatusNotImplemented
|
||||
if rr.Code != want {
|
||||
t.Errorf("Status incorrect, want: %d, but got %d", want, rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_External_Auth_Wrapper_TimeoutGivesInternalServerError(t *testing.T) {
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
next := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
passBody := false
|
||||
handler := MakeExternalAuthHandler(next, time.Millisecond*10, s.URL, passBody)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
rr := httptest.NewRecorder()
|
||||
handler(rr, req)
|
||||
|
||||
want := http.StatusInternalServerError
|
||||
if rr.Code != want {
|
||||
t.Errorf("Status incorrect, want: %d, but got %d", want, rr.Code)
|
||||
}
|
||||
wantSubstring := "context deadline exceeded\n"
|
||||
if !strings.HasSuffix(string(rr.Body.Bytes()), wantSubstring) {
|
||||
t.Errorf("Body incorrect, want to have suffix: %q, but got %q", []byte(wantSubstring), rr.Body)
|
||||
}
|
||||
}
|
||||
|
||||
// // Test_External_Auth_Wrapper_PassesValidAuthButOnly200IsValid this test exists
|
||||
// // to document the TODO action to consider all "2xx" statuses as valid.
|
||||
// func Test_External_Auth_Wrapper_PassesValidAuthButOnly200IsValid(t *testing.T) {
|
||||
|
||||
// s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// w.WriteHeader(http.StatusAccepted)
|
||||
// }))
|
||||
// defer s.Close()
|
||||
|
||||
// next := func(w http.ResponseWriter, r *http.Request) {
|
||||
// w.WriteHeader(http.StatusNotImplemented)
|
||||
// }
|
||||
|
||||
// passBody := false
|
||||
// handler := MakeExternalAuthHandler(next, time.Second*5, s.URL, passBody)
|
||||
|
||||
// req := httptest.NewRequest(http.MethodGet, s.URL, nil)
|
||||
// rr := httptest.NewRecorder()
|
||||
// handler(rr, req)
|
||||
// want := http.StatusUnauthorized
|
||||
// if rr.Code != want {
|
||||
// t.Errorf("Status incorrect, want: %d, but got %d", want, rr.Code)
|
||||
// }
|
||||
// }
|
@ -10,40 +10,17 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/openfaas/faas/gateway/pkg/middleware"
|
||||
"github.com/openfaas/faas/gateway/types"
|
||||
)
|
||||
|
||||
// functionMatcher parses out the service name (group 1) and rest of path (group 2).
|
||||
var functionMatcher = regexp.MustCompile("^/?(?:async-)?function/([^/?]+)([^?]*)")
|
||||
|
||||
// Indices and meta-data for functionMatcher regex parts
|
||||
const (
|
||||
hasPathCount = 3
|
||||
routeIndex = 0 // routeIndex corresponds to /function/ or /async-function/
|
||||
nameIndex = 1 // nameIndex is the function name
|
||||
pathIndex = 2 // pathIndex is the path i.e. /employee/:id/
|
||||
)
|
||||
|
||||
// BaseURLResolver URL resolver for upstream requests
|
||||
type BaseURLResolver interface {
|
||||
Resolve(r *http.Request) string
|
||||
}
|
||||
|
||||
// URLPathTransformer Transform the incoming URL path for upstream requests
|
||||
type URLPathTransformer interface {
|
||||
Transform(r *http.Request) string
|
||||
}
|
||||
|
||||
// MakeForwardingProxyHandler create a handler which forwards HTTP requests
|
||||
func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy,
|
||||
notifiers []HTTPNotifier,
|
||||
baseURLResolver BaseURLResolver,
|
||||
urlPathTransformer URLPathTransformer,
|
||||
baseURLResolver middleware.BaseURLResolver,
|
||||
urlPathTransformer middleware.URLPathTransformer,
|
||||
serviceAuthInjector middleware.AuthInjector) http.HandlerFunc {
|
||||
|
||||
writeRequestURI := false
|
||||
@ -165,80 +142,6 @@ func deleteHeaders(target *http.Header, exclude *[]string) {
|
||||
}
|
||||
}
|
||||
|
||||
// SingleHostBaseURLResolver resolves URLs against a single BaseURL
|
||||
type SingleHostBaseURLResolver struct {
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
// Resolve the base URL for a request
|
||||
func (s SingleHostBaseURLResolver) Resolve(r *http.Request) string {
|
||||
|
||||
baseURL := s.BaseURL
|
||||
|
||||
if strings.HasSuffix(baseURL, "/") {
|
||||
baseURL = baseURL[0 : len(baseURL)-1]
|
||||
}
|
||||
return baseURL
|
||||
}
|
||||
|
||||
// FunctionAsHostBaseURLResolver resolves URLs using a function from the URL as a host
|
||||
type FunctionAsHostBaseURLResolver struct {
|
||||
FunctionSuffix string
|
||||
FunctionNamespace string
|
||||
}
|
||||
|
||||
// Resolve the base URL for a request
|
||||
func (f FunctionAsHostBaseURLResolver) Resolve(r *http.Request) string {
|
||||
svcName := getServiceName(r.URL.Path)
|
||||
|
||||
const watchdogPort = 8080
|
||||
var suffix string
|
||||
|
||||
if len(f.FunctionSuffix) > 0 {
|
||||
if index := strings.LastIndex(svcName, "."); index > -1 && len(svcName) > index+1 {
|
||||
suffix = strings.Replace(f.FunctionSuffix, f.FunctionNamespace, "", -1)
|
||||
} else {
|
||||
suffix = "." + f.FunctionSuffix
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("http://%s%s:%d", svcName, suffix, watchdogPort)
|
||||
}
|
||||
|
||||
// TransparentURLPathTransformer passes the requested URL path through untouched.
|
||||
type TransparentURLPathTransformer struct {
|
||||
}
|
||||
|
||||
// Transform returns the URL path unchanged.
|
||||
func (f TransparentURLPathTransformer) Transform(r *http.Request) string {
|
||||
return r.URL.Path
|
||||
}
|
||||
|
||||
// FunctionPrefixTrimmingURLPathTransformer removes the "/function/servicename/" prefix from the URL path.
|
||||
type FunctionPrefixTrimmingURLPathTransformer struct {
|
||||
}
|
||||
|
||||
// Transform removes the "/function/servicename/" prefix from the URL path.
|
||||
func (f FunctionPrefixTrimmingURLPathTransformer) Transform(r *http.Request) string {
|
||||
ret := r.URL.Path
|
||||
|
||||
if ret != "" {
|
||||
// When forwarding to a function, since the `/function/xyz` portion
|
||||
// of a path like `/function/xyz/rest/of/path` is only used or needed
|
||||
// by the Gateway, we want to trim it down to `/rest/of/path` for the
|
||||
// upstream request. In the following regex, in the case of a match
|
||||
// the r.URL.Path will be at `0`, the function name at `1` and the
|
||||
// rest of the path (the part we are interested in) at `2`.
|
||||
matcher := functionMatcher.Copy()
|
||||
parts := matcher.FindStringSubmatch(ret)
|
||||
if len(parts) == hasPathCount {
|
||||
ret = parts[pathIndex]
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Hop-by-hop headers. These are removed when sent to the backend.
|
||||
// As of RFC 7230, hop-by-hop headers are required to appear in the
|
||||
// Connection header field. These are the headers defined by the
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/openfaas/faas/gateway/pkg/middleware"
|
||||
)
|
||||
|
||||
func Test_buildUpstreamRequest_Body_Method_Query(t *testing.T) {
|
||||
@ -170,7 +172,7 @@ func Test_getServiceName(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
service := getServiceName(u.Path)
|
||||
service := middleware.GetServiceName(u.Path)
|
||||
if service != s.serviceName {
|
||||
t.Fatalf("Incorrect service name - want: %s, got: %s", s.serviceName, service)
|
||||
}
|
||||
@ -195,7 +197,7 @@ func Test_buildUpstreamRequest_WithPathNoQuery(t *testing.T) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
transformer := FunctionPrefixTrimmingURLPathTransformer{}
|
||||
transformer := middleware.FunctionPrefixTrimmingURLPathTransformer{}
|
||||
transformedPath := transformer.Transform(request)
|
||||
|
||||
wantTransformedPath := functionPath
|
||||
@ -251,7 +253,7 @@ func Test_buildUpstreamRequest_WithNoPathNoQuery(t *testing.T) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
transformer := FunctionPrefixTrimmingURLPathTransformer{}
|
||||
transformer := middleware.FunctionPrefixTrimmingURLPathTransformer{}
|
||||
transformedPath := transformer.Transform(request)
|
||||
|
||||
wantTransformedPath := "/"
|
||||
@ -305,7 +307,7 @@ func Test_buildUpstreamRequest_WithPathAndQuery(t *testing.T) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
transformer := FunctionPrefixTrimmingURLPathTransformer{}
|
||||
transformer := middleware.FunctionPrefixTrimmingURLPathTransformer{}
|
||||
transformedPath := transformer.Transform(request)
|
||||
|
||||
wantTransformedPath := functionPath
|
||||
|
@ -5,7 +5,7 @@ package handlers
|
||||
|
||||
import "net/http"
|
||||
|
||||
//HealthzHandler healthz hanlder for mertics server
|
||||
// HealthzHandler healthz hanlder for mertics server
|
||||
func HealthzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
switch r.Method {
|
||||
|
@ -5,10 +5,9 @@ package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"io/ioutil"
|
||||
"net/http/httptest"
|
||||
|
||||
providerTypes "github.com/openfaas/faas-provider/types"
|
||||
@ -27,7 +26,7 @@ func MakeInfoHandler(h http.Handler) http.HandlerFunc {
|
||||
|
||||
var provider *providerTypes.ProviderInfo
|
||||
|
||||
upstreamBody, _ := ioutil.ReadAll(upstreamCall.Body)
|
||||
upstreamBody, _ := io.ReadAll(upstreamCall.Body)
|
||||
err := json.Unmarshal(upstreamBody, &provider)
|
||||
if err != nil {
|
||||
log.Printf("Error unmarshalling provider json from body %s. Error %s\n", upstreamBody, err.Error())
|
||||
|
@ -3,10 +3,13 @@
|
||||
|
||||
package handlers
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"github.com/openfaas/faas/gateway/pkg/middleware"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_getNamespace_Default(t *testing.T) {
|
||||
root, ns := getNamespace("openfaas-fn", "figlet.openfaas-fn")
|
||||
root, ns := middleware.GetNamespace("openfaas-fn", "figlet.openfaas-fn")
|
||||
wantRoot := "figlet"
|
||||
wantNs := "openfaas-fn"
|
||||
|
||||
@ -19,7 +22,7 @@ func Test_getNamespace_Default(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_getNamespace_Override(t *testing.T) {
|
||||
root, ns := getNamespace("fn", "figlet.fn")
|
||||
root, ns := middleware.GetNamespace("fn", "figlet.fn")
|
||||
wantRoot := "figlet"
|
||||
wantNs := "fn"
|
||||
|
||||
@ -32,7 +35,7 @@ func Test_getNamespace_Override(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_getNamespace_Empty(t *testing.T) {
|
||||
root, ns := getNamespace("", "figlet")
|
||||
root, ns := middleware.GetNamespace("", "figlet")
|
||||
wantRoot := "figlet"
|
||||
wantNs := ""
|
||||
|
||||
|
@ -6,50 +6,21 @@ package handlers
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/openfaas/faas-provider/httputil"
|
||||
)
|
||||
|
||||
// MakeNotifierWrapper wraps a http.HandlerFunc in an interceptor to pass to HTTPNotifier
|
||||
func MakeNotifierWrapper(next http.HandlerFunc, notifiers []HTTPNotifier) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
then := time.Now()
|
||||
|
||||
writer := newWriteInterceptor(w)
|
||||
next(&writer, r)
|
||||
|
||||
url := r.URL.String()
|
||||
|
||||
writer := httputil.NewHttpWriteInterceptor(w)
|
||||
next(writer, r)
|
||||
|
||||
for _, notifier := range notifiers {
|
||||
notifier.Notify(r.Method, url, url, writer.Status(), "completed", time.Since(then))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newWriteInterceptor(w http.ResponseWriter) writeInterceptor {
|
||||
return writeInterceptor{
|
||||
w: w,
|
||||
}
|
||||
}
|
||||
|
||||
type writeInterceptor struct {
|
||||
CapturedStatusCode int
|
||||
w http.ResponseWriter
|
||||
}
|
||||
|
||||
func (c *writeInterceptor) Status() int {
|
||||
if c.CapturedStatusCode == 0 {
|
||||
return http.StatusOK
|
||||
}
|
||||
return c.CapturedStatusCode
|
||||
}
|
||||
|
||||
func (c *writeInterceptor) Header() http.Header {
|
||||
return c.w.Header()
|
||||
}
|
||||
|
||||
func (c *writeInterceptor) Write(data []byte) (int, error) {
|
||||
return c.w.Write(data)
|
||||
}
|
||||
|
||||
func (c *writeInterceptor) WriteHeader(code int) {
|
||||
c.CapturedStatusCode = code
|
||||
c.w.WriteHeader(code)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/openfaas/faas/gateway/metrics"
|
||||
"github.com/openfaas/faas/gateway/pkg/middleware"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@ -16,20 +17,6 @@ type HTTPNotifier interface {
|
||||
Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration)
|
||||
}
|
||||
|
||||
// PrometheusServiceNotifier notifier for core service endpoints
|
||||
type PrometheusServiceNotifier struct {
|
||||
ServiceMetrics *metrics.ServiceMetricOptions
|
||||
}
|
||||
|
||||
// Notify about service metrics
|
||||
func (psn PrometheusServiceNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
|
||||
code := fmt.Sprintf("%d", statusCode)
|
||||
path := urlToLabel(URL)
|
||||
|
||||
psn.ServiceMetrics.Counter.WithLabelValues(method, path, code).Inc()
|
||||
psn.ServiceMetrics.Histogram.WithLabelValues(method, path, code).Observe(duration.Seconds())
|
||||
}
|
||||
|
||||
func urlToLabel(path string) string {
|
||||
if len(path) > 0 {
|
||||
path = strings.TrimRight(path, "/")
|
||||
@ -49,7 +36,7 @@ type PrometheusFunctionNotifier struct {
|
||||
|
||||
// Notify records metrics in Prometheus
|
||||
func (p PrometheusFunctionNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
|
||||
serviceName := getServiceName(originalURL)
|
||||
serviceName := middleware.GetServiceName(originalURL)
|
||||
if len(p.FunctionNamespace) > 0 {
|
||||
if !strings.Contains(serviceName, ".") {
|
||||
serviceName = fmt.Sprintf("%s.%s", serviceName, p.FunctionNamespace)
|
||||
@ -74,24 +61,6 @@ func (p PrometheusFunctionNotifier) Notify(method string, URL string, originalUR
|
||||
|
||||
}
|
||||
|
||||
func getServiceName(urlValue string) string {
|
||||
var serviceName string
|
||||
forward := "/function/"
|
||||
if strings.HasPrefix(urlValue, forward) {
|
||||
// With a path like `/function/xyz/rest/of/path?q=a`, the service
|
||||
// name we wish to locate is just the `xyz` portion. With a positive
|
||||
// match on the regex below, it will return a three-element slice.
|
||||
// The item at index `0` is the same as `urlValue`, at `1`
|
||||
// will be the service name we need, and at `2` the rest of the path.
|
||||
matcher := functionMatcher.Copy()
|
||||
matches := matcher.FindStringSubmatch(urlValue)
|
||||
if len(matches) == hasPathCount {
|
||||
serviceName = matches[nameIndex]
|
||||
}
|
||||
}
|
||||
return strings.Trim(serviceName, "/")
|
||||
}
|
||||
|
||||
// LoggingNotifier notifies a log about a request
|
||||
type LoggingNotifier struct {
|
||||
}
|
||||
@ -99,6 +68,6 @@ type LoggingNotifier struct {
|
||||
// Notify the LoggingNotifier about a request
|
||||
func (LoggingNotifier) Notify(method string, URL string, originalURL string, statusCode int, event string, duration time.Duration) {
|
||||
if event == "completed" {
|
||||
log.Printf("Forwarded [%s] to %s - [%d] - %fs seconds", method, originalURL, statusCode, duration.Seconds())
|
||||
log.Printf("Forwarded [%s] to %s - [%d] - %.4fs", method, originalURL, statusCode, duration.Seconds())
|
||||
}
|
||||
}
|
||||
|
@ -14,24 +14,24 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
ftypes "github.com/openfaas/faas-provider/types"
|
||||
"github.com/openfaas/faas/gateway/metrics"
|
||||
"github.com/openfaas/faas/gateway/pkg/middleware"
|
||||
|
||||
"github.com/openfaas/faas/gateway/scaling"
|
||||
)
|
||||
|
||||
const queueAnnotation = "com.openfaas.queue"
|
||||
|
||||
// MakeQueuedProxy accepts work onto a queue
|
||||
func MakeQueuedProxy(metrics metrics.MetricOptions, queuer ftypes.RequestQueuer, pathTransformer URLPathTransformer, defaultNS string, functionQuery scaling.FunctionQuery) http.HandlerFunc {
|
||||
func MakeQueuedProxy(metrics metrics.MetricOptions, queuer ftypes.RequestQueuer, pathTransformer middleware.URLPathTransformer, defaultNS string, functionQuery scaling.FunctionQuery) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var body []byte
|
||||
if r.Body != nil {
|
||||
defer r.Body.Close()
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
var err error
|
||||
body, err = ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
callbackURL, err := getCallbackURLHeader(r.Header)
|
||||
@ -43,12 +43,6 @@ func MakeQueuedProxy(metrics metrics.MetricOptions, queuer ftypes.RequestQueuer,
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
|
||||
queueName, err := getQueueName(name, functionQuery)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
req := &ftypes.QueueRequest{
|
||||
Function: name,
|
||||
Body: body,
|
||||
@ -58,16 +52,12 @@ func MakeQueuedProxy(metrics metrics.MetricOptions, queuer ftypes.RequestQueuer,
|
||||
Header: r.Header,
|
||||
Host: r.Host,
|
||||
CallbackURL: callbackURL,
|
||||
QueueName: queueName,
|
||||
}
|
||||
|
||||
if len(queueName) > 0 {
|
||||
log.Printf("Queueing %s to: %s\n", name, queueName)
|
||||
}
|
||||
|
||||
if err = queuer.Queue(req); err != nil {
|
||||
fmt.Printf("Queue error: %v\n", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
log.Printf("Error queuing request: %v", err)
|
||||
http.Error(w, fmt.Sprintf("Error queuing request: %s", err.Error()),
|
||||
http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@ -91,21 +81,6 @@ func getCallbackURLHeader(header http.Header) (*url.URL, error) {
|
||||
return callbackURL, nil
|
||||
}
|
||||
|
||||
func getQueueName(name string, fnQuery scaling.FunctionQuery) (queueName string, err error) {
|
||||
fn, ns := getNameParts(name)
|
||||
|
||||
annotations, err := fnQuery.GetAnnotations(fn, ns)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
queueName = ""
|
||||
if v := annotations[queueAnnotation]; len(v) > 0 {
|
||||
queueName = v
|
||||
}
|
||||
|
||||
return queueName, err
|
||||
}
|
||||
|
||||
func getNameParts(name string) (fn, ns string) {
|
||||
fn = name
|
||||
ns = ""
|
||||
|
@ -7,18 +7,11 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/openfaas/faas/gateway/pkg/middleware"
|
||||
"github.com/openfaas/faas/gateway/scaling"
|
||||
)
|
||||
|
||||
func getNamespace(defaultNamespace, fullName string) (string, string) {
|
||||
if index := strings.LastIndex(fullName, "."); index > -1 {
|
||||
return fullName[:index], fullName[index+1:]
|
||||
}
|
||||
return fullName, defaultNamespace
|
||||
}
|
||||
|
||||
// MakeScalingHandler creates handler which can scale a function from
|
||||
// zero to N replica(s). After scaling the next http.HandlerFunc will
|
||||
// be called. If the function is not ready after the configured
|
||||
@ -28,7 +21,7 @@ func MakeScalingHandler(next http.HandlerFunc, scaler scaling.FunctionScaler, co
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
functionName, namespace := getNamespace(defaultNamespace, getServiceName(r.URL.String()))
|
||||
functionName, namespace := middleware.GetNamespace(defaultNamespace, middleware.GetServiceName(r.URL.String()))
|
||||
|
||||
res := scaler.Scale(functionName, namespace)
|
||||
|
||||
@ -55,6 +48,7 @@ func MakeScalingHandler(next http.HandlerFunc, scaler scaling.FunctionScaler, co
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[Scale] function=%s.%s 0=>N timed-out after %fs\n", functionName, namespace, res.Duration.Seconds())
|
||||
log.Printf("[Scale] function=%s.%s 0=>N timed-out after %.4fs\n",
|
||||
functionName, namespace, res.Duration.Seconds())
|
||||
}
|
||||
}
|
||||
|
123
gateway/main.go
123
gateway/main.go
@ -26,10 +26,6 @@ const NameExpression = "-a-zA-Z_0-9."
|
||||
|
||||
func main() {
|
||||
|
||||
if len(version.GitCommitMessage) == 0 {
|
||||
version.GitCommitMessage = "See GitHub for latest changes"
|
||||
}
|
||||
|
||||
osEnv := types.OsEnv{}
|
||||
readConfig := types.ReadConfig{}
|
||||
config, configErr := readConfig.Read(osEnv)
|
||||
@ -37,15 +33,18 @@ func main() {
|
||||
if configErr != nil {
|
||||
log.Fatalln(configErr)
|
||||
}
|
||||
|
||||
log.Printf("HTTP Read Timeout: %s", config.ReadTimeout)
|
||||
log.Printf("HTTP Write Timeout: %s", config.WriteTimeout)
|
||||
|
||||
if !config.UseExternalProvider() {
|
||||
log.Fatalln("You must provide an external provider via 'functions_provider_url' env-var.")
|
||||
}
|
||||
|
||||
log.Printf("Binding to external function provider: %s", config.FunctionsProviderURL)
|
||||
fmt.Printf("OpenFaaS Gateway - Community Edition (CE)\n"+
|
||||
"\nVersion: %s Commit: %s\nTimeouts: read=%s\twrite=%s\tupstream=%s\nFunction provider: %s\n\n",
|
||||
version.BuildVersion(),
|
||||
version.GitCommitSHA,
|
||||
config.ReadTimeout,
|
||||
config.WriteTimeout,
|
||||
config.UpstreamTimeout,
|
||||
config.FunctionsProviderURL)
|
||||
|
||||
// credentials is used for service-to-service auth
|
||||
var credentials *auth.BasicAuthCredentials
|
||||
@ -66,9 +65,6 @@ func main() {
|
||||
|
||||
servicePollInterval := time.Second * 5
|
||||
|
||||
metadataQuery := metrics.NewMetadataQuery(credentials)
|
||||
fmt.Println(metadataQuery)
|
||||
|
||||
metricsOptions := metrics.BuildMetricsOptions()
|
||||
exporter := metrics.NewExporter(metricsOptions, credentials, config.Namespace)
|
||||
exporter.StartServiceWatcher(*config.FunctionsProviderURL, metricsOptions, "func", servicePollInterval)
|
||||
@ -86,29 +82,18 @@ func main() {
|
||||
FunctionNamespace: config.Namespace,
|
||||
}
|
||||
|
||||
prometheusServiceNotifier := handlers.PrometheusServiceNotifier{
|
||||
ServiceMetrics: metricsOptions.ServiceMetrics,
|
||||
}
|
||||
|
||||
functionNotifiers := []handlers.HTTPNotifier{loggingNotifier, prometheusNotifier}
|
||||
forwardingNotifiers := []handlers.HTTPNotifier{loggingNotifier, prometheusServiceNotifier}
|
||||
forwardingNotifiers := []handlers.HTTPNotifier{loggingNotifier}
|
||||
quietNotifier := []handlers.HTTPNotifier{}
|
||||
|
||||
urlResolver := handlers.SingleHostBaseURLResolver{BaseURL: config.FunctionsProviderURL.String()}
|
||||
var functionURLResolver handlers.BaseURLResolver
|
||||
var functionURLTransformer handlers.URLPathTransformer
|
||||
nilURLTransformer := handlers.TransparentURLPathTransformer{}
|
||||
trimURLTransformer := handlers.FunctionPrefixTrimmingURLPathTransformer{}
|
||||
urlResolver := middleware.SingleHostBaseURLResolver{BaseURL: config.FunctionsProviderURL.String()}
|
||||
var functionURLResolver middleware.BaseURLResolver
|
||||
var functionURLTransformer middleware.URLPathTransformer
|
||||
nilURLTransformer := middleware.TransparentURLPathTransformer{}
|
||||
trimURLTransformer := middleware.FunctionPrefixTrimmingURLPathTransformer{}
|
||||
|
||||
if config.DirectFunctions {
|
||||
functionURLResolver = handlers.FunctionAsHostBaseURLResolver{
|
||||
FunctionSuffix: config.DirectFunctionsSuffix,
|
||||
FunctionNamespace: config.Namespace,
|
||||
}
|
||||
functionURLTransformer = trimURLTransformer
|
||||
} else {
|
||||
functionURLResolver = urlResolver
|
||||
functionURLTransformer = nilURLTransformer
|
||||
}
|
||||
functionURLResolver = urlResolver
|
||||
functionURLTransformer = nilURLTransformer
|
||||
|
||||
var serviceAuthInjector middleware.AuthInjector
|
||||
|
||||
@ -116,7 +101,20 @@ func main() {
|
||||
serviceAuthInjector = &middleware.BasicAuthInjector{Credentials: credentials}
|
||||
}
|
||||
|
||||
decorateExternalAuth := handlers.MakeExternalAuthHandler
|
||||
// externalServiceQuery is used to query metadata from the provider about a function
|
||||
externalServiceQuery := plugin.NewExternalServiceQuery(*config.FunctionsProviderURL, serviceAuthInjector)
|
||||
|
||||
scalingConfig := scaling.ScalingConfig{
|
||||
MaxPollCount: uint(1000),
|
||||
SetScaleRetries: uint(20),
|
||||
FunctionPollInterval: time.Millisecond * 100,
|
||||
CacheExpiry: time.Millisecond * 250, // freshness of replica values before going stale
|
||||
ServiceQuery: externalServiceQuery,
|
||||
}
|
||||
|
||||
// This cache can be used to query a function's annotations.
|
||||
functionAnnotationCache := scaling.NewFunctionCache(scalingConfig.CacheExpiry)
|
||||
cachedFunctionQuery := scaling.NewCachedFunctionQuery(functionAnnotationCache, externalServiceQuery)
|
||||
|
||||
faasHandlers.Proxy = handlers.MakeCallIDMiddleware(
|
||||
handlers.MakeForwardingProxyHandler(reverseProxy, functionNotifiers, functionURLResolver, functionURLTransformer, nil),
|
||||
@ -133,31 +131,25 @@ func main() {
|
||||
|
||||
faasHandlers.NamespaceListerHandler = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||
|
||||
externalServiceQuery := plugin.NewExternalServiceQuery(*config.FunctionsProviderURL, serviceAuthInjector)
|
||||
faasHandlers.Alert = handlers.MakeNotifierWrapper(
|
||||
handlers.MakeAlertHandler(externalServiceQuery, config.Namespace),
|
||||
forwardingNotifiers,
|
||||
quietNotifier,
|
||||
)
|
||||
|
||||
faasHandlers.LogProxyHandler = handlers.NewLogHandlerFunc(*config.LogsProviderURL, config.WriteTimeout)
|
||||
|
||||
scalingConfig := scaling.ScalingConfig{
|
||||
MaxPollCount: uint(1000),
|
||||
SetScaleRetries: uint(20),
|
||||
FunctionPollInterval: time.Millisecond * 100,
|
||||
CacheExpiry: time.Millisecond * 250, // freshness of replica values before going stale
|
||||
ServiceQuery: externalServiceQuery,
|
||||
}
|
||||
|
||||
functionProxy := faasHandlers.Proxy
|
||||
|
||||
if config.ScaleFromZero {
|
||||
scalingFunctionCache := scaling.NewFunctionCache(scalingConfig.CacheExpiry)
|
||||
scaler := scaling.NewFunctionScaler(scalingConfig, scalingFunctionCache)
|
||||
functionProxy = handlers.MakeScalingHandler(faasHandlers.Proxy, scaler, scalingConfig, config.Namespace)
|
||||
functionProxy = handlers.MakeScalingHandler(functionProxy, scaler, scalingConfig, config.Namespace)
|
||||
}
|
||||
|
||||
if config.UseNATS() {
|
||||
log.Println("Async enabled: Using NATS Streaming.")
|
||||
log.Println("Async enabled: Using NATS Streaming")
|
||||
log.Println("Deprecation Notice: NATS Streaming is no longer maintained and won't receive updates from June 2023")
|
||||
|
||||
maxReconnect := 60
|
||||
interval := time.Second * 2
|
||||
|
||||
@ -168,44 +160,39 @@ func main() {
|
||||
log.Fatalln(queueErr)
|
||||
}
|
||||
|
||||
queueFunctionCache := scaling.NewFunctionCache(scalingConfig.CacheExpiry)
|
||||
functionQuery := scaling.NewCachedFunctionQuery(queueFunctionCache, externalServiceQuery)
|
||||
|
||||
faasHandlers.QueuedProxy = handlers.MakeNotifierWrapper(
|
||||
handlers.MakeCallIDMiddleware(handlers.MakeQueuedProxy(metricsOptions, natsQueue, trimURLTransformer, config.Namespace, functionQuery)),
|
||||
handlers.MakeCallIDMiddleware(handlers.MakeQueuedProxy(metricsOptions, natsQueue, trimURLTransformer, config.Namespace, cachedFunctionQuery)),
|
||||
forwardingNotifiers,
|
||||
)
|
||||
}
|
||||
|
||||
prometheusQuery := metrics.NewPrometheusQuery(config.PrometheusHost, config.PrometheusPort, &http.Client{})
|
||||
faasHandlers.ListFunctions = metrics.AddMetricsHandler(faasHandlers.ListFunctions, prometheusQuery)
|
||||
faasHandlers.ScaleFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||
faasHandlers.ScaleFunction = scaling.MakeHorizontalScalingHandler(handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector))
|
||||
|
||||
if credentials != nil {
|
||||
faasHandlers.Alert =
|
||||
decorateExternalAuth(faasHandlers.Alert, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.Alert, credentials)
|
||||
faasHandlers.UpdateFunction =
|
||||
decorateExternalAuth(faasHandlers.UpdateFunction, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.UpdateFunction, credentials)
|
||||
faasHandlers.DeleteFunction =
|
||||
decorateExternalAuth(faasHandlers.DeleteFunction, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.DeleteFunction, credentials)
|
||||
faasHandlers.DeployFunction =
|
||||
decorateExternalAuth(faasHandlers.DeployFunction, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.DeployFunction, credentials)
|
||||
faasHandlers.ListFunctions =
|
||||
decorateExternalAuth(faasHandlers.ListFunctions, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.ListFunctions, credentials)
|
||||
faasHandlers.ScaleFunction =
|
||||
decorateExternalAuth(faasHandlers.ScaleFunction, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.ScaleFunction, credentials)
|
||||
faasHandlers.FunctionStatus =
|
||||
decorateExternalAuth(faasHandlers.FunctionStatus, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.FunctionStatus, credentials)
|
||||
faasHandlers.InfoHandler =
|
||||
decorateExternalAuth(faasHandlers.InfoHandler, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
faasHandlers.AsyncReport =
|
||||
decorateExternalAuth(faasHandlers.AsyncReport, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.InfoHandler, credentials)
|
||||
faasHandlers.SecretHandler =
|
||||
decorateExternalAuth(faasHandlers.SecretHandler, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.SecretHandler, credentials)
|
||||
faasHandlers.LogProxyHandler =
|
||||
decorateExternalAuth(faasHandlers.LogProxyHandler, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.LogProxyHandler, credentials)
|
||||
faasHandlers.NamespaceListerHandler =
|
||||
decorateExternalAuth(faasHandlers.NamespaceListerHandler, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)
|
||||
auth.DecorateWithBasicAuth(faasHandlers.NamespaceListerHandler, credentials)
|
||||
}
|
||||
|
||||
r := mux.NewRouter()
|
||||
@ -234,8 +221,6 @@ func main() {
|
||||
r.HandleFunc("/async-function/{name:["+NameExpression+"]+}/", faasHandlers.QueuedProxy).Methods(http.MethodPost)
|
||||
r.HandleFunc("/async-function/{name:["+NameExpression+"]+}", faasHandlers.QueuedProxy).Methods(http.MethodPost)
|
||||
r.HandleFunc("/async-function/{name:["+NameExpression+"]+}/{params:.*}", faasHandlers.QueuedProxy).Methods(http.MethodPost)
|
||||
|
||||
r.HandleFunc("/system/async-report", handlers.MakeNotifierWrapper(faasHandlers.AsyncReport, forwardingNotifiers))
|
||||
}
|
||||
|
||||
fs := http.FileServer(http.Dir("./assets/"))
|
||||
@ -247,9 +232,11 @@ func main() {
|
||||
uiHandler := http.StripPrefix("/ui", fsCORS)
|
||||
if credentials != nil {
|
||||
r.PathPrefix("/ui/").Handler(
|
||||
decorateExternalAuth(uiHandler.ServeHTTP, config.UpstreamTimeout, config.AuthProxyURL, config.AuthProxyPassBody)).Methods(http.MethodGet)
|
||||
auth.DecorateWithBasicAuth(uiHandler.ServeHTTP, credentials)).
|
||||
Methods(http.MethodGet)
|
||||
} else {
|
||||
r.PathPrefix("/ui/").Handler(uiHandler).Methods(http.MethodGet)
|
||||
r.PathPrefix("/ui/").Handler(uiHandler).
|
||||
Methods(http.MethodGet)
|
||||
}
|
||||
|
||||
//Start metrics server in a goroutine
|
||||
@ -273,7 +260,7 @@ func main() {
|
||||
log.Fatal(s.ListenAndServe())
|
||||
}
|
||||
|
||||
//runMetricsServer Listen on a separate HTTP port for Prometheus metrics to keep this accessible from
|
||||
// runMetricsServer Listen on a separate HTTP port for Prometheus metrics to keep this accessible from
|
||||
// the internal network only.
|
||||
func runMetricsServer() {
|
||||
metricsHandler := metrics.PrometheusHandler()
|
||||
|
@ -34,19 +34,17 @@ func AddMetricsHandler(handler http.HandlerFunc, prometheusQuery PrometheusQuery
|
||||
log.Printf("List functions responded with code %d, body: %s",
|
||||
recorder.Code,
|
||||
string(upstreamBody))
|
||||
|
||||
http.Error(w, "Metrics hander: unexpected status code retrieving functions from backend", http.StatusInternalServerError)
|
||||
http.Error(w, string(upstreamBody), recorder.Code)
|
||||
return
|
||||
}
|
||||
|
||||
var functions []types.FunctionStatus
|
||||
|
||||
err := json.Unmarshal(upstreamBody, &functions)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Metrics upstream error: %s", err)
|
||||
log.Printf("Metrics upstream error: %s, value: %s", err, string(upstreamBody))
|
||||
|
||||
http.Error(w, "Error parsing metrics from upstream provider/backend", http.StatusInternalServerError)
|
||||
http.Error(w, "Unable to parse list of functions from provider", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@ -63,8 +61,8 @@ func AddMetricsHandler(handler http.HandlerFunc, prometheusQuery PrometheusQuery
|
||||
|
||||
results, err := prometheusQuery.Fetch(url.QueryEscape(q))
|
||||
if err != nil {
|
||||
// log the error but continue, the mixIn will correctly handle the empty results.
|
||||
log.Printf("Error querying Prometheus: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
mixIn(&functions, results)
|
||||
}
|
||||
@ -72,7 +70,7 @@ func AddMetricsHandler(handler http.HandlerFunc, prometheusQuery PrometheusQuery
|
||||
bytesOut, err := json.Marshal(functions)
|
||||
if err != nil {
|
||||
log.Printf("Error serializing functions: %s", err)
|
||||
http.Error(w, "error writing response after adding metrics", http.StatusInternalServerError)
|
||||
http.Error(w, "Error writing response after adding metrics", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
types "github.com/openfaas/faas-provider/types"
|
||||
@ -55,6 +56,34 @@ func Test_PrometheusMetrics_MixedInto_Services(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MetricHandler_ForwardsErrors(t *testing.T) {
|
||||
functionsHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
w.Write([]byte("test error case"))
|
||||
}
|
||||
// explicitly set the query fetcher to nil because it should
|
||||
// not be called when a non-200 response is returned from the
|
||||
// functions handler, if it is called then the test will panic
|
||||
handler := AddMetricsHandler(functionsHandler, nil)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest(http.MethodGet, "/system/functions", nil)
|
||||
handler.ServeHTTP(rr, request)
|
||||
|
||||
if status := rr.Code; status != http.StatusConflict {
|
||||
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusConflict)
|
||||
}
|
||||
|
||||
if rr.Header().Get("Content-Type") != "text/plain; charset=utf-8" {
|
||||
t.Errorf("Want 'text/plain; charset=utf-8' content-type, got: %s", rr.Header().Get("Content-Type"))
|
||||
}
|
||||
body := strings.TrimSpace(rr.Body.String())
|
||||
if body != "test error case" {
|
||||
t.Errorf("Want 'test error case', got: %q", body)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_FunctionsHandler_ReturnsJSONAndOneFunction(t *testing.T) {
|
||||
functionsHandler := makeFunctionsHandler()
|
||||
|
||||
|
@ -12,14 +12,12 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"log"
|
||||
|
||||
"github.com/openfaas/faas-provider/auth"
|
||||
types "github.com/openfaas/faas-provider/types"
|
||||
"github.com/openfaas/faas/gateway/scaling"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@ -48,10 +46,6 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
||||
e.metricOptions.GatewayFunctionsHistogram.Describe(ch)
|
||||
e.metricOptions.ServiceReplicasGauge.Describe(ch)
|
||||
e.metricOptions.GatewayFunctionInvocationStarted.Describe(ch)
|
||||
e.metricOptions.ServiceTargetLoadGauge.Describe(ch)
|
||||
|
||||
e.metricOptions.ServiceMetrics.Counter.Describe(ch)
|
||||
e.metricOptions.ServiceMetrics.Histogram.Describe(ch)
|
||||
}
|
||||
|
||||
// Collect collects data to be consumed by prometheus
|
||||
@ -62,7 +56,6 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
||||
e.metricOptions.GatewayFunctionInvocationStarted.Collect(ch)
|
||||
|
||||
e.metricOptions.ServiceReplicasGauge.Reset()
|
||||
e.metricOptions.ServiceTargetLoadGauge.Reset()
|
||||
|
||||
for _, service := range e.services {
|
||||
var serviceName string
|
||||
@ -76,52 +69,9 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
||||
e.metricOptions.ServiceReplicasGauge.
|
||||
WithLabelValues(serviceName).
|
||||
Set(float64(service.Replicas))
|
||||
|
||||
// Set minimum replicas
|
||||
minReplicas := scaling.DefaultMinReplicas
|
||||
if service.Labels != nil {
|
||||
a := *service.Labels
|
||||
if v, ok := a[scaling.MinScaleLabel]; ok && len(v) > 0 {
|
||||
val, _ := strconv.Atoi(v)
|
||||
minReplicas = val
|
||||
}
|
||||
}
|
||||
|
||||
e.metricOptions.ServiceMinReplicasGauge.
|
||||
WithLabelValues(serviceName).
|
||||
Set(float64(minReplicas))
|
||||
|
||||
// Set scale type
|
||||
scaleType := scaling.DefaultTypeScale
|
||||
if service.Labels != nil {
|
||||
a := *service.Labels
|
||||
if v, ok := a[scaling.ScaleTypeLabel]; ok && len(v) > 0 {
|
||||
scaleType = v
|
||||
}
|
||||
}
|
||||
|
||||
// Set target load
|
||||
targetScale := scaling.DefaultTargetLoad
|
||||
if service.Labels != nil {
|
||||
a := *service.Labels
|
||||
if v, ok := a[scaling.TargetLoadLabel]; ok && len(v) > 0 {
|
||||
val, _ := strconv.Atoi(v)
|
||||
targetScale = val
|
||||
}
|
||||
}
|
||||
|
||||
e.metricOptions.ServiceTargetLoadGauge.
|
||||
WithLabelValues(serviceName, scaleType).
|
||||
Set(float64(targetScale))
|
||||
|
||||
}
|
||||
|
||||
e.metricOptions.ServiceReplicasGauge.Collect(ch)
|
||||
e.metricOptions.ServiceMinReplicasGauge.Collect(ch)
|
||||
e.metricOptions.ServiceTargetLoadGauge.Collect(ch)
|
||||
|
||||
e.metricOptions.ServiceMetrics.Counter.Collect(ch)
|
||||
e.metricOptions.ServiceMetrics.Histogram.Collect(ch)
|
||||
}
|
||||
|
||||
// StartServiceWatcher starts a ticker and collects service replica counts to expose to prometheus
|
||||
@ -188,7 +138,7 @@ func (e *Exporter) getHTTPClient(timeout time.Duration) http.Client {
|
||||
}
|
||||
|
||||
func (e *Exporter) getFunctions(endpointURL url.URL, namespace string) ([]types.FunctionStatus, error) {
|
||||
timeout := 3 * time.Second
|
||||
timeout := 5 * time.Second
|
||||
proxyClient := e.getHTTPClient(timeout)
|
||||
|
||||
endpointURL.Path = path.Join(endpointURL.Path, "/system/functions")
|
||||
@ -214,10 +164,11 @@ func (e *Exporter) getFunctions(endpointURL url.URL, namespace string) ([]types.
|
||||
return services, readErr
|
||||
}
|
||||
|
||||
unmarshalErr := json.Unmarshal(bytesOut, &services)
|
||||
if unmarshalErr != nil {
|
||||
return services, unmarshalErr
|
||||
if err := json.Unmarshal(bytesOut, &services); err != nil {
|
||||
return services, fmt.Errorf("error unmarshalling response: %s, error: %s",
|
||||
string(bytesOut), err)
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
@ -230,7 +181,7 @@ func (e *Exporter) getNamespaces(endpointURL url.URL) ([]string, error) {
|
||||
get.SetBasicAuth(e.credentials.User, e.credentials.Password)
|
||||
}
|
||||
|
||||
timeout := 3 * time.Second
|
||||
timeout := 5 * time.Second
|
||||
proxyClient := e.getHTTPClient(timeout)
|
||||
|
||||
res, err := proxyClient.Do(get)
|
||||
@ -247,9 +198,8 @@ func (e *Exporter) getNamespaces(endpointURL url.URL) ([]string, error) {
|
||||
return namespaces, readErr
|
||||
}
|
||||
|
||||
unmarshalErr := json.Unmarshal(bytesOut, &namespaces)
|
||||
if unmarshalErr != nil {
|
||||
return namespaces, unmarshalErr
|
||||
if err := json.Unmarshal(bytesOut, &namespaces); err != nil {
|
||||
return namespaces, fmt.Errorf("error unmarshalling response: %s, error: %s", string(bytesOut), err)
|
||||
}
|
||||
return namespaces, nil
|
||||
}
|
||||
|
@ -17,11 +17,7 @@ type MetricOptions struct {
|
||||
GatewayFunctionsHistogram *prometheus.HistogramVec
|
||||
GatewayFunctionInvocationStarted *prometheus.CounterVec
|
||||
|
||||
ServiceReplicasGauge *prometheus.GaugeVec
|
||||
ServiceMinReplicasGauge *prometheus.GaugeVec
|
||||
ServiceTargetLoadGauge *prometheus.GaugeVec
|
||||
|
||||
ServiceMetrics *ServiceMetricOptions
|
||||
ServiceReplicasGauge *prometheus.GaugeVec
|
||||
}
|
||||
|
||||
// ServiceMetricOptions provides RED metrics
|
||||
@ -71,42 +67,6 @@ func BuildMetricsOptions() MetricOptions {
|
||||
[]string{"function_name"},
|
||||
)
|
||||
|
||||
serviceMinReplicas := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "gateway",
|
||||
Name: "service_min",
|
||||
Help: "Minium replicas for function",
|
||||
},
|
||||
[]string{"function_name"},
|
||||
)
|
||||
|
||||
serviceTargetLoad := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "gateway",
|
||||
Name: "service_target_load",
|
||||
Help: "Target load for function",
|
||||
},
|
||||
[]string{"function_name", "scaling_type"},
|
||||
)
|
||||
|
||||
// For automatic monitoring and alerting (RED method)
|
||||
histogram := prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Subsystem: "http",
|
||||
Name: "request_duration_seconds",
|
||||
Help: "Seconds spent serving HTTP requests.",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"method", "path", "status"})
|
||||
|
||||
// Can be used Kubernetes HPA v2
|
||||
counter := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Subsystem: "http",
|
||||
Name: "requests_total",
|
||||
Help: "The total number of HTTP requests.",
|
||||
},
|
||||
[]string{"method", "path", "status"},
|
||||
)
|
||||
|
||||
gatewayFunctionInvocationStarted := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: "gateway",
|
||||
@ -117,18 +77,10 @@ func BuildMetricsOptions() MetricOptions {
|
||||
[]string{"function_name"},
|
||||
)
|
||||
|
||||
serviceMetricOptions := &ServiceMetricOptions{
|
||||
Counter: counter,
|
||||
Histogram: histogram,
|
||||
}
|
||||
|
||||
metricsOptions := MetricOptions{
|
||||
GatewayFunctionsHistogram: gatewayFunctionsHistogram,
|
||||
GatewayFunctionInvocation: gatewayFunctionInvocation,
|
||||
ServiceReplicasGauge: serviceReplicas,
|
||||
ServiceMinReplicasGauge: serviceMinReplicas,
|
||||
ServiceTargetLoadGauge: serviceTargetLoad,
|
||||
ServiceMetrics: serviceMetricOptions,
|
||||
GatewayFunctionInvocationStarted: gatewayFunctionInvocationStarted,
|
||||
}
|
||||
|
||||
|
155
gateway/pkg/middleware/baseurlresolver_test.go
Normal file
155
gateway/pkg/middleware/baseurlresolver_test.go
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (c) OpenFaaS Author(s). All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_SingleHostBaseURLResolver_BuildURL(t *testing.T) {
|
||||
|
||||
newNamespace := "production-fn"
|
||||
function := "figlet"
|
||||
r := SingleHostBaseURLResolver{BaseURL: "http://faas-netes.openfaas:8080"}
|
||||
|
||||
want := "http://faas-netes.openfaas:8080/function/figlet.production-fn/healthz"
|
||||
|
||||
got := r.BuildURL(function, newNamespace, "/healthz", true)
|
||||
if got != want {
|
||||
t.Fatalf("r.URL failed, want: %s got: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SingleHostBaseURLResolver_BuildURL_DefaultNamespace(t *testing.T) {
|
||||
|
||||
newNamespace := "openfaas-fn"
|
||||
function := "figlet"
|
||||
r := SingleHostBaseURLResolver{BaseURL: "http://faas-netes.openfaas:8080"}
|
||||
|
||||
want := "http://faas-netes.openfaas:8080/function/figlet.openfaas-fn/_/health"
|
||||
|
||||
got := r.BuildURL(function, newNamespace, "/_/health", true)
|
||||
if got != want {
|
||||
t.Fatalf("r.URL failed, want: %s got: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSingleHostBaseURLResolver(t *testing.T) {
|
||||
|
||||
urlVal, _ := url.Parse("http://upstream:8080/")
|
||||
r := SingleHostBaseURLResolver{BaseURL: urlVal.String()}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/function/hello", nil)
|
||||
|
||||
resolved := r.Resolve(req)
|
||||
want := "http://upstream:8080"
|
||||
if resolved != want {
|
||||
t.Logf("r.Resolve failed, want: %s got: %s", want, resolved)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
const watchdogPort = 8080
|
||||
|
||||
func TestURL_NonDefaultNamespaceWithPath(t *testing.T) {
|
||||
suffix := "openfaas-fn.local.cluster.svc"
|
||||
namespace := "openfaas-fn"
|
||||
newNamespace := "production-fn"
|
||||
function := "figlet"
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix, FunctionNamespace: namespace}
|
||||
|
||||
want := "http://figlet.production-fn.local.cluster.svc:8080/healthz"
|
||||
|
||||
got := r.BuildURL(function, newNamespace, "/healthz", true)
|
||||
if got != want {
|
||||
t.Fatalf("r.URL failed, want: %s got: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestURL_NonDefaultNamespaceWithout(t *testing.T) {
|
||||
suffix := "openfaas-fn.local.cluster.svc"
|
||||
namespace := "openfaas-fn"
|
||||
newNamespace := "production-fn"
|
||||
function := "figlet"
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix, FunctionNamespace: namespace}
|
||||
|
||||
want := "http://figlet.production-fn.local.cluster.svc:8080"
|
||||
|
||||
got := r.BuildURL(function, newNamespace, "", true)
|
||||
if got != want {
|
||||
t.Fatalf("r.URL failed, want: %s got: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestURL_DefaultNamespaceWithPath(t *testing.T) {
|
||||
suffix := "openfaas-fn.local.cluster.svc"
|
||||
namespace := "openfaas-fn"
|
||||
newNamespace := "production-fn"
|
||||
function := "figlet"
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix, FunctionNamespace: namespace}
|
||||
|
||||
want := "http://figlet.production-fn.local.cluster.svc:8080/_/health"
|
||||
|
||||
got := r.BuildURL(function, newNamespace, "/_/health", true)
|
||||
if got != want {
|
||||
t.Fatalf("r.URL failed, want: %s got: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunctionAsHostBaseURLResolver_WithNamespaceOverride(t *testing.T) {
|
||||
|
||||
suffix := "openfaas-fn.local.cluster.svc."
|
||||
namespace := "openfaas-fn"
|
||||
newNS := "production-fn"
|
||||
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix, FunctionNamespace: namespace}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/function/hello."+newNS, nil)
|
||||
|
||||
resolved := r.Resolve(req)
|
||||
|
||||
newSuffix := strings.Replace(suffix, namespace, newNS, -1)
|
||||
|
||||
want := fmt.Sprintf("http://hello.%s:%d", newSuffix, watchdogPort)
|
||||
log.Println(want)
|
||||
if resolved != want {
|
||||
t.Logf("r.Resolve failed, want: %s got: %s", want, resolved)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunctionAsHostBaseURLResolver_WithSuffix(t *testing.T) {
|
||||
suffix := "openfaas-fn.local.cluster.svc."
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/function/hello", nil)
|
||||
|
||||
resolved := r.Resolve(req)
|
||||
want := fmt.Sprintf("http://hello.%s:%d", suffix, watchdogPort)
|
||||
log.Println(want)
|
||||
if resolved != want {
|
||||
t.Logf("r.Resolve failed, want: %s got: %s", want, resolved)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunctionAsHostBaseURLResolver_WithoutSuffix(t *testing.T) {
|
||||
suffix := ""
|
||||
r := FunctionAsHostBaseURLResolver{FunctionSuffix: suffix}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/function/hello", nil)
|
||||
|
||||
resolved := r.Resolve(req)
|
||||
want := fmt.Sprintf("http://hello%s:%d", suffix, watchdogPort)
|
||||
|
||||
if resolved != want {
|
||||
t.Logf("r.Resolve failed, want: %s got: %s", want, resolved)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) OpenFaaS Author(s). All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
package handlers
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
156
gateway/pkg/middleware/resolver.go
Normal file
156
gateway/pkg/middleware/resolver.go
Normal file
@ -0,0 +1,156 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// functionMatcher parses out the service name (group 1) and rest of path (group 2).
|
||||
var functionMatcher = regexp.MustCompile("^/?(?:async-)?function/([^/?]+)([^?]*)")
|
||||
|
||||
// Indices and meta-data for functionMatcher regex parts
|
||||
const (
|
||||
hasPathCount = 3
|
||||
routeIndex = 0 // routeIndex corresponds to /function/ or /async-function/
|
||||
nameIndex = 1 // nameIndex is the function name
|
||||
pathIndex = 2 // pathIndex is the path i.e. /employee/:id/
|
||||
)
|
||||
|
||||
// BaseURLResolver URL resolver for upstream requests
|
||||
type BaseURLResolver interface {
|
||||
Resolve(r *http.Request) string
|
||||
BuildURL(function, namespace, healthPath string, directFunctions bool) string
|
||||
}
|
||||
|
||||
// URLPathTransformer Transform the incoming URL path for upstream requests
|
||||
type URLPathTransformer interface {
|
||||
Transform(r *http.Request) string
|
||||
}
|
||||
|
||||
// SingleHostBaseURLResolver resolves URLs against a single BaseURL
|
||||
type SingleHostBaseURLResolver struct {
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
func (s SingleHostBaseURLResolver) BuildURL(function, namespace, healthPath string, directFunctions bool) string {
|
||||
u, _ := url.Parse(s.BaseURL)
|
||||
|
||||
base := fmt.Sprintf("/function/%s.%s/", function, namespace)
|
||||
|
||||
if len(healthPath) > 0 {
|
||||
u.Path = path.Join(base, healthPath)
|
||||
} else {
|
||||
u.Path = base
|
||||
}
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// Resolve the base URL for a request
|
||||
func (s SingleHostBaseURLResolver) Resolve(r *http.Request) string {
|
||||
|
||||
baseURL := s.BaseURL
|
||||
|
||||
if strings.HasSuffix(baseURL, "/") {
|
||||
baseURL = baseURL[0 : len(baseURL)-1]
|
||||
}
|
||||
return baseURL
|
||||
}
|
||||
|
||||
// FunctionAsHostBaseURLResolver resolves URLs using a function from the URL as a host
|
||||
type FunctionAsHostBaseURLResolver struct {
|
||||
FunctionSuffix string
|
||||
FunctionNamespace string
|
||||
}
|
||||
|
||||
// Resolve the base URL for a request
|
||||
func (f FunctionAsHostBaseURLResolver) Resolve(r *http.Request) string {
|
||||
svcName := GetServiceName(r.URL.Path)
|
||||
|
||||
const watchdogPort = 8080
|
||||
var suffix string
|
||||
|
||||
if len(f.FunctionSuffix) > 0 {
|
||||
if index := strings.LastIndex(svcName, "."); index > -1 && len(svcName) > index+1 {
|
||||
suffix = strings.Replace(f.FunctionSuffix, f.FunctionNamespace, "", -1)
|
||||
} else {
|
||||
suffix = "." + f.FunctionSuffix
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("http://%s%s:%d", svcName, suffix, watchdogPort)
|
||||
}
|
||||
|
||||
func (f FunctionAsHostBaseURLResolver) BuildURL(function, namespace, healthPath string, directFunctions bool) string {
|
||||
svcName := function
|
||||
|
||||
const watchdogPort = 8080
|
||||
var suffix string
|
||||
|
||||
if len(f.FunctionSuffix) > 0 {
|
||||
suffix = strings.Replace(f.FunctionSuffix, f.FunctionNamespace, namespace, 1)
|
||||
}
|
||||
|
||||
u, _ := url.Parse(fmt.Sprintf("http://%s.%s:%d", svcName, suffix, watchdogPort))
|
||||
if len(healthPath) > 0 {
|
||||
u.Path = healthPath
|
||||
}
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// TransparentURLPathTransformer passes the requested URL path through untouched.
|
||||
type TransparentURLPathTransformer struct {
|
||||
}
|
||||
|
||||
// Transform returns the URL path unchanged.
|
||||
func (f TransparentURLPathTransformer) Transform(r *http.Request) string {
|
||||
return r.URL.Path
|
||||
}
|
||||
|
||||
// FunctionPrefixTrimmingURLPathTransformer removes the "/function/servicename/" prefix from the URL path.
|
||||
type FunctionPrefixTrimmingURLPathTransformer struct {
|
||||
}
|
||||
|
||||
// Transform removes the "/function/servicename/" prefix from the URL path.
|
||||
func (f FunctionPrefixTrimmingURLPathTransformer) Transform(r *http.Request) string {
|
||||
ret := r.URL.Path
|
||||
|
||||
if ret != "" {
|
||||
// When forwarding to a function, since the `/function/xyz` portion
|
||||
// of a path like `/function/xyz/rest/of/path` is only used or needed
|
||||
// by the Gateway, we want to trim it down to `/rest/of/path` for the
|
||||
// upstream request. In the following regex, in the case of a match
|
||||
// the r.URL.Path will be at `0`, the function name at `1` and the
|
||||
// rest of the path (the part we are interested in) at `2`.
|
||||
matcher := functionMatcher.Copy()
|
||||
parts := matcher.FindStringSubmatch(ret)
|
||||
if len(parts) == hasPathCount {
|
||||
ret = parts[pathIndex]
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetServiceName(urlValue string) string {
|
||||
var serviceName string
|
||||
forward := "/function/"
|
||||
if strings.HasPrefix(urlValue, forward) {
|
||||
// With a path like `/function/xyz/rest/of/path?q=a`, the service
|
||||
// name we wish to locate is just the `xyz` portion. With a positive
|
||||
// match on the regex below, it will return a three-element slice.
|
||||
// The item at index `0` is the same as `urlValue`, at `1`
|
||||
// will be the service name we need, and at `2` the rest of the path.
|
||||
matcher := functionMatcher.Copy()
|
||||
matches := matcher.FindStringSubmatch(urlValue)
|
||||
if len(matches) == hasPathCount {
|
||||
serviceName = matches[nameIndex]
|
||||
}
|
||||
}
|
||||
return strings.Trim(serviceName, "/")
|
||||
}
|
10
gateway/pkg/middleware/service_name.go
Normal file
10
gateway/pkg/middleware/service_name.go
Normal file
@ -0,0 +1,10 @@
|
||||
package middleware
|
||||
|
||||
import "strings"
|
||||
|
||||
func GetNamespace(defaultNamespace, fullName string) (string, string) {
|
||||
if index := strings.LastIndex(fullName, "."); index > -1 {
|
||||
return fullName[:index], fullName[index+1:]
|
||||
}
|
||||
return fullName, defaultNamespace
|
||||
}
|
@ -2,6 +2,8 @@ package middleware
|
||||
|
||||
import "net/http"
|
||||
|
||||
// AuthInjector is an interface for injecting authentication information into a request
|
||||
// which will be proxied or made to a remote/upstream service.
|
||||
type AuthInjector interface {
|
||||
Inject(r *http.Request)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) OpenFaaS Author(s). All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
package handlers
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
@ -7,7 +7,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -32,7 +32,7 @@ type ExternalServiceQuery struct {
|
||||
|
||||
// NewExternalServiceQuery proxies service queries to external plugin via HTTP
|
||||
func NewExternalServiceQuery(externalURL url.URL, authInjector middleware.AuthInjector) scaling.ServiceQuery {
|
||||
timeout := 5 * time.Second
|
||||
timeout := 3 * time.Second
|
||||
|
||||
proxyClient := http.Client{
|
||||
Transport: &http.Transport{
|
||||
@ -82,35 +82,28 @@ func (s ExternalServiceQuery) GetReplicas(serviceName, serviceNamespace string)
|
||||
|
||||
res, err := s.ProxyClient.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("Unable to connect to %s, error: %s", urlPath, err)
|
||||
log.Println(urlPath, err)
|
||||
return emptyServiceQueryResponse, err
|
||||
|
||||
}
|
||||
|
||||
var bytesOut []byte
|
||||
if res.Body != nil {
|
||||
bytesOut, _ = io.ReadAll(res.Body)
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
if res.StatusCode == http.StatusOK {
|
||||
if err := json.Unmarshal(bytesOut, &function); err != nil {
|
||||
log.Printf("Unable to unmarshal: %q, %s", string(bytesOut), err)
|
||||
return emptyServiceQueryResponse, err
|
||||
}
|
||||
|
||||
// log.Printf("GetReplicas [%s.%s] took: %fs", serviceName, serviceNamespace, time.Since(start).Seconds())
|
||||
|
||||
} else {
|
||||
|
||||
var body []byte
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
body, _ = ioutil.ReadAll(res.Body)
|
||||
}
|
||||
|
||||
if res.StatusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &function)
|
||||
if err != nil {
|
||||
log.Printf("Unable to unmarshal %s, error: %s", string(body), err)
|
||||
}
|
||||
|
||||
log.Printf("GetReplicas [%s.%s] took: %fs",
|
||||
serviceName,
|
||||
serviceNamespace,
|
||||
time.Since(start).Seconds())
|
||||
|
||||
} else {
|
||||
log.Printf("GetReplicas [%s.%s] took: %fs, code: %d",
|
||||
serviceName,
|
||||
serviceNamespace,
|
||||
time.Since(start).Seconds(),
|
||||
res.StatusCode)
|
||||
|
||||
return emptyServiceQueryResponse, fmt.Errorf("server returned non-200 status code (%d) for function, %s", res.StatusCode, serviceName)
|
||||
}
|
||||
log.Printf("GetReplicas [%s.%s] took: %.4fs, code: %d\n", serviceName, serviceNamespace, time.Since(start).Seconds(), res.StatusCode)
|
||||
return emptyServiceQueryResponse, fmt.Errorf("server returned non-200 status code (%d) for function, %s, body: %s", res.StatusCode, serviceName, string(bytesOut))
|
||||
}
|
||||
|
||||
minReplicas := uint64(scaling.DefaultMinReplicas)
|
||||
@ -118,20 +111,17 @@ func (s ExternalServiceQuery) GetReplicas(serviceName, serviceNamespace string)
|
||||
scalingFactor := uint64(scaling.DefaultScalingFactor)
|
||||
availableReplicas := function.AvailableReplicas
|
||||
|
||||
targetLoad := uint64(scaling.DefaultTargetLoad)
|
||||
|
||||
if function.Labels != nil {
|
||||
labels := *function.Labels
|
||||
|
||||
minReplicas = extractLabelValue(labels[scaling.MinScaleLabel], minReplicas)
|
||||
maxReplicas = extractLabelValue(labels[scaling.MaxScaleLabel], maxReplicas)
|
||||
extractedScalingFactor := extractLabelValue(labels[scaling.ScalingFactorLabel], scalingFactor)
|
||||
targetLoad = extractLabelValue(labels[scaling.TargetLoadLabel], targetLoad)
|
||||
|
||||
if extractedScalingFactor > 0 && extractedScalingFactor <= 100 {
|
||||
scalingFactor = extractedScalingFactor
|
||||
} else {
|
||||
log.Printf("Bad Scaling Factor: %d, is not in range of [0 - 100]. Will fallback to %d", extractedScalingFactor, scalingFactor)
|
||||
return scaling.ServiceQueryResponse{}, fmt.Errorf("bad scaling factor: %d, is not in range of [0 - 100]", extractedScalingFactor)
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +132,6 @@ func (s ExternalServiceQuery) GetReplicas(serviceName, serviceNamespace string)
|
||||
ScalingFactor: scalingFactor,
|
||||
AvailableReplicas: availableReplicas,
|
||||
Annotations: function.Annotations,
|
||||
TargetLoad: targetLoad,
|
||||
}, err
|
||||
}
|
||||
|
||||
@ -183,7 +172,8 @@ func (s ExternalServiceQuery) SetReplicas(serviceName, serviceNamespace string,
|
||||
err = fmt.Errorf("error scaling HTTP code %d, %s", res.StatusCode, urlPath)
|
||||
}
|
||||
|
||||
log.Printf("SetReplicas [%s.%s] took: %fs", serviceName, serviceNamespace, time.Since(start).Seconds())
|
||||
log.Printf("SetReplicas [%s.%s] took: %.4fs",
|
||||
serviceName, serviceNamespace, time.Since(start).Seconds())
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -75,7 +75,6 @@ func TestGetReplicasExistentFn(t *testing.T) {
|
||||
MinReplicas: uint64(scaling.DefaultMinReplicas),
|
||||
ScalingFactor: uint64(scaling.DefaultScalingFactor),
|
||||
AvailableReplicas: 0,
|
||||
TargetLoad: 10,
|
||||
}
|
||||
|
||||
var injector middleware.AuthInjector
|
||||
|
@ -5,13 +5,6 @@
|
||||
// the OpenFaaS gateway REST API
|
||||
package requests
|
||||
|
||||
// AsyncReport is the report from a function executed on a queue worker.
|
||||
type AsyncReport struct {
|
||||
FunctionName string `json:"name"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
TimeTaken float64 `json:"timeTaken"`
|
||||
}
|
||||
|
||||
// DeleteFunctionRequest delete a deployed function
|
||||
type DeleteFunctionRequest struct {
|
||||
FunctionName string `json:"functionName"`
|
||||
|
@ -3,12 +3,18 @@
|
||||
|
||||
package scaling
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
type CachedFunctionQuery struct {
|
||||
cache FunctionCacher
|
||||
serviceQuery ServiceQuery
|
||||
emptyAnnotations map[string]string
|
||||
singleFlight *singleflight.Group
|
||||
}
|
||||
|
||||
func NewCachedFunctionQuery(cache FunctionCacher, serviceQuery ServiceQuery) FunctionQuery {
|
||||
@ -16,6 +22,7 @@ func NewCachedFunctionQuery(cache FunctionCacher, serviceQuery ServiceQuery) Fun
|
||||
cache: cache,
|
||||
serviceQuery: serviceQuery,
|
||||
emptyAnnotations: map[string]string{},
|
||||
singleFlight: &singleflight.Group{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,13 +42,21 @@ func (c *CachedFunctionQuery) Get(fn string, ns string) (ServiceQueryResponse, e
|
||||
|
||||
query, hit := c.cache.Get(fn, ns)
|
||||
if !hit {
|
||||
key := fmt.Sprintf("GetReplicas-%s.%s", fn, ns)
|
||||
queryResponse, err, _ := c.singleFlight.Do(key, func() (interface{}, error) {
|
||||
log.Printf("Cache miss - run GetReplicas")
|
||||
// If there is a cache miss, then fetch the value from the provider API
|
||||
return c.serviceQuery.GetReplicas(fn, ns)
|
||||
})
|
||||
|
||||
// If there is a cache miss, then fetch the value from the provider API
|
||||
queryResponse, err := c.serviceQuery.GetReplicas(fn, ns)
|
||||
if err != nil {
|
||||
return ServiceQueryResponse{}, err
|
||||
}
|
||||
c.cache.Set(fn, ns, queryResponse)
|
||||
|
||||
if queryResponse != nil {
|
||||
c.cache.Set(fn, ns, queryResponse.(ServiceQueryResponse))
|
||||
}
|
||||
|
||||
} else {
|
||||
return query, nil
|
||||
}
|
||||
|
@ -4,21 +4,26 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/openfaas/faas/gateway/types"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
// NewFunctionScaler create a new scaler with the specified
|
||||
// ScalingConfig
|
||||
func NewFunctionScaler(config ScalingConfig, functionCacher FunctionCacher) FunctionScaler {
|
||||
return FunctionScaler{
|
||||
Cache: functionCacher,
|
||||
Config: config,
|
||||
Cache: functionCacher,
|
||||
Config: config,
|
||||
SingleFlight: &singleflight.Group{},
|
||||
}
|
||||
}
|
||||
|
||||
// FunctionScaler scales from zero
|
||||
type FunctionScaler struct {
|
||||
Cache FunctionCacher
|
||||
Config ScalingConfig
|
||||
Cache FunctionCacher
|
||||
Config ScalingConfig
|
||||
SingleFlight *singleflight.Group
|
||||
}
|
||||
|
||||
// FunctionScaleResult holds the result of scaling from zero
|
||||
@ -34,6 +39,8 @@ type FunctionScaleResult struct {
|
||||
func (f *FunctionScaler) Scale(functionName, namespace string) FunctionScaleResult {
|
||||
start := time.Now()
|
||||
|
||||
// First check the cache, if there are available replicas, then the
|
||||
// request can be served.
|
||||
if cachedResponse, hit := f.Cache.Get(functionName, namespace); hit &&
|
||||
cachedResponse.AvailableReplicas > 0 {
|
||||
return FunctionScaleResult{
|
||||
@ -44,7 +51,12 @@ func (f *FunctionScaler) Scale(functionName, namespace string) FunctionScaleResu
|
||||
}
|
||||
}
|
||||
|
||||
queryResponse, err := f.Config.ServiceQuery.GetReplicas(functionName, namespace)
|
||||
// The wasn't a hit, or there were no available replicas found
|
||||
// so query the live endpoint
|
||||
getKey := fmt.Sprintf("GetReplicas-%s.%s", functionName, namespace)
|
||||
res, err, _ := f.SingleFlight.Do(getKey, func() (interface{}, error) {
|
||||
return f.Config.ServiceQuery.GetReplicas(functionName, namespace)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return FunctionScaleResult{
|
||||
@ -54,36 +66,78 @@ func (f *FunctionScaler) Scale(functionName, namespace string) FunctionScaleResu
|
||||
Duration: time.Since(start),
|
||||
}
|
||||
}
|
||||
if res == nil {
|
||||
return FunctionScaleResult{
|
||||
Error: fmt.Errorf("empty response from server"),
|
||||
Available: false,
|
||||
Found: false,
|
||||
Duration: time.Since(start),
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there are available replicas in the live data
|
||||
if res.(ServiceQueryResponse).AvailableReplicas > 0 {
|
||||
return FunctionScaleResult{
|
||||
Error: nil,
|
||||
Available: true,
|
||||
Found: true,
|
||||
Duration: time.Since(start),
|
||||
}
|
||||
}
|
||||
|
||||
// Store the result of GetReplicas in the cache
|
||||
queryResponse := res.(ServiceQueryResponse)
|
||||
f.Cache.Set(functionName, namespace, queryResponse)
|
||||
|
||||
if queryResponse.AvailableReplicas == 0 {
|
||||
// If the desired replica count is 0, then a scale up event
|
||||
// is required.
|
||||
if queryResponse.Replicas == 0 {
|
||||
minReplicas := uint64(1)
|
||||
if queryResponse.MinReplicas > 0 {
|
||||
minReplicas = queryResponse.MinReplicas
|
||||
}
|
||||
|
||||
scaleResult := backoff(func(attempt int) error {
|
||||
queryResponse, err := f.Config.ServiceQuery.GetReplicas(functionName, namespace)
|
||||
// In a retry-loop, first query desired replicas, then
|
||||
// set them if the value is still at 0.
|
||||
scaleResult := types.Retry(func(attempt int) error {
|
||||
|
||||
res, err, _ := f.SingleFlight.Do(getKey, func() (interface{}, error) {
|
||||
return f.Config.ServiceQuery.GetReplicas(functionName, namespace)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Cache the response
|
||||
queryResponse = res.(ServiceQueryResponse)
|
||||
f.Cache.Set(functionName, namespace, queryResponse)
|
||||
|
||||
// The scale up is complete because the desired replica count
|
||||
// has been set to 1 or more.
|
||||
if queryResponse.Replicas > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[Scale %d] function=%s 0 => %d requested", attempt, functionName, minReplicas)
|
||||
setScaleErr := f.Config.ServiceQuery.SetReplicas(functionName, namespace, minReplicas)
|
||||
if setScaleErr != nil {
|
||||
return fmt.Errorf("unable to scale function [%s], err: %s", functionName, setScaleErr)
|
||||
// Request a scale up to the minimum amount of replicas
|
||||
setKey := fmt.Sprintf("SetReplicas-%s.%s", functionName, namespace)
|
||||
|
||||
if _, err, _ := f.SingleFlight.Do(setKey, func() (interface{}, error) {
|
||||
|
||||
log.Printf("[Scale %d/%d] function=%s 0 => %d requested",
|
||||
attempt, int(f.Config.SetScaleRetries), functionName, minReplicas)
|
||||
|
||||
if err := f.Config.ServiceQuery.SetReplicas(functionName, namespace, minReplicas); err != nil {
|
||||
return nil, fmt.Errorf("unable to scale function [%s], err: %s", functionName, err)
|
||||
}
|
||||
return nil, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}, int(f.Config.SetScaleRetries), f.Config.FunctionPollInterval)
|
||||
}, "Scale", int(f.Config.SetScaleRetries), f.Config.FunctionPollInterval)
|
||||
|
||||
if scaleResult != nil {
|
||||
return FunctionScaleResult{
|
||||
@ -94,37 +148,44 @@ func (f *FunctionScaler) Scale(functionName, namespace string) FunctionScaleResu
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < int(f.Config.MaxPollCount); i++ {
|
||||
queryResponse, err := f.Config.ServiceQuery.GetReplicas(functionName, namespace)
|
||||
if err == nil {
|
||||
f.Cache.Set(functionName, namespace, queryResponse)
|
||||
}
|
||||
totalTime := time.Since(start)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return FunctionScaleResult{
|
||||
Error: err,
|
||||
Available: false,
|
||||
Found: true,
|
||||
Duration: totalTime,
|
||||
}
|
||||
}
|
||||
// Holding pattern for at least one function replica to be available
|
||||
for i := 0; i < int(f.Config.MaxPollCount); i++ {
|
||||
|
||||
if queryResponse.AvailableReplicas > 0 {
|
||||
res, err, _ := f.SingleFlight.Do(getKey, func() (interface{}, error) {
|
||||
return f.Config.ServiceQuery.GetReplicas(functionName, namespace)
|
||||
})
|
||||
queryResponse := res.(ServiceQueryResponse)
|
||||
|
||||
log.Printf("[Scale] function=%s 0 => %d successful - %fs",
|
||||
functionName, queryResponse.AvailableReplicas, totalTime.Seconds())
|
||||
|
||||
return FunctionScaleResult{
|
||||
Error: nil,
|
||||
Available: true,
|
||||
Found: true,
|
||||
Duration: totalTime,
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(f.Config.FunctionPollInterval)
|
||||
if err == nil {
|
||||
f.Cache.Set(functionName, namespace, queryResponse)
|
||||
}
|
||||
|
||||
totalTime := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
return FunctionScaleResult{
|
||||
Error: err,
|
||||
Available: false,
|
||||
Found: true,
|
||||
Duration: totalTime,
|
||||
}
|
||||
}
|
||||
|
||||
if queryResponse.AvailableReplicas > 0 {
|
||||
|
||||
log.Printf("[Ready] function=%s waited for - %.4fs", functionName, totalTime.Seconds())
|
||||
|
||||
return FunctionScaleResult{
|
||||
Error: nil,
|
||||
Available: true,
|
||||
Found: true,
|
||||
Duration: totalTime,
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(f.Config.FunctionPollInterval)
|
||||
}
|
||||
|
||||
return FunctionScaleResult{
|
||||
@ -134,23 +195,3 @@ func (f *FunctionScaler) Scale(functionName, namespace string) FunctionScaleResu
|
||||
Duration: time.Since(start),
|
||||
}
|
||||
}
|
||||
|
||||
type routine func(attempt int) error
|
||||
|
||||
func backoff(r routine, attempts int, interval time.Duration) error {
|
||||
var err error
|
||||
|
||||
for i := 0; i < attempts; i++ {
|
||||
res := r(i)
|
||||
if res != nil {
|
||||
err = res
|
||||
|
||||
log.Printf("Attempt: %d, had error: %s\n", i, res)
|
||||
} else {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
time.Sleep(interval)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -1,17 +1,23 @@
|
||||
package scaling
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/openfaas/faas-provider/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultMinReplicas is the minimal amount of replicas for a service.
|
||||
DefaultMinReplicas = 1
|
||||
|
||||
// DefaultMaxReplicas is the amount of replicas a service will auto-scale up to.
|
||||
DefaultMaxReplicas = 20
|
||||
DefaultMaxReplicas = 5
|
||||
|
||||
// DefaultScalingFactor is the defining proportion for the scaling increments.
|
||||
DefaultScalingFactor = 20
|
||||
|
||||
// DefaultTargetLoad
|
||||
DefaultTargetLoad = 10
|
||||
DefaultScalingFactor = 10
|
||||
|
||||
DefaultTypeScale = "rps"
|
||||
|
||||
@ -23,10 +29,44 @@ const (
|
||||
|
||||
// ScalingFactorLabel label indicates the scaling factor for a function
|
||||
ScalingFactorLabel = "com.openfaas.scale.factor"
|
||||
|
||||
// TargetLoadLabel see also DefaultTargetScale
|
||||
TargetLoadLabel = "com.openfaas.scale.target"
|
||||
|
||||
// ScaleTypeLabel see also DefaultScaleType
|
||||
ScaleTypeLabel = "com.openfaas.scale.type"
|
||||
)
|
||||
|
||||
func MakeHorizontalScalingHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Only POST is allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if r.Body == nil {
|
||||
http.Error(w, "Error reading request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Error reading request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
scaleRequest := types.ScaleServiceRequest{}
|
||||
if err := json.Unmarshal(body, &scaleRequest); err != nil {
|
||||
http.Error(w, "Error unmarshalling request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if scaleRequest.Replicas < 1 {
|
||||
scaleRequest.Replicas = 1
|
||||
}
|
||||
|
||||
if scaleRequest.Replicas > DefaultMaxReplicas {
|
||||
scaleRequest.Replicas = DefaultMaxReplicas
|
||||
}
|
||||
|
||||
upstreamReq, _ := json.Marshal(scaleRequest)
|
||||
// Restore the io.ReadCloser to its original state
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(upstreamReq))
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
@ -17,5 +17,4 @@ type ServiceQueryResponse struct {
|
||||
ScalingFactor uint64
|
||||
AvailableReplicas uint64
|
||||
Annotations *map[string]string
|
||||
TargetLoad uint64
|
||||
}
|
||||
|
73
gateway/scaling/single.go
Normal file
73
gateway/scaling/single.go
Normal file
@ -0,0 +1,73 @@
|
||||
package scaling
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Call struct {
|
||||
wg *sync.WaitGroup
|
||||
res *SingleFlightResult
|
||||
}
|
||||
|
||||
type SingleFlight struct {
|
||||
lock *sync.RWMutex
|
||||
calls map[string]*Call
|
||||
}
|
||||
|
||||
type SingleFlightResult struct {
|
||||
Result interface{}
|
||||
Error error
|
||||
}
|
||||
|
||||
func NewSingleFlight() *SingleFlight {
|
||||
return &SingleFlight{
|
||||
lock: &sync.RWMutex{},
|
||||
calls: map[string]*Call{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SingleFlight) Do(key string, f func() (interface{}, error)) (interface{}, error) {
|
||||
|
||||
s.lock.Lock()
|
||||
|
||||
if call, ok := s.calls[key]; ok {
|
||||
s.lock.Unlock()
|
||||
call.wg.Wait()
|
||||
|
||||
return call.res.Result, call.res.Error
|
||||
}
|
||||
|
||||
var call *Call
|
||||
if s.calls[key] == nil {
|
||||
call = &Call{
|
||||
wg: &sync.WaitGroup{},
|
||||
}
|
||||
s.calls[key] = call
|
||||
}
|
||||
|
||||
call.wg.Add(1)
|
||||
|
||||
s.lock.Unlock()
|
||||
|
||||
go func() {
|
||||
log.Printf("Miss, so running: %s", key)
|
||||
res, err := f()
|
||||
|
||||
s.lock.Lock()
|
||||
call.res = &SingleFlightResult{
|
||||
Result: res,
|
||||
Error: err,
|
||||
}
|
||||
|
||||
call.wg.Done()
|
||||
|
||||
delete(s.calls, key)
|
||||
|
||||
s.lock.Unlock()
|
||||
}()
|
||||
|
||||
call.wg.Wait()
|
||||
|
||||
return call.res.Result, call.res.Error
|
||||
}
|
@ -28,9 +28,6 @@ type HandlerSet struct {
|
||||
// QueuedProxy queue work and return synchronous response
|
||||
QueuedProxy http.HandlerFunc
|
||||
|
||||
// AsyncReport report a deferred execution result
|
||||
AsyncReport http.HandlerFunc
|
||||
|
||||
// ScaleFunction enables a function to be scaled
|
||||
ScaleFunction http.HandlerFunc
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -59,7 +58,7 @@ func (ReadConfig) Read(hasEnv HasEnv) (*GatewayConfig, error) {
|
||||
PrometheusPort: 9090,
|
||||
}
|
||||
|
||||
defaultDuration := time.Second * 8
|
||||
defaultDuration := time.Second * 60
|
||||
|
||||
cfg.ReadTimeout = parseIntOrDurationValue(hasEnv.Getenv("read_timeout"), defaultDuration)
|
||||
cfg.WriteTimeout = parseIntOrDurationValue(hasEnv.Getenv("write_timeout"), defaultDuration)
|
||||
@ -129,9 +128,6 @@ func (ReadConfig) Read(hasEnv HasEnv) (*GatewayConfig, error) {
|
||||
cfg.PrometheusHost = prometheusHost
|
||||
}
|
||||
|
||||
cfg.DirectFunctions = parseBoolValue(hasEnv.Getenv("direct_functions"))
|
||||
cfg.DirectFunctionsSuffix = hasEnv.Getenv("direct_functions_suffix")
|
||||
|
||||
cfg.UseBasicAuth = parseBoolValue(hasEnv.Getenv("basic_auth"))
|
||||
|
||||
secretPath := hasEnv.Getenv("secret_mount_path")
|
||||
@ -169,12 +165,6 @@ func (ReadConfig) Read(hasEnv HasEnv) (*GatewayConfig, error) {
|
||||
|
||||
cfg.Namespace = hasEnv.Getenv("function_namespace")
|
||||
|
||||
if len(cfg.DirectFunctionsSuffix) > 0 && len(cfg.Namespace) > 0 {
|
||||
if strings.HasPrefix(cfg.DirectFunctionsSuffix, cfg.Namespace) == false {
|
||||
return nil, fmt.Errorf("function_namespace must be a sub-string of direct_functions_suffix")
|
||||
}
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
@ -214,12 +204,6 @@ type GatewayConfig struct {
|
||||
// Port to connect to Prometheus.
|
||||
PrometheusPort int
|
||||
|
||||
// If set to true we will access upstream functions directly rather than through the upstream provider
|
||||
DirectFunctions bool
|
||||
|
||||
// If set this will be used to resolve functions directly
|
||||
DirectFunctionsSuffix string
|
||||
|
||||
// If set, reads secrets from file-system for enabling basic auth.
|
||||
UseBasicAuth bool
|
||||
|
||||
|
@ -38,16 +38,6 @@ func TestRead_UseExternalProvider_Defaults(t *testing.T) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if config.DirectFunctions != false {
|
||||
t.Log("Default for DirectFunctions should be false")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if len(config.DirectFunctionsSuffix) > 0 {
|
||||
t.Log("Default for DirectFunctionsSuffix should be empty")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if len(config.Namespace) > 0 {
|
||||
t.Log("Default for Namespace should be empty")
|
||||
t.Fail()
|
||||
@ -89,54 +79,6 @@ func TestRead_NamespaceOverrideAgressWithFunctionSuffix_Valid(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRead_NamespaceOverrideAgressWithFunctionSuffix_Invalid(t *testing.T) {
|
||||
|
||||
defaults := NewEnvBucket()
|
||||
readConfig := ReadConfig{}
|
||||
|
||||
defaults.Setenv("direct_functions", "true")
|
||||
wantSuffix := "openfaas-fn.cluster.local.svc."
|
||||
|
||||
defaults.Setenv("direct_functions_suffix", wantSuffix)
|
||||
defaults.Setenv("function_namespace", "fn")
|
||||
|
||||
_, err := readConfig.Read(defaults)
|
||||
|
||||
if err == nil {
|
||||
t.Logf("Expected an error because function_namespace should be a sub-string of direct_functions_suffix")
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
want := "function_namespace must be a sub-string of direct_functions_suffix"
|
||||
|
||||
if want != err.Error() {
|
||||
t.Logf("Error want: %s, got: %s", want, err.Error())
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRead_DirectFunctionsOverride(t *testing.T) {
|
||||
defaults := NewEnvBucket()
|
||||
readConfig := ReadConfig{}
|
||||
defaults.Setenv("direct_functions", "true")
|
||||
wantSuffix := "openfaas-fn.cluster.local.svc."
|
||||
defaults.Setenv("direct_functions_suffix", wantSuffix)
|
||||
|
||||
config, _ := readConfig.Read(defaults)
|
||||
|
||||
if config.DirectFunctions != true {
|
||||
t.Logf("DirectFunctions should be true, got: %v", config.DirectFunctions)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if config.DirectFunctionsSuffix != wantSuffix {
|
||||
t.Logf("DirectFunctionsSuffix want: %s, got: %s", wantSuffix, config.DirectFunctionsSuffix)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRead_ScaleZeroDefaultAndOverride(t *testing.T) {
|
||||
defaults := NewEnvBucket()
|
||||
readConfig := ReadConfig{}
|
||||
@ -166,13 +108,16 @@ func TestRead_EmptyTimeoutConfig(t *testing.T) {
|
||||
|
||||
config, _ := readConfig.Read(defaults)
|
||||
|
||||
if (config.ReadTimeout) != time.Duration(8)*time.Second {
|
||||
t.Log("ReadTimeout incorrect")
|
||||
t.Fail()
|
||||
want := time.Second * 60
|
||||
got := config.ReadTimeout
|
||||
if got != want {
|
||||
t.Fatalf("config.ReadTimeout want: %s, but got: %s", want, got)
|
||||
}
|
||||
if (config.WriteTimeout) != time.Duration(8)*time.Second {
|
||||
t.Log("WriteTimeout incorrect")
|
||||
t.Fail()
|
||||
|
||||
want = time.Second * 60
|
||||
got = config.WriteTimeout
|
||||
if got != want {
|
||||
t.Fatalf("config.WriteTimeout want: %s, but got: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
|
25
gateway/types/retry.go
Normal file
25
gateway/types/retry.go
Normal file
@ -0,0 +1,25 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type routine func(attempt int) error
|
||||
|
||||
func Retry(r routine, label string, attempts int, interval time.Duration) error {
|
||||
var err error
|
||||
|
||||
for i := 0; i < attempts; i++ {
|
||||
res := r(i)
|
||||
if res != nil {
|
||||
err = res
|
||||
log.Printf("[%s]: %d/%d, error: %s\n", label, i, attempts, res)
|
||||
} else {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
time.Sleep(interval)
|
||||
}
|
||||
return err
|
||||
}
|
43
gateway/types/retry_test.go
Normal file
43
gateway/types/retry_test.go
Normal file
@ -0,0 +1,43 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_retry_early_success(t *testing.T) {
|
||||
called := 0
|
||||
maxRetries := 10
|
||||
routine := func(i int) error {
|
||||
|
||||
called++
|
||||
if called == 5 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("not called 5 times yet")
|
||||
}
|
||||
|
||||
Retry(routine, "test", maxRetries, time.Millisecond*5)
|
||||
|
||||
want := 5
|
||||
if called != want {
|
||||
t.Errorf("want: %d, got: %d", want, called)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_retry_until_max_attempts(t *testing.T) {
|
||||
called := 0
|
||||
maxRetries := 10
|
||||
routine := func(i int) error {
|
||||
called++
|
||||
return fmt.Errorf("unable to pass condition for routine")
|
||||
}
|
||||
|
||||
Retry(routine, "test", maxRetries, time.Millisecond*5)
|
||||
|
||||
want := maxRetries
|
||||
if called != want {
|
||||
t.Errorf("want: %d, got: %d", want, called)
|
||||
}
|
||||
}
|
8
gateway/vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
8
gateway/vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
@ -1,8 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- "1.x"
|
||||
- master
|
||||
env:
|
||||
- TAGS=""
|
||||
- TAGS="-tags purego"
|
||||
script: go test $TAGS -v ./...
|
6
gateway/vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
6
gateway/vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
@ -1,7 +1,7 @@
|
||||
# xxhash
|
||||
|
||||
[](https://godoc.org/github.com/cespare/xxhash)
|
||||
[](https://travis-ci.org/cespare/xxhash)
|
||||
[](https://pkg.go.dev/github.com/cespare/xxhash/v2)
|
||||
[](https://github.com/cespare/xxhash/actions/workflows/test.yml)
|
||||
|
||||
xxhash is a Go implementation of the 64-bit
|
||||
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
||||
@ -64,4 +64,6 @@ $ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||
|
||||
- [InfluxDB](https://github.com/influxdata/influxdb)
|
||||
- [Prometheus](https://github.com/prometheus/prometheus)
|
||||
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||
- [FreeCache](https://github.com/coocood/freecache)
|
||||
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
||||
|
3
gateway/vendor/github.com/cespare/xxhash/v2/go.mod
generated
vendored
3
gateway/vendor/github.com/cespare/xxhash/v2/go.mod
generated
vendored
@ -1,3 +0,0 @@
|
||||
module github.com/cespare/xxhash/v2
|
||||
|
||||
go 1.11
|
0
gateway/vendor/github.com/cespare/xxhash/v2/go.sum
generated
vendored
0
gateway/vendor/github.com/cespare/xxhash/v2/go.sum
generated
vendored
1
gateway/vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
1
gateway/vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
@ -193,7 +193,6 @@ func (d *Digest) UnmarshalBinary(b []byte) error {
|
||||
b, d.v4 = consumeUint64(b)
|
||||
b, d.total = consumeUint64(b)
|
||||
copy(d.mem[:], b)
|
||||
b = b[len(d.mem):]
|
||||
d.n = int(d.total % uint64(len(d.mem)))
|
||||
return nil
|
||||
}
|
||||
|
62
gateway/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
generated
vendored
62
gateway/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
generated
vendored
@ -6,7 +6,7 @@
|
||||
|
||||
// Register allocation:
|
||||
// AX h
|
||||
// CX pointer to advance through b
|
||||
// SI pointer to advance through b
|
||||
// DX n
|
||||
// BX loop end
|
||||
// R8 v1, k1
|
||||
@ -16,39 +16,39 @@
|
||||
// R12 tmp
|
||||
// R13 prime1v
|
||||
// R14 prime2v
|
||||
// R15 prime4v
|
||||
// DI prime4v
|
||||
|
||||
// round reads from and advances the buffer pointer in CX.
|
||||
// round reads from and advances the buffer pointer in SI.
|
||||
// It assumes that R13 has prime1v and R14 has prime2v.
|
||||
#define round(r) \
|
||||
MOVQ (CX), R12 \
|
||||
ADDQ $8, CX \
|
||||
MOVQ (SI), R12 \
|
||||
ADDQ $8, SI \
|
||||
IMULQ R14, R12 \
|
||||
ADDQ R12, r \
|
||||
ROLQ $31, r \
|
||||
IMULQ R13, r
|
||||
|
||||
// mergeRound applies a merge round on the two registers acc and val.
|
||||
// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v.
|
||||
// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v.
|
||||
#define mergeRound(acc, val) \
|
||||
IMULQ R14, val \
|
||||
ROLQ $31, val \
|
||||
IMULQ R13, val \
|
||||
XORQ val, acc \
|
||||
IMULQ R13, acc \
|
||||
ADDQ R15, acc
|
||||
ADDQ DI, acc
|
||||
|
||||
// func Sum64(b []byte) uint64
|
||||
TEXT ·Sum64(SB), NOSPLIT, $0-32
|
||||
// Load fixed primes.
|
||||
MOVQ ·prime1v(SB), R13
|
||||
MOVQ ·prime2v(SB), R14
|
||||
MOVQ ·prime4v(SB), R15
|
||||
MOVQ ·prime4v(SB), DI
|
||||
|
||||
// Load slice.
|
||||
MOVQ b_base+0(FP), CX
|
||||
MOVQ b_base+0(FP), SI
|
||||
MOVQ b_len+8(FP), DX
|
||||
LEAQ (CX)(DX*1), BX
|
||||
LEAQ (SI)(DX*1), BX
|
||||
|
||||
// The first loop limit will be len(b)-32.
|
||||
SUBQ $32, BX
|
||||
@ -65,14 +65,14 @@ TEXT ·Sum64(SB), NOSPLIT, $0-32
|
||||
XORQ R11, R11
|
||||
SUBQ R13, R11
|
||||
|
||||
// Loop until CX > BX.
|
||||
// Loop until SI > BX.
|
||||
blockLoop:
|
||||
round(R8)
|
||||
round(R9)
|
||||
round(R10)
|
||||
round(R11)
|
||||
|
||||
CMPQ CX, BX
|
||||
CMPQ SI, BX
|
||||
JLE blockLoop
|
||||
|
||||
MOVQ R8, AX
|
||||
@ -100,16 +100,16 @@ noBlocks:
|
||||
afterBlocks:
|
||||
ADDQ DX, AX
|
||||
|
||||
// Right now BX has len(b)-32, and we want to loop until CX > len(b)-8.
|
||||
// Right now BX has len(b)-32, and we want to loop until SI > len(b)-8.
|
||||
ADDQ $24, BX
|
||||
|
||||
CMPQ CX, BX
|
||||
CMPQ SI, BX
|
||||
JG fourByte
|
||||
|
||||
wordLoop:
|
||||
// Calculate k1.
|
||||
MOVQ (CX), R8
|
||||
ADDQ $8, CX
|
||||
MOVQ (SI), R8
|
||||
ADDQ $8, SI
|
||||
IMULQ R14, R8
|
||||
ROLQ $31, R8
|
||||
IMULQ R13, R8
|
||||
@ -117,18 +117,18 @@ wordLoop:
|
||||
XORQ R8, AX
|
||||
ROLQ $27, AX
|
||||
IMULQ R13, AX
|
||||
ADDQ R15, AX
|
||||
ADDQ DI, AX
|
||||
|
||||
CMPQ CX, BX
|
||||
CMPQ SI, BX
|
||||
JLE wordLoop
|
||||
|
||||
fourByte:
|
||||
ADDQ $4, BX
|
||||
CMPQ CX, BX
|
||||
CMPQ SI, BX
|
||||
JG singles
|
||||
|
||||
MOVL (CX), R8
|
||||
ADDQ $4, CX
|
||||
MOVL (SI), R8
|
||||
ADDQ $4, SI
|
||||
IMULQ R13, R8
|
||||
XORQ R8, AX
|
||||
|
||||
@ -138,19 +138,19 @@ fourByte:
|
||||
|
||||
singles:
|
||||
ADDQ $4, BX
|
||||
CMPQ CX, BX
|
||||
CMPQ SI, BX
|
||||
JGE finalize
|
||||
|
||||
singlesLoop:
|
||||
MOVBQZX (CX), R12
|
||||
ADDQ $1, CX
|
||||
MOVBQZX (SI), R12
|
||||
ADDQ $1, SI
|
||||
IMULQ ·prime5v(SB), R12
|
||||
XORQ R12, AX
|
||||
|
||||
ROLQ $11, AX
|
||||
IMULQ R13, AX
|
||||
|
||||
CMPQ CX, BX
|
||||
CMPQ SI, BX
|
||||
JL singlesLoop
|
||||
|
||||
finalize:
|
||||
@ -179,9 +179,9 @@ TEXT ·writeBlocks(SB), NOSPLIT, $0-40
|
||||
MOVQ ·prime2v(SB), R14
|
||||
|
||||
// Load slice.
|
||||
MOVQ b_base+8(FP), CX
|
||||
MOVQ b_base+8(FP), SI
|
||||
MOVQ b_len+16(FP), DX
|
||||
LEAQ (CX)(DX*1), BX
|
||||
LEAQ (SI)(DX*1), BX
|
||||
SUBQ $32, BX
|
||||
|
||||
// Load vN from d.
|
||||
@ -199,7 +199,7 @@ blockLoop:
|
||||
round(R10)
|
||||
round(R11)
|
||||
|
||||
CMPQ CX, BX
|
||||
CMPQ SI, BX
|
||||
JLE blockLoop
|
||||
|
||||
// Copy vN back to d.
|
||||
@ -208,8 +208,8 @@ blockLoop:
|
||||
MOVQ R10, 16(AX)
|
||||
MOVQ R11, 24(AX)
|
||||
|
||||
// The number of bytes written is CX minus the old base pointer.
|
||||
SUBQ b_base+8(FP), CX
|
||||
MOVQ CX, ret+32(FP)
|
||||
// The number of bytes written is SI minus the old base pointer.
|
||||
SUBQ b_base+8(FP), SI
|
||||
MOVQ SI, ret+32(FP)
|
||||
|
||||
RET
|
||||
|
55
gateway/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
55
gateway/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
@ -6,41 +6,52 @@
|
||||
package xxhash
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Notes:
|
||||
//
|
||||
// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ
|
||||
// for some discussion about these unsafe conversions.
|
||||
//
|
||||
// In the future it's possible that compiler optimizations will make these
|
||||
// unsafe operations unnecessary: https://golang.org/issue/2205.
|
||||
// XxxString functions unnecessary by realizing that calls such as
|
||||
// Sum64([]byte(s)) don't need to copy s. See https://golang.org/issue/2205.
|
||||
// If that happens, even if we keep these functions they can be replaced with
|
||||
// the trivial safe code.
|
||||
|
||||
// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:
|
||||
//
|
||||
// Both of these wrapper functions still incur function call overhead since they
|
||||
// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write
|
||||
// for strings to squeeze out a bit more speed. Mid-stack inlining should
|
||||
// eventually fix this.
|
||||
// var b []byte
|
||||
// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||
// bh.Len = len(s)
|
||||
// bh.Cap = len(s)
|
||||
//
|
||||
// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough
|
||||
// weight to this sequence of expressions that any function that uses it will
|
||||
// not be inlined. Instead, the functions below use a different unsafe
|
||||
// conversion designed to minimize the inliner weight and allow both to be
|
||||
// inlined. There is also a test (TestInlining) which verifies that these are
|
||||
// inlined.
|
||||
//
|
||||
// See https://github.com/golang/go/issues/42739 for discussion.
|
||||
|
||||
// Sum64String computes the 64-bit xxHash digest of s.
|
||||
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
||||
func Sum64String(s string) uint64 {
|
||||
var b []byte
|
||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||
bh.Len = len(s)
|
||||
bh.Cap = len(s)
|
||||
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
|
||||
return Sum64(b)
|
||||
}
|
||||
|
||||
// WriteString adds more data to d. It always returns len(s), nil.
|
||||
// It may be faster than Write([]byte(s)) by avoiding a copy.
|
||||
func (d *Digest) WriteString(s string) (n int, err error) {
|
||||
var b []byte
|
||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||
bh.Len = len(s)
|
||||
bh.Cap = len(s)
|
||||
return d.Write(b)
|
||||
d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
|
||||
// d.Write always returns len(s), nil.
|
||||
// Ignoring the return output and returning these fixed values buys a
|
||||
// savings of 6 in the inliner's cost model.
|
||||
return len(s), nil
|
||||
}
|
||||
|
||||
// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout
|
||||
// of the first two words is the same as the layout of a string.
|
||||
type sliceHeader struct {
|
||||
s string
|
||||
cap int
|
||||
}
|
||||
|
179
gateway/vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
179
gateway/vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
@ -1,179 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ptypes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
|
||||
anypb "github.com/golang/protobuf/ptypes/any"
|
||||
)
|
||||
|
||||
const urlPrefix = "type.googleapis.com/"
|
||||
|
||||
// AnyMessageName returns the message name contained in an anypb.Any message.
|
||||
// Most type assertions should use the Is function instead.
|
||||
//
|
||||
// Deprecated: Call the any.MessageName method instead.
|
||||
func AnyMessageName(any *anypb.Any) (string, error) {
|
||||
name, err := anyMessageName(any)
|
||||
return string(name), err
|
||||
}
|
||||
func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) {
|
||||
if any == nil {
|
||||
return "", fmt.Errorf("message is nil")
|
||||
}
|
||||
name := protoreflect.FullName(any.TypeUrl)
|
||||
if i := strings.LastIndex(any.TypeUrl, "/"); i >= 0 {
|
||||
name = name[i+len("/"):]
|
||||
}
|
||||
if !name.IsValid() {
|
||||
return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// MarshalAny marshals the given message m into an anypb.Any message.
|
||||
//
|
||||
// Deprecated: Call the anypb.New function instead.
|
||||
func MarshalAny(m proto.Message) (*anypb.Any, error) {
|
||||
switch dm := m.(type) {
|
||||
case DynamicAny:
|
||||
m = dm.Message
|
||||
case *DynamicAny:
|
||||
if dm == nil {
|
||||
return nil, proto.ErrNil
|
||||
}
|
||||
m = dm.Message
|
||||
}
|
||||
b, err := proto.Marshal(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &anypb.Any{TypeUrl: urlPrefix + proto.MessageName(m), Value: b}, nil
|
||||
}
|
||||
|
||||
// Empty returns a new message of the type specified in an anypb.Any message.
|
||||
// It returns protoregistry.NotFound if the corresponding message type could not
|
||||
// be resolved in the global registry.
|
||||
//
|
||||
// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead
|
||||
// to resolve the message name and create a new instance of it.
|
||||
func Empty(any *anypb.Any) (proto.Message, error) {
|
||||
name, err := anyMessageName(any)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mt, err := protoregistry.GlobalTypes.FindMessageByName(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.MessageV1(mt.New().Interface()), nil
|
||||
}
|
||||
|
||||
// UnmarshalAny unmarshals the encoded value contained in the anypb.Any message
|
||||
// into the provided message m. It returns an error if the target message
|
||||
// does not match the type in the Any message or if an unmarshal error occurs.
|
||||
//
|
||||
// The target message m may be a *DynamicAny message. If the underlying message
|
||||
// type could not be resolved, then this returns protoregistry.NotFound.
|
||||
//
|
||||
// Deprecated: Call the any.UnmarshalTo method instead.
|
||||
func UnmarshalAny(any *anypb.Any, m proto.Message) error {
|
||||
if dm, ok := m.(*DynamicAny); ok {
|
||||
if dm.Message == nil {
|
||||
var err error
|
||||
dm.Message, err = Empty(any)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
m = dm.Message
|
||||
}
|
||||
|
||||
anyName, err := AnyMessageName(any)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msgName := proto.MessageName(m)
|
||||
if anyName != msgName {
|
||||
return fmt.Errorf("mismatched message type: got %q want %q", anyName, msgName)
|
||||
}
|
||||
return proto.Unmarshal(any.Value, m)
|
||||
}
|
||||
|
||||
// Is reports whether the Any message contains a message of the specified type.
|
||||
//
|
||||
// Deprecated: Call the any.MessageIs method instead.
|
||||
func Is(any *anypb.Any, m proto.Message) bool {
|
||||
if any == nil || m == nil {
|
||||
return false
|
||||
}
|
||||
name := proto.MessageName(m)
|
||||
if !strings.HasSuffix(any.TypeUrl, name) {
|
||||
return false
|
||||
}
|
||||
return len(any.TypeUrl) == len(name) || any.TypeUrl[len(any.TypeUrl)-len(name)-1] == '/'
|
||||
}
|
||||
|
||||
// DynamicAny is a value that can be passed to UnmarshalAny to automatically
|
||||
// allocate a proto.Message for the type specified in an anypb.Any message.
|
||||
// The allocated message is stored in the embedded proto.Message.
|
||||
//
|
||||
// Example:
|
||||
// var x ptypes.DynamicAny
|
||||
// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
|
||||
// fmt.Printf("unmarshaled message: %v", x.Message)
|
||||
//
|
||||
// Deprecated: Use the any.UnmarshalNew method instead to unmarshal
|
||||
// the any message contents into a new instance of the underlying message.
|
||||
type DynamicAny struct{ proto.Message }
|
||||
|
||||
func (m DynamicAny) String() string {
|
||||
if m.Message == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return m.Message.String()
|
||||
}
|
||||
func (m DynamicAny) Reset() {
|
||||
if m.Message == nil {
|
||||
return
|
||||
}
|
||||
m.Message.Reset()
|
||||
}
|
||||
func (m DynamicAny) ProtoMessage() {
|
||||
return
|
||||
}
|
||||
func (m DynamicAny) ProtoReflect() protoreflect.Message {
|
||||
if m.Message == nil {
|
||||
return nil
|
||||
}
|
||||
return dynamicAny{proto.MessageReflect(m.Message)}
|
||||
}
|
||||
|
||||
type dynamicAny struct{ protoreflect.Message }
|
||||
|
||||
func (m dynamicAny) Type() protoreflect.MessageType {
|
||||
return dynamicAnyType{m.Message.Type()}
|
||||
}
|
||||
func (m dynamicAny) New() protoreflect.Message {
|
||||
return dynamicAnyType{m.Message.Type()}.New()
|
||||
}
|
||||
func (m dynamicAny) Interface() protoreflect.ProtoMessage {
|
||||
return DynamicAny{proto.MessageV1(m.Message.Interface())}
|
||||
}
|
||||
|
||||
type dynamicAnyType struct{ protoreflect.MessageType }
|
||||
|
||||
func (t dynamicAnyType) New() protoreflect.Message {
|
||||
return dynamicAny{t.MessageType.New()}
|
||||
}
|
||||
func (t dynamicAnyType) Zero() protoreflect.Message {
|
||||
return dynamicAny{t.MessageType.Zero()}
|
||||
}
|
62
gateway/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
62
gateway/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
@ -1,62 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: github.com/golang/protobuf/ptypes/any/any.proto
|
||||
|
||||
package any
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// Symbols defined in public import of google/protobuf/any.proto.
|
||||
|
||||
type Any = anypb.Any
|
||||
|
||||
var File_github_com_golang_protobuf_ptypes_any_any_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = []byte{
|
||||
0x0a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
|
||||
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
|
||||
0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2b, 0x5a, 0x29,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
|
||||
0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65,
|
||||
0x73, 0x2f, 0x61, 0x6e, 0x79, 0x3b, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = []interface{}{}
|
||||
var file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_github_com_golang_protobuf_ptypes_any_any_proto_init() }
|
||||
func file_github_com_golang_protobuf_ptypes_any_any_proto_init() {
|
||||
if File_github_com_golang_protobuf_ptypes_any_any_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 0,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes,
|
||||
DependencyIndexes: file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs,
|
||||
}.Build()
|
||||
File_github_com_golang_protobuf_ptypes_any_any_proto = out.File
|
||||
file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = nil
|
||||
file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = nil
|
||||
file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = nil
|
||||
}
|
10
gateway/vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
10
gateway/vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
@ -1,10 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ptypes provides functionality for interacting with well-known types.
|
||||
//
|
||||
// Deprecated: Well-known types have specialized functionality directly
|
||||
// injected into the generated packages for each message type.
|
||||
// See the deprecation notice for each function for the suggested alternative.
|
||||
package ptypes
|
76
gateway/vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
76
gateway/vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
@ -1,76 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ptypes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
durationpb "github.com/golang/protobuf/ptypes/duration"
|
||||
)
|
||||
|
||||
// Range of google.protobuf.Duration as specified in duration.proto.
|
||||
// This is about 10,000 years in seconds.
|
||||
const (
|
||||
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
|
||||
minSeconds = -maxSeconds
|
||||
)
|
||||
|
||||
// Duration converts a durationpb.Duration to a time.Duration.
|
||||
// Duration returns an error if dur is invalid or overflows a time.Duration.
|
||||
//
|
||||
// Deprecated: Call the dur.AsDuration and dur.CheckValid methods instead.
|
||||
func Duration(dur *durationpb.Duration) (time.Duration, error) {
|
||||
if err := validateDuration(dur); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d := time.Duration(dur.Seconds) * time.Second
|
||||
if int64(d/time.Second) != dur.Seconds {
|
||||
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
|
||||
}
|
||||
if dur.Nanos != 0 {
|
||||
d += time.Duration(dur.Nanos) * time.Nanosecond
|
||||
if (d < 0) != (dur.Nanos < 0) {
|
||||
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
|
||||
}
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// DurationProto converts a time.Duration to a durationpb.Duration.
|
||||
//
|
||||
// Deprecated: Call the durationpb.New function instead.
|
||||
func DurationProto(d time.Duration) *durationpb.Duration {
|
||||
nanos := d.Nanoseconds()
|
||||
secs := nanos / 1e9
|
||||
nanos -= secs * 1e9
|
||||
return &durationpb.Duration{
|
||||
Seconds: int64(secs),
|
||||
Nanos: int32(nanos),
|
||||
}
|
||||
}
|
||||
|
||||
// validateDuration determines whether the durationpb.Duration is valid
|
||||
// according to the definition in google/protobuf/duration.proto.
|
||||
// A valid durpb.Duration may still be too large to fit into a time.Duration
|
||||
// Note that the range of durationpb.Duration is about 10,000 years,
|
||||
// while the range of time.Duration is about 290 years.
|
||||
func validateDuration(dur *durationpb.Duration) error {
|
||||
if dur == nil {
|
||||
return errors.New("duration: nil Duration")
|
||||
}
|
||||
if dur.Seconds < minSeconds || dur.Seconds > maxSeconds {
|
||||
return fmt.Errorf("duration: %v: seconds out of range", dur)
|
||||
}
|
||||
if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 {
|
||||
return fmt.Errorf("duration: %v: nanos out of range", dur)
|
||||
}
|
||||
// Seconds and Nanos must have the same sign, unless d.Nanos is zero.
|
||||
if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) {
|
||||
return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur)
|
||||
}
|
||||
return nil
|
||||
}
|
63
gateway/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
63
gateway/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
@ -1,63 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: github.com/golang/protobuf/ptypes/duration/duration.proto
|
||||
|
||||
package duration
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
durationpb "google.golang.org/protobuf/types/known/durationpb"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// Symbols defined in public import of google/protobuf/duration.proto.
|
||||
|
||||
type Duration = durationpb.Duration
|
||||
|
||||
var File_github_com_golang_protobuf_ptypes_duration_duration_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = []byte{
|
||||
0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
|
||||
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
|
||||
0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x75, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67,
|
||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73,
|
||||
0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = []interface{}{}
|
||||
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() }
|
||||
func file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() {
|
||||
if File_github_com_golang_protobuf_ptypes_duration_duration_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 0,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes,
|
||||
DependencyIndexes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs,
|
||||
}.Build()
|
||||
File_github_com_golang_protobuf_ptypes_duration_duration_proto = out.File
|
||||
file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = nil
|
||||
file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = nil
|
||||
file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = nil
|
||||
}
|
112
gateway/vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
112
gateway/vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
@ -1,112 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ptypes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
timestamppb "github.com/golang/protobuf/ptypes/timestamp"
|
||||
)
|
||||
|
||||
// Range of google.protobuf.Duration as specified in timestamp.proto.
|
||||
const (
|
||||
// Seconds field of the earliest valid Timestamp.
|
||||
// This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
||||
minValidSeconds = -62135596800
|
||||
// Seconds field just after the latest valid Timestamp.
|
||||
// This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
||||
maxValidSeconds = 253402300800
|
||||
)
|
||||
|
||||
// Timestamp converts a timestamppb.Timestamp to a time.Time.
|
||||
// It returns an error if the argument is invalid.
|
||||
//
|
||||
// Unlike most Go functions, if Timestamp returns an error, the first return
|
||||
// value is not the zero time.Time. Instead, it is the value obtained from the
|
||||
// time.Unix function when passed the contents of the Timestamp, in the UTC
|
||||
// locale. This may or may not be a meaningful time; many invalid Timestamps
|
||||
// do map to valid time.Times.
|
||||
//
|
||||
// A nil Timestamp returns an error. The first return value in that case is
|
||||
// undefined.
|
||||
//
|
||||
// Deprecated: Call the ts.AsTime and ts.CheckValid methods instead.
|
||||
func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) {
|
||||
// Don't return the zero value on error, because corresponds to a valid
|
||||
// timestamp. Instead return whatever time.Unix gives us.
|
||||
var t time.Time
|
||||
if ts == nil {
|
||||
t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
|
||||
} else {
|
||||
t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
|
||||
}
|
||||
return t, validateTimestamp(ts)
|
||||
}
|
||||
|
||||
// TimestampNow returns a google.protobuf.Timestamp for the current time.
|
||||
//
|
||||
// Deprecated: Call the timestamppb.Now function instead.
|
||||
func TimestampNow() *timestamppb.Timestamp {
|
||||
ts, err := TimestampProto(time.Now())
|
||||
if err != nil {
|
||||
panic("ptypes: time.Now() out of Timestamp range")
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
|
||||
// It returns an error if the resulting Timestamp is invalid.
|
||||
//
|
||||
// Deprecated: Call the timestamppb.New function instead.
|
||||
func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) {
|
||||
ts := ×tamppb.Timestamp{
|
||||
Seconds: t.Unix(),
|
||||
Nanos: int32(t.Nanosecond()),
|
||||
}
|
||||
if err := validateTimestamp(ts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// TimestampString returns the RFC 3339 string for valid Timestamps.
|
||||
// For invalid Timestamps, it returns an error message in parentheses.
|
||||
//
|
||||
// Deprecated: Call the ts.AsTime method instead,
|
||||
// followed by a call to the Format method on the time.Time value.
|
||||
func TimestampString(ts *timestamppb.Timestamp) string {
|
||||
t, err := Timestamp(ts)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("(%v)", err)
|
||||
}
|
||||
return t.Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
// validateTimestamp determines whether a Timestamp is valid.
|
||||
// A valid timestamp represents a time in the range [0001-01-01, 10000-01-01)
|
||||
// and has a Nanos field in the range [0, 1e9).
|
||||
//
|
||||
// If the Timestamp is valid, validateTimestamp returns nil.
|
||||
// Otherwise, it returns an error that describes the problem.
|
||||
//
|
||||
// Every valid Timestamp can be represented by a time.Time,
|
||||
// but the converse is not true.
|
||||
func validateTimestamp(ts *timestamppb.Timestamp) error {
|
||||
if ts == nil {
|
||||
return errors.New("timestamp: nil Timestamp")
|
||||
}
|
||||
if ts.Seconds < minValidSeconds {
|
||||
return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
|
||||
}
|
||||
if ts.Seconds >= maxValidSeconds {
|
||||
return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
|
||||
}
|
||||
if ts.Nanos < 0 || ts.Nanos >= 1e9 {
|
||||
return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
|
||||
}
|
||||
return nil
|
||||
}
|
3
gateway/vendor/github.com/gorilla/mux/go.mod
generated
vendored
3
gateway/vendor/github.com/gorilla/mux/go.mod
generated
vendored
@ -1,3 +0,0 @@
|
||||
module github.com/gorilla/mux
|
||||
|
||||
go 1.12
|
5
gateway/vendor/github.com/nats-io/nats.go/.gitignore
generated
vendored
5
gateway/vendor/github.com/nats-io/nats.go/.gitignore
generated
vendored
@ -39,4 +39,7 @@ _testmain.go
|
||||
# bin
|
||||
|
||||
# Goland
|
||||
.idea
|
||||
.idea
|
||||
|
||||
# VS Code
|
||||
.vscode
|
26
gateway/vendor/github.com/nats-io/nats.go/.travis.yml
generated
vendored
26
gateway/vendor/github.com/nats-io/nats.go/.travis.yml
generated
vendored
@ -1,19 +1,25 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.16.x
|
||||
- 1.15.x
|
||||
- 1.18.x
|
||||
- 1.17.x
|
||||
go_import_path: github.com/nats-io/nats.go
|
||||
install:
|
||||
- go get -t ./...
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get github.com/wadey/gocovmerge
|
||||
- go get -u honnef.co/go/tools/cmd/staticcheck
|
||||
- go get -u github.com/client9/misspell/cmd/misspell
|
||||
- if [[ "$TRAVIS_GO_VERSION" =~ 1.18 ]]; then
|
||||
go install github.com/mattn/goveralls@latest;
|
||||
go install github.com/wadey/gocovmerge@latest;
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest;
|
||||
go install github.com/client9/misspell/cmd/misspell@latest;
|
||||
fi
|
||||
before_script:
|
||||
- $(exit $(go fmt ./... | wc -l))
|
||||
- go vet -modfile=go_test.mod ./...
|
||||
- find . -type f -name "*.go" | xargs misspell -error -locale US
|
||||
- staticcheck ./...
|
||||
- if [[ "$TRAVIS_GO_VERSION" =~ 1.18 ]]; then
|
||||
find . -type f -name "*.go" | xargs misspell -error -locale US;
|
||||
GOFLAGS="-mod=mod -modfile=go_test.mod" staticcheck ./...;
|
||||
fi
|
||||
script:
|
||||
- go test -modfile=go_test.mod -v -run=TestNoRace -p=1 ./... --failfast
|
||||
- if [[ "$TRAVIS_GO_VERSION" =~ 1.16 ]]; then ./scripts/cov.sh TRAVIS; else go test -modfile=go_test.mod -race -v -p=1 ./... --failfast; fi
|
||||
- go test -modfile=go_test.mod -v -run=TestNoRace -p=1 ./... --failfast -vet=off
|
||||
- if [[ "$TRAVIS_GO_VERSION" =~ 1.18 ]]; then ./scripts/cov.sh TRAVIS; else go test -modfile=go_test.mod -race -v -p=1 ./... --failfast -vet=off; fi
|
||||
after_success:
|
||||
- if [[ "$TRAVIS_GO_VERSION" =~ 1.18 ]]; then $HOME/gopath/bin/goveralls -coverprofile=acc.out -service travis-ci; fi
|
||||
|
106
gateway/vendor/github.com/nats-io/nats.go/.words
generated
vendored
Normal file
106
gateway/vendor/github.com/nats-io/nats.go/.words
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
1
|
||||
|
||||
derek
|
||||
dlc
|
||||
ivan
|
||||
|
||||
acknowledgement/SM
|
||||
arity
|
||||
deduplication/S
|
||||
demarshal/SDG
|
||||
durables
|
||||
iff
|
||||
observable/S
|
||||
redelivery/S
|
||||
retransmitting
|
||||
retry/SB
|
||||
|
||||
SlowConsumer
|
||||
|
||||
AppendInt
|
||||
ReadMIMEHeader
|
||||
|
||||
clientProtoZero
|
||||
jetstream
|
||||
v1
|
||||
v2
|
||||
|
||||
ack/SGD
|
||||
auth
|
||||
authToken
|
||||
chans
|
||||
creds
|
||||
config/S
|
||||
cseq
|
||||
impl
|
||||
msgh
|
||||
msgId
|
||||
mux/S
|
||||
nack
|
||||
ptr
|
||||
puback
|
||||
scanf
|
||||
stderr
|
||||
stdout
|
||||
structs
|
||||
tm
|
||||
todo
|
||||
unsub/S
|
||||
|
||||
permessage
|
||||
permessage-deflate
|
||||
urlA
|
||||
urlB
|
||||
websocket
|
||||
ws
|
||||
wss
|
||||
|
||||
NKey
|
||||
pList
|
||||
|
||||
backend/S
|
||||
backoff/S
|
||||
decompressor/CGS
|
||||
inflight
|
||||
inlined
|
||||
lookups
|
||||
reconnection/MS
|
||||
redeliver/ADGS
|
||||
responder/S
|
||||
rewrap/S
|
||||
rollup/S
|
||||
unreceive/DRSZGB
|
||||
variadic
|
||||
wakeup/S
|
||||
whitespace
|
||||
wrap/AS
|
||||
|
||||
omitempty
|
||||
|
||||
apache
|
||||
html
|
||||
ietf
|
||||
www
|
||||
|
||||
sum256
|
||||
32bit/S
|
||||
64bit/S
|
||||
64k
|
||||
128k
|
||||
512k
|
||||
|
||||
hacky
|
||||
handroll/D
|
||||
|
||||
rfc6455
|
||||
rfc7692
|
||||
0x00
|
||||
0xff
|
||||
20x
|
||||
40x
|
||||
50x
|
||||
|
||||
ErrXXX
|
||||
|
||||
atlanta
|
||||
eu
|
25
gateway/vendor/github.com/nats-io/nats.go/.words.readme
generated
vendored
Normal file
25
gateway/vendor/github.com/nats-io/nats.go/.words.readme
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
The .words file is used by gospel (v1.2+), which wraps the Hunspell libraries
|
||||
but populates the dictionary with identifiers from the Go source.
|
||||
|
||||
<https://github.com/kortschak/gospel>
|
||||
|
||||
Alas, no comments are allowed in the .words file and newer versions of gospel
|
||||
error out on seeing them. This is really a hunspell restriction.
|
||||
|
||||
We assume en_US hunspell dictionaries are installed and used.
|
||||
The /AFFIXRULES are defined in en_US.aff (eg: /usr/share/hunspell/en_US.aff)
|
||||
Invoke `hunspell -D` to see the actual locations.
|
||||
|
||||
Words which are in the base dictionary can't have extra affix rules added to
|
||||
them, so we have to start with the affixed variant we want to add.
|
||||
Thus `creds` rather than `cred/S` and so on.
|
||||
|
||||
So we can't use receive/DRSZGBU, adding 'U', to allow unreceive and variants,
|
||||
we have to use unreceive as the stem.
|
||||
|
||||
We can't define our own affix or compound rules,
|
||||
to capture rfc\d{3,} or 0x[0-9A-Fa-f]{2}
|
||||
|
||||
The spelling tokenizer doesn't take "permessage-deflate" as allowing for ...
|
||||
"permessage-deflate", which is an RFC7692 registered extension for websockets.
|
||||
We have to explicitly list "permessage".
|
18
gateway/vendor/github.com/nats-io/nats.go/README.md
generated
vendored
18
gateway/vendor/github.com/nats-io/nats.go/README.md
generated
vendored
@ -1,10 +1,18 @@
|
||||
# NATS - Go Client
|
||||
A [Go](http://golang.org) client for the [NATS messaging system](https://nats.io).
|
||||
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fnats-io%2Fgo-nats?ref=badge_shield)
|
||||
[](https://goreportcard.com/report/github.com/nats-io/nats.go) [](http://travis-ci.com/nats-io/nats.go) [](https://pkg.go.dev/github.com/nats-io/nats.go)
|
||||
[](https://coveralls.io/r/nats-io/nats.go?branch=master)
|
||||
[![License Apache 2][License-Image]][License-Url] [![Go Report Card][ReportCard-Image]][ReportCard-Url] [![Build Status][Build-Status-Image]][Build-Status-Url] [![GoDoc][GoDoc-Image]][GoDoc-Url] [![Coverage Status][Coverage-image]][Coverage-Url]
|
||||
|
||||
[License-Url]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
[License-Image]: https://img.shields.io/badge/License-Apache2-blue.svg
|
||||
[ReportCard-Url]: https://goreportcard.com/report/github.com/nats-io/nats.go
|
||||
[ReportCard-Image]: https://goreportcard.com/badge/github.com/nats-io/nats.go
|
||||
[Build-Status-Url]: https://travis-ci.com/github/nats-io/nats.go
|
||||
[Build-Status-Image]: https://travis-ci.com/nats-io/nats.go.svg?branch=main
|
||||
[GoDoc-Url]: https://pkg.go.dev/github.com/nats-io/nats.go
|
||||
[GoDoc-Image]: https://img.shields.io/badge/GoDoc-reference-007d9c
|
||||
[Coverage-Url]: https://coveralls.io/r/nats-io/nats.go?branch=main
|
||||
[Coverage-image]: https://coveralls.io/repos/github/nats-io/nats.go/badge.svg?branch=main
|
||||
|
||||
## Installation
|
||||
|
||||
@ -21,7 +29,7 @@ When using or transitioning to Go modules support:
|
||||
```bash
|
||||
# Go client latest or explicit version
|
||||
go get github.com/nats-io/nats.go/@latest
|
||||
go get github.com/nats-io/nats.go/@v1.11.0
|
||||
go get github.com/nats-io/nats.go/@v1.22.1
|
||||
|
||||
# For latest NATS Server, add /v2 at the end
|
||||
go get github.com/nats-io/nats-server/v2
|
||||
|
26
gateway/vendor/github.com/nats-io/nats.go/TODO.md
generated
vendored
26
gateway/vendor/github.com/nats-io/nats.go/TODO.md
generated
vendored
@ -1,26 +0,0 @@
|
||||
|
||||
- [ ] Better constructors, options handling
|
||||
- [ ] Functions for callback settings after connection created.
|
||||
- [ ] Better options for subscriptions. Slow Consumer state settable, Go routines vs Inline.
|
||||
- [ ] Move off of channels for subscribers, use syncPool linkedLists, etc with highwater.
|
||||
- [ ] Test for valid subjects on publish and subscribe?
|
||||
- [ ] SyncSubscriber and Next for EncodedConn
|
||||
- [ ] Fast Publisher?
|
||||
- [ ] pooling for structs used? leaky bucket?
|
||||
- [ ] Timeout 0 should work as no timeout
|
||||
- [x] Ping timer
|
||||
- [x] Name in Connect for gnatsd
|
||||
- [x] Asynchronous error handling
|
||||
- [x] Parser rewrite
|
||||
- [x] Reconnect
|
||||
- [x] Hide Lock
|
||||
- [x] Easier encoder interface
|
||||
- [x] QueueSubscribeSync
|
||||
- [x] Make nats specific errors prefixed with 'nats:'
|
||||
- [x] API test for closed connection
|
||||
- [x] TLS/SSL
|
||||
- [x] Stats collection
|
||||
- [x] Disconnect detection
|
||||
- [x] Optimized Publish (coalescing)
|
||||
- [x] Do Examples via Go style
|
||||
- [x] Standardized Errors
|
44
gateway/vendor/github.com/nats-io/nats.go/context.go
generated
vendored
44
gateway/vendor/github.com/nats-io/nats.go/context.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2016-2018 The NATS Authors
|
||||
// Copyright 2016-2022 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@ -21,20 +21,13 @@ import (
|
||||
// RequestMsgWithContext takes a context, a subject and payload
|
||||
// in bytes and request expecting a single response.
|
||||
func (nc *Conn) RequestMsgWithContext(ctx context.Context, msg *Msg) (*Msg, error) {
|
||||
var hdr []byte
|
||||
var err error
|
||||
|
||||
if len(msg.Header) > 0 {
|
||||
if !nc.info.Headers {
|
||||
return nil, ErrHeadersNotSupported
|
||||
}
|
||||
|
||||
hdr, err = msg.headerBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg == nil {
|
||||
return nil, ErrInvalidMsg
|
||||
}
|
||||
hdr, err := msg.headerBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nc.requestWithContext(ctx, msg.Subject, hdr, msg.Data)
|
||||
}
|
||||
|
||||
@ -92,7 +85,7 @@ func (nc *Conn) requestWithContext(ctx context.Context, subj string, hdr, data [
|
||||
|
||||
// oldRequestWithContext utilizes inbox and subscription per request.
|
||||
func (nc *Conn) oldRequestWithContext(ctx context.Context, subj string, hdr, data []byte) (*Msg, error) {
|
||||
inbox := NewInbox()
|
||||
inbox := nc.NewInbox()
|
||||
ch := make(chan *Msg, RequestChanLen)
|
||||
|
||||
s, err := nc.subscribe(inbox, _EMPTY_, nil, ch, true, nil)
|
||||
@ -110,10 +103,7 @@ func (nc *Conn) oldRequestWithContext(ctx context.Context, subj string, hdr, dat
|
||||
return s.NextMsgWithContext(ctx)
|
||||
}
|
||||
|
||||
// NextMsgWithContext takes a context and returns the next message
|
||||
// available to a synchronous subscriber, blocking until it is delivered
|
||||
// or context gets canceled.
|
||||
func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
|
||||
func (s *Subscription) nextMsgWithContext(ctx context.Context, pullSubInternal, waitIfNoMsg bool) (*Msg, error) {
|
||||
if ctx == nil {
|
||||
return nil, ErrInvalidContext
|
||||
}
|
||||
@ -125,7 +115,7 @@ func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
err := s.validateNextMsgState()
|
||||
err := s.validateNextMsgState(pullSubInternal)
|
||||
if err != nil {
|
||||
s.mu.Unlock()
|
||||
return nil, err
|
||||
@ -150,6 +140,11 @@ func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
|
||||
return msg, nil
|
||||
}
|
||||
default:
|
||||
// If internal and we don't want to wait, signal that there is no
|
||||
// message in the internal queue.
|
||||
if pullSubInternal && !waitIfNoMsg {
|
||||
return nil, errNoMessages
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
@ -167,6 +162,13 @@ func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// NextMsgWithContext takes a context and returns the next message
|
||||
// available to a synchronous subscriber, blocking until it is delivered
|
||||
// or context gets canceled.
|
||||
func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
|
||||
return s.nextMsgWithContext(ctx, false, true)
|
||||
}
|
||||
|
||||
// FlushWithContext will allow a context to control the duration
|
||||
// of a Flush() call. This context should be non-nil and should
|
||||
// have a deadline set. We will return an error if none is present.
|
||||
@ -215,7 +217,7 @@ func (nc *Conn) FlushWithContext(ctx context.Context) error {
|
||||
|
||||
// RequestWithContext will create an Inbox and perform a Request
|
||||
// using the provided cancellation context with the Inbox reply
|
||||
// for the data v. A response will be decoded into the vPtrResponse.
|
||||
// for the data v. A response will be decoded into the vPtr last parameter.
|
||||
func (c *EncodedConn) RequestWithContext(ctx context.Context, subject string, v interface{}, vPtr interface{}) error {
|
||||
if ctx == nil {
|
||||
return ErrInvalidContext
|
||||
|
2
gateway/vendor/github.com/nats-io/nats.go/enc.go
generated
vendored
2
gateway/vendor/github.com/nats-io/nats.go/enc.go
generated
vendored
@ -130,7 +130,7 @@ func (c *EncodedConn) Request(subject string, v interface{}, vPtr interface{}, t
|
||||
|
||||
// Handler is a specific callback used for Subscribe. It is generalized to
|
||||
// an interface{}, but we will discover its format and arguments at runtime
|
||||
// and perform the correct callback, including de-marshaling encoded data
|
||||
// and perform the correct callback, including demarshaling encoded data
|
||||
// back into the appropriate struct based on the signature of the Handler.
|
||||
//
|
||||
// Handlers are expected to have one of four signatures.
|
||||
|
8
gateway/vendor/github.com/nats-io/nats.go/go.mod
generated
vendored
8
gateway/vendor/github.com/nats-io/nats.go/go.mod
generated
vendored
@ -1,8 +0,0 @@
|
||||
module github.com/nats-io/nats.go
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/nats-io/nkeys v0.3.0
|
||||
github.com/nats-io/nuid v1.0.1
|
||||
)
|
11
gateway/vendor/github.com/nats-io/nats.go/go.sum
generated
vendored
11
gateway/vendor/github.com/nats-io/nats.go/go.sum
generated
vendored
@ -1,11 +0,0 @@
|
||||
github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
|
||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b h1:wSOdpTq0/eI46Ez/LkDwIsAKA71YP2SRKBODiRWM0as=
|
||||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
13
gateway/vendor/github.com/nats-io/nats.go/go_test.mod
generated
vendored
13
gateway/vendor/github.com/nats-io/nats.go/go_test.mod
generated
vendored
@ -1,11 +1,20 @@
|
||||
module github.com/nats-io/nats.go
|
||||
|
||||
go 1.15
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/nats-io/nats-server/v2 v2.2.7-0.20210618192106-93a3720475a4
|
||||
github.com/nats-io/nats-server/v2 v2.9.6
|
||||
github.com/nats-io/nkeys v0.3.0
|
||||
github.com/nats-io/nuid v1.0.1
|
||||
google.golang.org/protobuf v1.23.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/klauspost/compress v1.15.11 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.3.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
||||
)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user